/* Copyright 2006-2007 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

var LSN = new Object();

/*------------------------------------------------------------------------------
 * defined - Return true unless the variable type is 'undefined'
 * @param variable
 *----------------------------------------------------------------------------*/

function defined(unk) {
  return typeof(unk) == 'undefined' ? false : true;
}

/*------------------------------------------------------------------------------
 * getElement - Cross-browser function for referring to a document element
 * @param unk Element id, Element object, or a function (which ought return an
 * element object)
 *----------------------------------------------------------------------------*/

function getElement(unk) {
  return  typeof(unk) == 'object'   ?   unk                                :
          typeof(unk) == 'function' ?   unk()                              :
          document.getElementById   ?   document.getElementById(unk)       :
          document.all              ?   document.all[unk]                  :
          document.layers           ?   document.layers[unk]               :
                                        false;
}

/*------------------------------------------------------------------------------
 * getChildrenByTagName - Get child elements by their tag name
 * @param id of the target element, or an element object
 * @param tagName name of the child tags to return
 * @returns Array
 *----------------------------------------------------------------------------*/

function getChildrenByTagName(id, tagName) {
  return getChildrenByAttrs(id, {'tagName': tagName});
}

/*------------------------------------------------------------------------------
 * getChildrenByAttrs - Get child elements by their attributes
 * @param id of the target element, or an element object
 * @param props collection of attributes which must match
 * @returns Array
 *
 * The attribute 'tagName' is handled in a special way, as it is not really an
 * node attribute.
 *
 * This example will return a list of INPUT elements which have a class equal
 * to 'ctrl':
 *
 *  var list = getChildrenByAttrs(document.body, {
 *    class: 'ctrl',
 *    tagName: 'input',
 *  });
 *----------------------------------------------------------------------------*/

function getChildrenByAttrs(id, props) {
  if (!id) throw ("Provide an element or element id");
  if (!props) throw ("Provide an attribute collection");
  var result = new Array();
  var elem = getElement(id);
  var len = elem.childNodes.length; // .length increases on read in ie6
  for (var i = 0; i < len; i++) {
    if (!elem.childNodes[i]) break;
    if (elem.childNodes[i].getAttributeNode) {
      var matches = true;
      for (var attr in props) {
        var value = attr == 'tagName'
          ? props[attr].toUpperCase()
          : props[attr];
        try {
          var nodeValue = attr == 'tagName'
            ? elem.childNodes[i].tagName
            : elem.childNodes[i].getAttributeNode(attr).value;
        } catch (err) {
          matches = false;
          continue;
        }
        if (value.match(/^~/)) {
          if (nodeValue) {
            var realValue = value.replace(/^~/,'');
            matches = matches & (nodeValue && (nodeValue.search(realValue) > -1));
          } else {
            matches = false;
          }
        } else {
          matches = matches & (nodeValue && (nodeValue == value));
        }
        if (!matches) break;
      }
      if (matches) result.push(elem.childNodes[i]);
      if (elem.childNodes[i].childNodes.length > 0) {
        var subElements = getChildrenByAttrs(elem.childNodes[i], props);
        for (var j = 0; j < subElements.length; j++) {
          result.push(subElements[j]);
        }
      }
    }
  }
  return result;
}

function createElement(tagName, props) {
  var elem = document.createElement(tagName.toUpperCase());
  if (props) {
    for (var k in props) {
      var v = props[k];
      if (typeof(v) == 'object') {
        for (var k2 in v) {
          var v2 = v[k2];
          elem[k][k2] = v2;
        }
      } else {
        elem[k] = v;
        if (k.search('inner') != 0) {
          elem.setAttribute(k, v);
        }
      }
    }
  }
  return elem;
}

function getField(id) {
  var elem = getElement(id);
  if (!elem) throw new Error('Element not found: ' + id);
  var name = elem.name ? elem.name : elem.id;
  var value = getValue(elem);
  return defined(value)
    ? {'name': name, 'value': value}
    : undefined;
}

function resolveValue(value) {
  /* Support for '&:id' values which refer to other elements */
  if (value.match(/^&:/)) {
    return getValue(value.replace(/^&:/, ''));
  }
  return value;
}

/* Get the logical value according to element type */
function getValue(elem) {
  var elem = getElement(elem);
  var value = undefined;
  switch (elem.tagName.toUpperCase()) {
    case 'INPUT':
      switch (elem.type.toUpperCase()) {
        case 'HIDDEN':
          value = resolveValue(elem.value);
          break;
        case 'CHECKBOX':
          value = elem.checked ? resolveValue(elem.value) : '';
          break;
        case 'RADIO':
          if (elem.checked) {
            value = resolveValue(elem.value);
          }
          break;
        case 'PASSWORD':
          value = hex_sha1(elem.value);
          break;
        case 'TEXT':
          value = elem.value;
          break;
        default: throw new Error('Unhandled input type: '+elem.type);
      }
      break;
    case 'TEXTAREA':
    case 'SELECT':
      value = elem.value;
      break;
    default:
      if (defined(elem.innerHTML)) {
        value = elem.innerHTML;
      } else {
        throw new Error('Unhandled tag: '+elem.tagName);
      }
  }
  return value;
}
/* Copyright 2008 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

LSN.CANVAS = new Canvas();

function Canvas() {
  this.root = function() { getRootElement(); };
  this.doc = document.documentElement;
  this.win = window;
};

Canvas.prototype.windowX = function() {
  var windowX = (this.doc && this.doc.clientWidth) || (this.doc && this.doc.offsetWidth)
    || this.win.innerWidth || self.innerWidth || this.root.clientWidth;
  return asInt(windowX);
};

Canvas.prototype.windowY = function() {
  var windowY = (this.doc && this.doc.clientHeight) || (this.doc && this.doc.offsetHeight)
    || this.win.innerHeight || self.innerHeight || this.root.clientHeight;
  return asInt(windowY);
};

Canvas.prototype.scrollX = function() {
  var scrollX = (this.doc && this.doc.scrollLeft)
    || this.win.pageXOffset || self.pageXOffset || this.root.scrollLeft;
  return asInt(scrollX);
};

Canvas.prototype.scrollY = function() {
  var scrollY = (this.doc && this.doc.scrollTop)
    || this.win.pageYOffset || self.pageYOffset || this.root.scrollTop;
  return asInt(scrollY);
};

Canvas.prototype.pageX = function() {
  var pageX = (this.doc && this.doc.scrollWidth)
    ? this.doc.scrollWidth
    : (this.root.scrollWidth > this.root.offsetWidth)
      ? this.root.scrollWidth
      : this.root.offsetWidth;
  return asInt(pageX);
};

Canvas.prototype.pageY = function() {
  var pageY = (this.doc && this.doc.scrollHeight)
    ? this.doc.scrollHeight
    : (this.root.scrollHeight > this.root.offsetHeight)
      ? this.root.scrollHeight
      : this.root.offsetHeight;
  return asInt(pageY);
};
/* Copyright 2006 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

LSN.LAYER_TOP = 100;
LSN.SCROLLBAR_WIDTH = -1;

/*------------------------------------------------------------------------------
 * toggleVisibility - Hide or show an element (using css 'visibility' property).
 * @param id HTML Element ID
 *----------------------------------------------------------------------------*/

function toggleVisibility(id) {
  var elem = getElement( id );
  var visibility = getCSSAttribute( elem, "visibility" );
  elem.style.visibility = visibility == "hidden" ? "visible" : "hidden";
}

/*------------------------------------------------------------------------------
 * toggleDisplay - Hide or show an element (using css 'display' property).
 * @param id HTML Element ID
 *----------------------------------------------------------------------------*/

function toggleDisplay(id) {
  var elem = getElement( id );
  var display = getCSSAttribute( elem, "display" );
  elem.style.display = display == "none" ? "block" : "none";
}

/*------------------------------------------------------------------------------
 * getWindowSize - Return an array (width, height) describing the browser window
 *----------------------------------------------------------------------------*/

function getWindowSize() {
  var w = 0;
  var h = 0;
  if (typeof(window.innerWidth) == 'number') {
    //Non-IE
    w = window.innerWidth;
    h = window.innerHeight;
  } else if (document.documentElement && (document.documentElement.clientWidth 
        || document.documentElement.clientHeight)) {
    //IE 6+ in 'standards compliant mode'
    w = document.documentElement.clientWidth;
    h = document.documentElement.clientHeight;
  } else if (document.body && (document.body.clientWidth || 
        document.body.clientHeight)) {
    //IE 4 compatible
    w = document.body.clientWidth;
    h = document.body.clientHeight;
  }
  return new Array(w, h);
}

function getPageSize() {
  var dims = getWindowSize();
  return new Array (LSN.CANVAS.scrollX() + dims[0], LSN.CANVAS.scrollY() + dims[1]);
}

/* -----------------------------------------------------------------------------
 * getViewportPosition - Pixel coordinates and dimensions of the viewport
 * getViewportPosition
 *
 * returns: Object w/members: left, top, width, height
 * -------------------------------------------------------------------------- */

function getViewportPosition() {
  return {
    'left':   LSN.CANVAS.scrollX(),
    'top':    LSN.CANVAS.scrollY(),
    'width':  window.opera ? LSN.CANVAS.pageX() + 0 : LSN.CANVAS.windowX(),
    'height': window.opera ? LSN.CANVAS.pageY() + 0 : LSN.CANVAS.windowY()
  };
}

/*------------------------------------------------------------------------------
 * getCenteredXY - Get the (x, y) pixel coordinates which will center the
 * element on the visible* screen.
 *
 * getCenteredXY element
 * getCenteredXY id
 *
 * *Visible meaning we take the screen's scroll positions into account.
 *----------------------------------------------------------------------------*/

function getCenteredXY(elem) {
  elem = getElement(elem);
  var vp = getViewportPosition();
  var pos = getElementPosition(elem);
  var x = vp['left'] + (vp['width'] / 2) - (pos['width'] / 2);
  var y = vp['top'] + (vp['height'] / 2) - (pos['height'] / 2);
  if (x < vp['left']) x = vp['left'];
  if (y < vp['top']) y = vp['top'];
  return new Array (x, y);
}

function getPosition(elem) {
  return {
    'top':    getTop(elem),
    'left':   getLeft(elem),
    'right':  getRight(elem),
    'bottom': getBottom(elem),
    'width':  getWidth(elem),
    'height': getHeight(elem)
  };
}

function getInnerPosition(elem) {
  return {
    'top':    getInnerTop(elem),
    'left':   getInnerLeft(elem),
    'right':  getInnerRight(elem),
    'bottom': getInnerBottom(elem),
    'width':  getInnerWidth(elem),
    'height': getInnerHeight(elem)
  };
}

/*------------------------------------------------------------------------------
 * Element dimensions and positions.
 *----------------------------------------------------------------------------*/

/* Outer */

function getTop(element)    {
  return getOffset(element, 'top');
}

function getBottom(element) {
  return getTop(element) + getHeight(element);
}

function getLeft(element)   {
  return getOffset(element, 'left');
}

function getRight(element)  {
  return getLeft(element) + getWidth(element);
}

function getWidth(element)  {
  var result = getDimension(element, 'width');
  result += asInt(getCSSAttribute(element, 'border-left-width'));
  result += asInt(getCSSAttribute(element, 'border-right-width'));
  return result;
}

function getHeight(element) {
  var result =  getDimension(element, 'height');
  result += asInt(getCSSAttribute(element, 'border-top-width'));
  result += asInt(getCSSAttribute(element, 'border-bottom-width'));
  return result;
}

/* Inner */

function getInnerTop(element)    {
  var result = getOffset(element, 'top');
  result += asInt(getCSSAttribute(element, 'border-top-width'));
  return result;
}

function getInnerBottom(element) {
  return getInnerTop(element) + getInnerHeight(element);
}

function getInnerLeft(element)   {
  var result = getOffset(element, 'left');
  result += asInt(getCSSAttribute(element, 'border-left-width'));
  return result;
}

function getInnerRight(element)  {
  return getInnerLeft(element) + getInnerWidth(element);
}

function getInnerWidth(element)  {
  return getDimension(element, 'width');
}

function getInnerHeight(element) {
  return getDimension(element, 'height');
}

/* -----------------------------------------------------------------------------
 * getElementPosition - Pixel coordinates and dimensions of the element
 * getElementPosition
 *
 * returns: Object w/members: left, top, width, height
 * -------------------------------------------------------------------------- */

function getElementPosition(elem) {
  elem = getElement(elem);
  return {
    'left':   getLeft(elem),
    'top':    getTop(elem),
    'width':  getWidth(elem),
    'height': getHeight(elem)
  };
}

/*------------------------------------------------------------------------------
 * getOffset - Return the offset (top or left) for the given element.
 * @param element an element object (or its id)
 * @param attr either 'top' or 'left'
 *----------------------------------------------------------------------------*/

function getOffset(elem, attr) {
  elem = getElement(elem);
  var offset = 0;
  if (elem) {
    offset = attr == 'top'
      ? elem.offsetTop
        ? elem.offsetTop
        : defined(elem.getBBox)
          ? elem.getBBox().y
          : 0
      : elem.offsetLeft
        ? elem.offsetLeft
        : defined(elem.getBBox)
          ? elem.getBBox().x
          : 0;
    offset += getOffset(elem.offsetParent, attr);
  }
  return isNaN(offset) ? 0 : offset;
}

/*------------------------------------------------------------------------------
 * getDimension - Return the dimension (width or height) for the given element.
 * @param elem an element object (or its id)
 * @param attr either 'width' or 'height'
 *----------------------------------------------------------------------------*/

function getDimension(elem, attr) {
  var result = 0;
  if (typeof(elem) != 'object') {
    elem = getElement(elem);
  }
  if (elem) {
    result = attr == 'height'
      ? elem.clientHeight
        ? elem.clientHeight
        : elem.offsetHeight
          ? elem.offsetHeight
          : defined(elem.getBBox)
            ? elem.getBBox().height
            : 0
      : elem.clientWidth
        ? elem.clientWidth
        : elem.offsetWidth
          ? elem.offsetWidth
          : defined(elem.getBBox)
            ? elem.getBBox().width
            : 0;
    if (isNaN(result) || result <= 0) {
      result = getCSSAttribute(elem, attr);
      result = parseInt(result.replace("\w", ""));
    }
    if (isNaN(result)) result = 0;
  }
  return isNaN(result) ? 0 : result;
}

/*------------------------------------------------------------------------------
 * getCSSAttribute - Get a CSS attribute value.
 * @param elem target element
 * @param propName style key
 * First check the style, and then look at the element's classes, then the id
 * selector.
 *----------------------------------------------------------------------------*/

function getCSSAttribute(elem, propName) {
  elem = getElement(elem);
  if (!elem) return;
  var hyphenated = asHyphenatedName(propName);
  var camelCase = asCamelCaseName(propName);
  if (elem.currentStyle) {
    return elem.currentStyle[camelCase]
  } else if(window.getComputedStyle) {
      var cs = document.defaultView.getComputedStyle(elem,null)
      return cs.getPropertyValue(hyphenated)
  } else {
    return;
  }
}

/* ------------------------------------------------------------------------------
 * getScrollbarWidth - Get the width of the scrollbar
 * getScrollbarWidth
 *
 * Note, does not work on Safari for Mac
 * --------------------------------------------------------------------------- */

function getScrollbarWidth() {
    if (LSN.SCROLLBAR_WIDTH > 0) return LSN.SCROLLBAR_WIDTH;
    var div = createElement('div', {
      'style': {
        'position': 'absolute',
        'top':      '-1000px',
        'left':     '-1000px',
        'width':    '100px',
        'height':   '50px',
        'overflow': 'hidden' 
      }
    });
    var content = createElement('div', {
      'style': {
        'width':  '100%',
        'height': '200px'
      }
    });
    div.appendChild(content);
    bodyAppend(div);
    var w1 = getWidth(content);
    div.style.overflow = 'auto';
    var w2 = getWidth(content);
    getBody().removeChild(div);
    LSN.SCROLLBAR_WIDTH = w1 - w2;
    if (LSN.SCROLLBAR_WIDTH <= 0) LSN.SCROLLBAR_WIDTH = 15; // default
    return LSN.SCROLLBAR_WIDTH;
}
/* Copyright 2006 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

LSN.STATUS_ID = 'lsn_status';
LSN.MESSAGE_BOX_ID = 'lsn_message_box';
LSN.TRACE_BOX_ID = 'lsn_trace_box';
LSN.MASK_ID = 'lsn_mask';

/*------------------------------------------------------------------------------
 * getRootElement - Get the document's root element
 *----------------------------------------------------------------------------*/

function getRootElement() {
  return document.rootElement || getBody() || document.documentElement
    || document.lastChild || document;
}

/*------------------------------------------------------------------------------
 * getBody - Get our document's body
 *----------------------------------------------------------------------------*/

function getBody() {
  var bodies = document.getElementsByTagName('body');
  return bodies[0];
}

/*------------------------------------------------------------------------------
 * bodyAppend - Tack an element on to the body
 * @param elem html element object
 *----------------------------------------------------------------------------*/

function bodyAppend(elem) {
  getBody().appendChild(elem);
}

/*------------------------------------------------------------------------------
 * createInlineFrame - Construct an inline frame
 *----------------------------------------------------------------------------*/

function createInlineFrame() {
  /* create new iframe element */
  var obj;
  if (document.all) {
    obj = document.createElement('<iframe frameborder="0">');
  } else {
    obj = document.createElement("iframe");
    obj.setAttribute('frameborder', 'none');
  }
  return obj;
}

/*------------------------------------------------------------------------------
 * createJavaPlugin - Construct a Java plug-in object
 * @param path path to jar file
 * @param classname main class
 * @param params array of k/v parameters
 * @param ver java plugin version (default 1.4)
 *----------------------------------------------------------------------------*/

function createJavaPlugin(path,classname,params,ver) {

  /* default argument values */
  if (!params) params = new Array();
  if (!ver) ver = '1.4';

  /* create new object element */
  var obj;
  if (document.all) {
    obj = document.createElement("<object classid='clsid:8AD9C840-044E-11D1-B3E9-00805F499D93'>");
  } else {
    obj = document.createElement("object");
    obj.setAttribute( 'code', classname);
    obj.setAttribute( 'type', 'application/x-java-applet;version=' + ver);
  }

  /* set parameters */
  params['archive'] = path;
  params['code'] = classname;
  params['MAYSCRIPT'] = 'true';
  for (var key in params) {
    var param = document.createElement("param");
    param.setAttribute( 'name', key );
    param.setAttribute( 'value', params[key] );
    obj.appendChild(param);
  }

  return obj;

}

/*------------------------------------------------------------------------------
 * addFormParameter - Adds a hidden input (key/value) to a form.
 * @param form HTMLForm Element
 * @param key parameter name
 * @param val parameter value
 *----------------------------------------------------------------------------*/

function addFormParameter(form, key, val) {
  var input = document.createElement("input");
  input.type  = "hidden";
  input.name  = key;
  input.value = val;
  input.style.display = "none";
  form.appendChild( input );
}

/*------------------------------------------------------------------------------
 * addFormParameters - Adds hidden input (key/value) elements to a form.
 * @param form HTMLForm Element
 * @param params named parameter array
 *----------------------------------------------------------------------------*/

function addFormParameters(form, params) {
  if (!params) return;
  for (var key in params) {
    addFormParameter(form, key, params[key]);
  }
}

/*------------------------------------------------------------------------------
 * removeChildren - Remove all child nodes from an element
 * @param element|id Element or Element ID
 *----------------------------------------------------------------------------*/

function removeChildren(elem) {
  elem = getElement(elem);
  for (var idx = elem.childNodes.length - 1; idx >= 0; idx--) {
    elem.removeChild(elem.childNodes[idx]);
  }
}

/*------------------------------------------------------------------------------
 * showMask - Mask document body for dialogs
 *----------------------------------------------------------------------------*/

function showMask() {
  var mask = getElement(LSN.MASK_ID);	
  if (!mask) {
    mask = document.createElement('div');
    mask.setAttribute('id', LSN.MASK_ID);
    bodyAppend(mask);
  }
  var vp = getViewportPosition();
  mask.style.width = vp['width'] + "px";
  mask.style.height = vp['height'] + "px";
  mask.orig_height = vp['height'];
  mask.orig_width = vp['width'];
  //Fix for ie5/6, mask unable to hide select boxes.
  mask.innerHTML = '<!--[if lte IE 6.5]><iframe></iframe><![endif]-->';
  addEvent('window', 'scroll', _scrollMask, 'SCROLL_MASK');
  _scrollMask();
  mask.style.display = 'block';
}

function _scrollMask() {
  var mask = getElement(LSN.MASK_ID);
  if (mask) {
    var new_height = mask.orig_height + LSN.CANVAS.scrollY();
    if (new_height > asInt(mask.style.height)) {
      mask.style.height = new_height + 'px';
    }
    var new_width = mask.orig_width + LSN.CANVAS.scrollX();
    if (new_width > asInt(mask.style.width)) {
      mask.style.width = new_width + 'px';
    }
  }
}

/*------------------------------------------------------------------------------
 * hideMask - Unmask document body for dialogs
 *----------------------------------------------------------------------------*/

function hideMask() {
  getElement(LSN.MASK_ID).style.display = 'none';
  removeEvent('SCROLL_MASK');
}

/*------------------------------------------------------------------------------
 * msgbox - Display a message with an OK button
 *----------------------------------------------------------------------------*/

function msgbox(text, props) {
  showMask();
  var div = getElement(LSN.MESSAGE_BOX_ID);	
  if (!div) {
    div = document.createElement('div');
    div.setAttribute('id', LSN.MESSAGE_BOX_ID);
    bodyAppend(div);
  }
  div.innerHTML = '<button id="msgbox-btn-ok" type="button" '
    + 'onclick="hideMsgbox()">OK</button>'
    + '<div>' + text + '</div>';
  if (div.style.display != 'block') {
    _setPosition(div, props); // position in plain view
    div.style.display = 'block';
    div.style.visibility = 'visible';
  }
  getElement('msgbox-btn-ok').focus();
}

function hideMsgbox() {
  var div = getElement(LSN.MESSAGE_BOX_ID);	
  div.innerHTML = '';
  div.style.display = 'none';
  hideMask();
}

/*------------------------------------------------------------------------------
 * setStatus - Display a message in the middle of the screen
 *----------------------------------------------------------------------------*/

function setStatus(text, props) {
  var div = getElement(LSN.STATUS_ID);	
  if (!div) {
    div = document.createElement('div');
    div.setAttribute('id', LSN.STATUS_ID);
    bodyAppend(div);
  }
  div.innerHTML = text;
  div.style.display = 'block';
  _setPosition(div, props);
}

/*------------------------------------------------------------------------------
 * setStatus - Remove the status message from display
 *----------------------------------------------------------------------------*/

function clearStatus() {
  var div = getElement(LSN.STATUS_ID);	
  div.innerHTML = '';
  div.style.display = 'none';
}

/*------------------------------------------------------------------------------
 * setStatus - Display a status message for a brief time
 *----------------------------------------------------------------------------*/

function flashStatus(text) {
  setStatus(text);
  setTimeout("clearStatus()", 1250);
}

/*------------------------------------------------------------------------------
 * _setPosition - Position an absolute element with respect to the view port
 *----------------------------------------------------------------------------*/

function _setPosition(elem, props) {
  elem = getElement(elem);
  if (!props) props = {'position': 'top-third'}
  /* Backup display values */
  var attrVisibility = elem.style.visibility;
  var attrDisplay = elem.style.display;
  /* Set display values */
  elem.style.visibility = 'hidden'; // don't flicker when positioning
  elem.style.display = 'block'; // so get height/width work
  /* Calculate new position */
  var dims = getWindowSize();
  var vp = getViewportPosition();
  if (props.position == 'top-third') {
    var xy = getCenteredXY(elem);
    var t = parseInt(xy[1] - (dims[1]/4));
    if (t < LSN.CANVAS.scrollY()) t = LSN.CANVAS.scrollY();
    elem.style.left = xy[0] + "px";
    elem.style.top = t + "px";
  } else if (props.position == 'center') {
    var xy = getCenteredXY(elem);
    elem.style.left = xy[0] + "px";
    elem.style.top = xy[1] + "px";
  } else if (props.position == 'bottom-left') {
    vp['left'] += asInt(getCSSAttribute(elem, 'padding-left'));
    vp['top'] -= asInt(getCSSAttribute(elem, 'padding-bottom'));
    elem.style.left = vp['left'] + 'px';
    elem.style.top = (vp['top'] + vp['height'] - getHeight(elem)) + 'px';
  }
  /* display in new position */
  elem.style.visibility = 'visible';
  /* Restore original values */
  elem.style.visibility = attrVisibility;
  elem.style.display = attrDisplay;
}

/*------------------------------------------------------------------------------
 * trace - Display messages in a cumlative way
 *----------------------------------------------------------------------------*/

function traceln() {
  if (!arguments || arguments.length <= 0) return;
  var text = join('', arguments);
  return trace(text + '<br/>');
}

function trace() {
  var text = join('', arguments);
  var div = getElement(LSN.TRACE_BOX_ID);	
  if (!div) {
    div = document.createElement('div');
    div.setAttribute('id', LSN.TRACE_BOX_ID);
    bodyAppend(div);
  }
  div.innerHTML += text;
  div.scrollTop = div.scrollHeight;
  _setPosition(div, {'position': 'bottom-left'});
  div.style.display = 'block';
}
/* Copyright 2007 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

LSN.DIALOG_ID = "lsn_dialog";

/**
 * showDialog - Generic dialog
 */

function showDialog(url, params, styles) {
  var dlg = getElement(LSN.DIALOG_ID);
  if (!dlg) {
    dlg = createElement('div', {'display': 'none', 'id': LSN.DIALOG_ID});
    bodyAppend(dlg);
  }
  dlg.innerHTML = fetchText(url, params);
  if (styles) {
    for (var k in styles) {
      dlg.style[k] = styles[k];
    }
  }
  if (! (dlg.style.left || dlg.style.top)) {
    _setPosition(dlg);
  }
  dlg.style.display = 'block';
  showMask();
  return dlg;
}

/*------------------------------------------------------------------------------
 * showAuthDialog - Request user authentication.
 *----------------------------------------------------------------------------*/
function showAuthDialog() {
  var dlg = getElement(LSN.DIALOG_ID);

  var o = fetchObject('/res/html/login/login.html');
  if (o.head.links.js) {
    for(var i=0; i < o.head.links.js.length; i++) {
      includeScriptURI(o.head.links.js[i]);
    }
  }
  if (o.head.css) includeStyle(o.head.css);
  if (o.head.js) includeScript(o.head.js);

  if (!dlg) {
    dlg = createElement('div', {'display': 'none', 'id': LSN.DIALOG_ID});
    bodyAppend(dlg);
  }
  dlg.innerHTML = o.value;

  if (! (dlg.style.left || dlg.style.top)) {
    _setPosition(dlg);
  }
  dlg.style.display = 'block';
  showMask();
  return dlg;
}

function hideDialog() {
  var dlg = getElement(LSN.DIALOG_ID);
  if (dlg) dlg.style.display = 'none';
  hideMask();
}
/* Copyright 2006-2008 Livesite Networks, LLC. All rights reserved. */

/*------------------------------------------------------------------------------
 * includeScript - Add a script to the current page DOM
 * @param text Text string containing script
 * @param id (optional) Element ID (will replace existing)
 *----------------------------------------------------------------------------*/

function includeScript(text, id) {
  if (!id) id = randomId('script');
  var elem = getElement(id);
  if (elem) {
    removeChildren(elem);
    try {
      if (text) elem.appendChild(document.createTextNode(text));
    } catch(ex) {
      elem.text = text;
    }
  } else {
    _include('javascript', { type: 'text/javascript', id: id },text);
  }
}

/*------------------------------------------------------------------------------
 * includeScriptURI - Add a script from URI to the current page DOM
 * @param uri of the script to be included.
 *----------------------------------------------------------------------------*/

function includeScriptURI(uri) {
  /* First check if the js is currently linked */
  var scripts = document.getElementsByTagName('script');
  var isIncluded = false;
  for(var i=0; i < scripts.length; i++) {
    var script = scripts[i]
    /*TODO Intelligent URI matching. */
    if(script.getAttribute('src') == uri) {
      isIncluded = true;
      break;
    }
  }
  if (!isIncluded) _include('js', { 
    type: 'text/javascript',
    src: uri,
    id: 'includeScriptURI'
  });
}

/*------------------------------------------------------------------------------
 * includeStyle - Add a style or group of styles to the current page DOM
 * @param styles Text string containing styles
 * @param id (optional) Element ID (will replace existing)
 *----------------------------------------------------------------------------*/

function includeStyle(styles, id) {

  if (!id) id = 'style' + Math.floor(Math.random()*10000);
  var elem = getElement(id);
  if (elem) {
    removeChildren(elem);
    try {
      if (styles) elem.appendChild(document.createTextNode(styles));
    } catch(ex) {
      elem.styleSheet.cssText = text;
    }
  } else {

    _include('style', {
      'type':   'text/css',
      'media':  'screen',
      'id':     id
    }, styles);
  }
}

/*------------------------------------------------------------------------------
 * includeStyleURI - Add a stylesheet from URI to the current page DOM
 * @param uri of the stylesheet to be included.
 *----------------------------------------------------------------------------*/

function includeStyleURI(uri) {
  /* First check if the css is currently linked */
  var links = document.getElementsByTagName('link');
  var isIncluded = false;
  for(var i=0; i < links.length; i++) {
    var link = links[i]
    /*TODO Intelligent URI matching. */
    if(link.getAttribute('href') == uri) {
      isIncluded = true;
      break;
    }
  }
  if (!isIncluded) _include('css', { 
    type: 'text/css',
    rel: 'stylesheet',
    href: uri,
    media: 'screen',
    title: 'includeStyleURI'
  });
}

/*------------------------------------------------------------------------------
 * _include - add css or js items to the DOM without checks. For internal use.
 * @param type the type of item to include
 * @param props properties list for item.
 * @param text Contains string of content for populating
 *----------------------------------------------------------------------------*/

function _include(type, props, text) {
  var head = document.getElementsByTagName('head')[0];
  if (!head) return; // TODO
  if(type == 'css') {
    head.appendChild(createElement('link', props));
  } else if(type == 'style') {
    var styleElem = createElement('style', props);
    try {
      styleElem.appendChild(document.createTextNode(text));
    } catch(ex) {
      styleElem.styleSheet.cssText = text;
    }
    head.appendChild(styleElem);
  } else if(type == 'js') {
    head.appendChild(createElement('script', props));
  } else if(type == 'javascript') {
    var scriptElem = createElement('script', props);
    try {
      scriptElem.appendChild(document.createTextNode(text));
    } catch(ex) {
      scriptElem.text = text;
    }
    head.appendChild(scriptElem);
  }
}

/* ------------------------------------------------------------------------------
 * insertAfter - Insert an element after another.
 * @param elem Element to insert
 * @param target Element which is to presceed it
 * --------------------------------------------------------------------------- */

function insertAfter(elem, target) {
  var p = target.parentNode;
  if (p.lastChild == target) {
    p.appendChild(elem);
  } else {
    p.insertBefore(elem, target.nextSibling);
  }
}

/* ------------------------------------------------------------------------------
 * getStyle - Get CSS property
 * --------------------------------------------------------------------------- */

function getStyle(elem, propName) {
  return getCSSAttribute(elem, propName);
}

/* ------------------------------------------------------------------------------
 * setStyle - Set CSS property
 * --------------------------------------------------------------------------- */

function setStyle(elem, propName, propValue, importance) {
  var elem = getElement(elem);
  if (!elem) return;
  if (defined(elem.style.setProperty)) {
    elem.style.setProperty(propName, propValue, importance ? importance : null);
  } else {
    propName = asCamelCaseName(propName);
    if (propName == 'float') propName = 'cssFloat';
    elem.style[propName] = propValue;
    if (propName == 'cssFloat') {
      elem.style['styleFloat'] = propValue; /* The IE way */
    }
  }
}

/* ------------------------------------------------------------------------------
 * setAttribute - Set element attribute
 * --------------------------------------------------------------------------- */

function setAttribute(elem, attrName, attrValue) {
  var elem = getElement(elem);
  if (!elem) return;
  if (defined(elem.setAttribute)) {
    elem.setAttribute(attrName, attrValue);
  } else {
    if (attrName == 'class') attrName = 'className';
    elem[attrName] = attrValue;
  }
}
/*------------------------------------------------------------------------------
 * LSN.EVENTS - Storage for events
 * Used by the functions 'addEvent' and 'doEvents'.
 * This array is structured:
 *
 *  LSN.EVENTS[tag-name][event-name] = Array()
 *
 * For instance, you write the functions 'resetAllForms' and 'selectFirstRow',
 * and then add this to your javascript:
 *
 *  addEvent('window', 'load', 'resetAllForms()':
 *  addEvent('window', 'load', 'selectFirstRow()':
 *
 * and this structure will contain:
 *
 *  LSN.EVENTS['window']['load'][0] = Function('resetAllForms()');
 *  LSN.EVENTS['window']['load'][1] = Function('selectFirstRow()');
 *----------------------------------------------------------------------------*/

LSN.EVENTS = new Array();

/*------------------------------------------------------------------------------
 * addEvent - Add an event
 * @param tag of the target element
 * @param name of the event
 * @param js code to execute (text)
 *----------------------------------------------------------------------------*/

function addEvent(tag, name, js, id) {
  if (!LSN.EVENTS[tag]) {
    LSN.EVENTS[tag] = new Array();
  }
  var namespace = LSN.EVENTS[tag];
  if (!namespace[name]) {
    namespace[name] = new Array();
  }
  var events = namespace[name];
  events[events.length] = new jsEvent(js, id);
}

function jsEvent(js, id) {
  this.id = id;
  this.handler = typeof(js) == 'function' ? js : new Function(js);
  return this;
}

function removeEvent(id) {
  if (!id) return;
  for (var tag in LSN.EVENTS) {
    for (name in LSN.EVENTS[tag]) {
      for (var idx = 0; idx < LSN.EVENTS[tag][name].length; idx++) {
        if (LSN.EVENTS[tag][name][idx].id == id) LSN.EVENTS[tag][name].splice(idx, 1);
      }
    }
  }
}

/*------------------------------------------------------------------------------
 * doEvents - Execute events
 * @param tag of the target element
 * @param name of the event
 *----------------------------------------------------------------------------*/

function doEvents(tag, name, p) {
  var retval = true;
  if (LSN.EVENTS[tag] && LSN.EVENTS[tag][name]) {
    for(var idx in LSN.EVENTS[tag][name]) {
      var eventObj = LSN.EVENTS[tag][name][idx];
      var eventFunc = eventObj.handler;
      if (typeof(eventFunc) == "function") {
        var func_retval;
        if (p && p.length) {
          if(p.length == 1) {
            func_retval = eventFunc(p[0]);
          } else if (p.length == 2) {
            func_retval = eventFunc(p[0],p[1]);
          } else if (p.length == 3) {
            func_retval = eventFunc(p[0],p[1],p[2]);
          } else if (p.length == 4) {
            func_retval = eventFunc(p[0],p[1],p[2],p[3]);
          } else if (p.length == 5) {
            func_retval = eventFunc(p[0],p[1],p[2],p[3],p[4]);
          } else if (p.length == 6) {
            func_retval = eventFunc(p[0],p[1],p[2],p[3],p[4],p[5]);
          } else if (p.length == 7) {
            func_retval = eventFunc(p[0],p[1],p[2],p[3],p[4],p[5],p[6]);
          } else if (p.length == 8) {
            func_retval = eventFunc(p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]);
          }
        } else {
          func_retval = eventFunc();
        }
        if (typeof(func_retval) != 'undefined') {
          retval &= func_retval;
        }
      }
    }
  }
  return retval;
}

/*------------------------------------------------------------------------------
 * Global event handlers.  Although this removes any existing event handlers,
 * from this point forward a handler can be added with:
 *   addEvent('window', event_name, "js code");
 *----------------------------------------------------------------------------*/

if (typeof(window.captureEvents) == 'function') {
  window.captureEvents(Event.MOUSEMOVE, Event.MOUSEUP);
}

/*------------------------------------------------------------------------------
 * initEvent - Set even handler for an object while preserving any which exist
 * @param target Such as window or document or an element
 * @param tagName Is the generic name of the target, like 'window'
 * @param eventName Such as 'mousemove'
 *----------------------------------------------------------------------------*/

function initEvent(target, tagName, eventName) {

  var currentHandler = target['on'+eventName];
  target['on'+eventName]  = new Function(
    "doEvents('"+tagName+"', '"+eventName+"', arguments)"
  );

  /*  !!!
   *    This is how it *should* be, but it is broken when
   *    net.livesite.js is included twice (perhaps different url's)
   *  !!!
  if (typeof(currentHandler) == 'function') {
      addEvent(tagName, eventName, currentHandler);
  }
  */
}

initEvent(window, 'window', 'load');
initEvent(window, 'window', 'resize');

if (window.opera) {
  initEvent(document, 'window', 'mousemove');
  initEvent(document, 'window', 'mouseup');
  initEvent(document, 'window', 'scroll');
} else if (document.all) {
  initEvent(document, 'window', 'mousemove');
  initEvent(document, 'window', 'mouseup');
  initEvent(window, 'window', 'scroll');
} else {
  initEvent(window, 'window', 'mousemove');
  initEvent(window, 'window', 'mouseup');
  initEvent(document, 'window', 'scroll');
}
/* Copyright 2006 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

/*------------------------------------------------------------------------------
 * modexec - Execute a server-side module
 * @param sub Address of subroutine to execute
 * @param args (optional) method arguments
 * @param method (optional) either "GET" or "POST"
 *
 * where:
 *
 *  args['on_success']     function to execute on success
 *  args['on_failure']     function to execute on failure
 *  args['params']         parameters passed to subroutine
 *
 * When either result function is called, it is passed a single argument, the
 * result object.  The result object will contain:
 *
 *  r['success']            true or false
 *  r['message']            brief message which is user comprehendable
 *  r['value']              value returned by the subroutine
 *  r['status']             contextual status code
 *  r['...']                any value the subroutine decided to set.  it is
 *                          convention that these fields correlate with
 *                          the status field.  Meaning, if r['status'] is
 *                          'multple-options', then r['multiple-options']
 *                          should contain these options from which to
 *                          choose.
 *
 * If neither 'on_success' nor 'on_failure' is provided, the default behaviour
 * is to only alert r['message'] on failure.
 *----------------------------------------------------------------------------*/

function modexec(sub, args, method) {
  var params = args['params'] ? args['params'] : new Object();
  params['sub'] = sub;
  var r = fetchObject('Action-modexec', params, method);
  if (r.success) {
    if (args['on_success']) args['on_success'](r);
  } else {
    if (args['on_failure']) {
      args['on_failure'](r);
    } else {
      alert(r.message);
    }
  }
  return r;
}

/*------------------------------------------------------------------------------
 * fetchObject - Translate a response which is eval-able as a JavaScript object.
 * @param url request URL
 * @param params (optional) request parameters
 * @param method (optional) either "GET" or "POST"
 *----------------------------------------------------------------------------*/

function fetchObject(url,params,method) {
  var result = null;
  if (typeof(params) == 'object') params['return'] = 'js';
  if (!defined(params)) params = { 'return': 'js' }; 
  try {
    var req = fetch(url,params,method);
  } catch (err) {
    return {'success': false, 'message': err, 'innerText': err};
  }
  try {
    var text = req.responseText;
    eval("result = " + text);
  } catch (err) {
    result = {message: text};
  } finally {
    delete req;
  }
  return result;
}

/*------------------------------------------------------------------------------
 * fetchText - Get a text response.
 * @param url request URL
 * @param params (optional) request parameters
 * @param method (optional) either "GET" or "POST"
 *----------------------------------------------------------------------------*/

function fetchText(url,params,method) {
  var req = fetch(url,params,method);
  return req.responseText;
}

/*------------------------------------------------------------------------------
 * fetchXML - Get an XML response.
 * @param url request URL
 * @param params (optional) request parameters
 * @param method (optional) either "GET" or "POST"
 *----------------------------------------------------------------------------*/

function fetchXML(url,params,method) {
  var req = fetch(url,params,method);
  return req.responseXML;
}

/*------------------------------------------------------------------------------
 * fetchTree - Get a hierarchical data object structure of the XML response.
 * @param url request URL
 * @param params (optional) request parameters
 * @param method (optional) either "GET" or "POST"
 *----------------------------------------------------------------------------*/

function fetchTree(url,params,method) {
  return new Tree(fetchXML(url,params,method));
}

/*------------------------------------------------------------------------------
 * fetch - Synchonous XMLHttpRequest wrapper.
 * @param url request URL
 * @param params (optional) request parameters
 * @param method (optional) either "GET" or "POST"
 *----------------------------------------------------------------------------*/

function fetch(url, params, method) {
  var req;
  var lastCursor = getPageCursor();
  if (!method) method = params ? "POST" : "GET";
  if (window.XMLHttpRequest) {
    req = new XMLHttpRequest();
  } else if( window.ActiveXObject ) {
    req = new ActiveXObject( "Microsoft.XMLHTTP" );
  }
  if (req) {
    req.open(method, url, false); // false meaning not async
    if (params) {
      req.setRequestHeader( "Content-Type",
        "application/x-www-form-urlencoded; charset=UTF-8" );
      if (typeof(params) == 'object') {
        params = objToQueryString(params);
      }
    }
    req.send(params);
    return req;
  }
  return null;
}

function objToQueryString(params, key) {
  var result = '';
  if (typeof(params) == 'function') {
    return '';
  }
  if (typeof(params) == 'object') {
    for (var k in params) {
      var subkey = key ? key + '/' + k : k;
      result += objToQueryString(params[k], subkey);
    }
  } else {
    var value = '';
    switch(typeof(params)) {
      case 'boolean': value = params ? '1' : '0'; break;
//    case 'string': value = pack_cgi(pack_nonprinting(params)); break;
//    case 'string': value = escape(escape_url_chars(params)); break;
      case 'string': value = encodeURIComponent(params); break;
      default: value = params;
    }
//traceln(key, ' = ', value, '(', typeof(params), ')');
    result += key
      ? key + '=' + value + ';'
      : value + ';';
  }
  return result;
}

/*------------------------------------------------------------------------------
 * getXMLData - Extract data from an XMLHttpRequest response object.
 * @param obj XMLHttpRequest response object
 * @param key xml element id
 *----------------------------------------------------------------------------*/

function getXMLData(obj,key) {
  if (obj.readyState == 4 && obj.status == 200) {
    if (obj.responseXML != null) {
      var elem = obj.responseXML.getElementById(key)
      if (elem && elem.firstChild) {
        return elem.firstChild.data;
      } else {
        throw "No element identified by: " + key;
      }
    }
  }
  return null;
}
/* Copyright 2006 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

/*------------------------------------------------------------------------------
 * getContentWindow - Returns the inner contentWindow of an IFRAME or FRAME.
 * @param id of the FRAME or IFRAME
 * @param verifiy (optional) element id
 * If <code>verify</code> is set, only return the contentWindow if it has an 
 * element by that ID.
 *----------------------------------------------------------------------------*/

function getContentWindow( id, verify ) {
  var content = document.getElementById( id );
  if( ! content ) {
    content = window.frames[id];
  }
  if( content ) {
    var cwin = content.contentWindow;
    if( verify ) {
      if( cwin.document.getElementById( verify ) ) {
        return content.contentWindow;
      }
    } else {
      return content.contentWindow;
    }
  }
  return false;
}

/*------------------------------------------------------------------------------
 * getContentDocument - Return the content document for the specified iframe.
 * @param frameid target frame id
 *----------------------------------------------------------------------------*/

function getContentDocument(frameid) {
  var doc;
  if (document.all) {
    doc = frames[frameid].document;
  } else {
    var iframe = getElement(frameid);
    var doc = iframe.contentDocument;
  }
  return doc;
}
LSN.KEYPRESS_HANDLERS = new Array();
LSN.ACCEPTING_KEYBOARD_EVENTS = true;

function KeyPress() {
    this.setHandler     = _setHandler;
    this.attach         = _attach;
    this.onKeyPress     = _onKeyPress;
    this.onKeyDown      = _onKeyDown;
    this.doEvent        = _doEvent;
    this.handlers       = new Array();
    return this;
}

function _setHandler(ascii_code, func_body) {
  this.handlers[ascii_code] = new Function(func_body);
}

function _attach(elem) {
  elem = getElement(elem);
  var key = makeElemKey(elem);
  LSN.KEYPRESS_HANDLERS[key] = this;
  elem.onkeypress_id = key;
  elem.onkeypress = this.onKeyPress;
  elem.onkeydown  = this.onKeyDown;
}

function _onKeyPress(event) {
  if (!LSN.ACCEPTING_KEYBOARD_EVENTS) return;
  LSN.ACCEPTING_KEYBOARD_EVENTS = false;
  if (!event) event = window.event;
  var kp = LSN.KEYPRESS_HANDLERS[ this.onkeypress_id ];
  return kp.doEvent(event);
}

function _doEvent(event) {
  var stopEvent = false;
  var kp = this;
  var char_code = getCharCode(event);
  var ascii_code = getAsciiSequence(event);
  var ascii_code2 = getAsciiSequence(event, true);
  var handler = typeof(kp.handlers[ascii_code]) == "function"
    ? kp.handlers[ascii_code]
    : typeof(kp.handlers[ascii_code2]) == "function"
      ? kp.handlers[ascii_code2]
      : undefined;
  if (handler) {
    handler();
    stopEvent = true;
    }
  LSN.ACCEPTING_KEYBOARD_EVENTS = true;
  if (stopEvent) {
    try {
      event.preventDefault();
    } catch(err) {
    }
    return false;
  } else {
    return true;
  }
}

function _onKeyDown(event) {
  if (document.all) {
    if (!event) var event = window.event;
    var char_code = getCharCode(event);
    // Forward events from IE:
    //  - arrow keys
    //  - tab
    if ((char_code == 9) || ((char_code >= 37) && (char_code <= 40))) {
      var kp = LSN.KEYPRESS_HANDLERS[this.onkeypress_id];
      return kp.doEvent(event);
    }
  }
}

function makeElemKey(elem) {
  var uid = Math.floor(Math.random() * 1000);
  var elem_key = String(elem) + "@" + uid;
  return elem_key;
}

function getAsciiSequence(event, numeric) {
  var char_code = getCharCode(event);
  var ascii_code = String.fromCharCode(char_code).toLowerCase();
  var sequence = event.altKey ? "alt+" : "";
  if (event.ctrlKey) sequence += "ctrl+";
  if (event.shiftKey) sequence += "shift+";
  if (numeric) return sequence + char_code;
  switch (char_code) {
    case 9    : sequence += 'tab';
                break;
    case 13   : sequence += 'enter';
                break;
    case 27   : sequence += 'esc';
                break;
    default   : sequence += ascii_code;
  }
  return sequence;
}

function getCharCode(event) {
  return  event.which     ? event.which     :
          event.keyCode   ? event.keyCode   :
          event.charCode  ? event.charCode  :
                            0;
}
/* Copyright 2006 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

/*------------------------------------------------------------------------------
 * createEMail - Create an email message (ala mailto:)
 * @param name recipient name
 * @param domain recipient domain
 * This is a placeholder implementation.  The goal is to provide a public
 * webpage with which one can encrypt email addresses which are decrypted here.
 *----------------------------------------------------------------------------*/

function createEmail(name,domain) {
  var href = "mail";
  href += "to:";
  href += name;
  href += "@"
  href += domain;
  document.location = href;
}
/* Copyright 2006 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

function asInt(unk) {
  var i = unk;
  if (typeof(unk) == 'string') {
    i = parseInt(unk.replace("\w", ""));
  }
  return isNaN(i) ? 0 : i;
}

function randomId(p,m) {
  if (!m) m = 10000;
  var n = Math.floor(Math.random()*m);
  return p ? p + n : n;
}

function asHyphenatedName(name) {
  function upperToHyphenLower(match) { return '-' + match.toLowerCase(); }
  return name.replace(/[A-Z]/g, upperToHyphenLower);
}

function asCamelCaseName(name) {
  function ucFirstMatch(str, p1, offest, s) { return p1.toUpperCase(); }
  return name.replace(/-([a-z])/g, ucFirstMatch);
}

function join(delim) {
  var str = undefined;
  for (var i = 1; i < arguments.length; i++) {
    if (typeof(arguments[i]) == 'undefined') {
      continue;
    } else if (typeof(arguments[i]) == 'array') {
      for (var j = 0; j < arguments[i].length; j++) {
        str = str == undefined ? '' : str + delim;
        str += arguments[i][j];
      }
    } else if (typeof(arguments[i]) == 'object') {
      if (defined(arguments[i].length)) {
        for (var j = 0; j < arguments[i].length; j++) {
          str = str == undefined ? '' : str + delim;
          str += arguments[i][j];
        }
      } else {
        for (var j in arguments[i]) {
          str = str == undefined ? '' : str + delim;
          str += j + delim + arguments[i][j];
        }
      }
    } else {
      str = str == undefined ? '' : str + delim;
      str += arguments[i];
    }
  }
  return str;
}

/* Encoding and decoding */

function unpack_ncr(str) {
  /* Hexadecimal */
  str = str.replace( /&#x([\da-f]{2,4});/gi,
    function($0, $1) {
      return String.fromCharCode("0x" + $1);
    });
  /* Decimal */
  str = str.replace( /&#([\d]{2,4});/gi,
    function($0, $1) {
      return String.fromCharCode($1);
    });
  return str;
}

/* the term "non-printing" should really be "non-printing-ascii" */

function _isNonprinting(c) {
  return (c < 32 && c != 9 && c != 10 && c != 13) || c > 127;
}

function unpack_nonprinting(str) {
  return str.replace( /&#([\d]{2,4});/gi,
  function($0, $1) {
    return _isNonprinting($1) ? String.fromCharCode($1) : $0;
  });
}

function pack_nonprinting(str) {
  return str.replace(/\W/g,
  function($0) {
    var ord = $0.charCodeAt().toString(10).toUpperCase();
    return _isNonprinting($0.charCodeAt()) ? "&#" + ord + ";" : $0;
  });
}

function pack_ncr(str) {
  return str.replace(/\W/g,
  function($0) {
    return "&#" + $0.charCodeAt().toString(10).toUpperCase() + ";";
  });
}

function unpack_cgi(str) {
  return str.replace( /%([\da-f]{2})/gi,
  function($0, $1) {
    return String.fromCharCode("0x" + $1);
  });
}

function pack_cgi(str) {
  return(str.replace(/\W/g,
    function($0) {
      var hex = $0.charCodeAt().toString(16).toUpperCase();
      hex = hex.length == 1 ? "0" + hex : hex;
      return "%" + hex;
    }));
}

function escape_url_chars(str) {
/*return(str.replace(/[\*\@\-\_\+\.\/]/g,*/
  return(str.replace(/[\+]/g,
    function($0) {
      var hex = $0.charCodeAt().toString(16).toUpperCase();
      hex = hex.length == 1 ? "0" + hex : hex;
      return "%" + hex;
    }));
}
/* Copyright 2006 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

/*------------------------------------------------------------------------------
 * applyFilters - Apply microsoft filters.
 * @param obj target object
 * @param filter_name short name of filter 
 * filter_name fills in this blank: progid:DXImageTransform.Microsoft.____
 *----------------------------------------------------------------------------*/

function applyFilters( obj, filter_name ) {
  if( ! document.all ) { return false; }
  if( obj ) {
    obj.style.filter = "progid:DXImageTransform.Microsoft." + filter_name;
    if( obj.filters ) {
      for( var i=0; i < obj.filters.length; i++ ) {
        var filter = obj.filters[i];
        filter.Apply();
        return true;
      }
    }
  }
}

/*------------------------------------------------------------------------------
 * playFilters - Play microsoft filters.
 * @param obj target object.
 *----------------------------------------------------------------------------*/

function playFilters( obj ) {
  if( ! document.all ) { return false; }
  if( obj ) {
    if( obj.filters ) {
      for( var i=0; i < obj.filters.length; i++ ) {
        var filter = obj.filters[i];
        filter.Play();
        return true;
      }
    }
  }
}
/* Copyright 2006-2007 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

LSN.MOUSE_X = -1;
LSN.MOUSE_Y = -1;

addEvent('window', 'mousemove', trackMousePosition);

function getPageCursor() {
  try {
    return getBody().style.cursor;
  } catch (ex) {
    throw new Error(ex);
  }
}

function setPageCursor(state) {
  try {
    getBody().style.cursor = state;
  } catch (ex) {
    throw new Error(ex);
  }
}

/*------------------------------------------------------------------------------
 * trackMousePosition - Set LSN.MOUSE_X and LSN.MOUSE_Y to current position
 * @param e event
 *
 * This method is part of the event chain for window.onMouseMove.  But 
 * sometimes you will want to call this manually (from an event) when your
 * event is triggered before onMouseMove();
 *----------------------------------------------------------------------------*/

function trackMousePosition(e) {
  var xy = getMouseXY(e);
  if (xy) {
    LSN.MOUSE_X = xy[0];
    LSN.MOUSE_Y = xy[1];
  }
}

/*------------------------------------------------------------------------------
 * isMouseOver - Is the mouse over any of the given elements?
 * @param element Element or ID
 * @param element (optional) Element or ID
 * @param element (optional) Element or ID
 * @param element (optional) ...
 * 
 * Note, if you are calling this form an event handler such as onMouseOut,
 * you should call trackMousePosition(event) in order to ensure the X/Y coords
 * are up-to-date.
 *----------------------------------------------------------------------------*/

function isMouseOver() {
  var result = false;
  for (var i = 0; i < arguments.length; i++) {
    var elem = getElement(arguments[i]);
    if (!elem) continue;
    var t = getTop(elem);
    var l = getLeft(elem);
    var w = getWidth(elem);
    var h = getHeight(elem);
    if (document.all) {
      result = LSN.MOUSE_X > l && LSN.MOUSE_X < (l+w)
            && LSN.MOUSE_Y > t && LSN.MOUSE_Y < (t+h);
    } else {
      result = LSN.MOUSE_X >= l && LSN.MOUSE_X < (l+w)
            && LSN.MOUSE_Y >= t && LSN.MOUSE_Y < (t+h);
    }
//  if (result) window.status = i +": "+ l +"/"+ LSN.MOUSE_X +"/"+ (l+w) +" | "+ " "+ t +"/"+ LSN.MOUSE_Y +"/"+ (t+h);
    if (result) break;
  }
  return result;
}

/*------------------------------------------------------------------------------
 * isMouseInside - Is the mouse inside the given element
 * @param element Element or ID
 * @param border_sz offest of what is considered 'inside'
 * 
 * Note, if you are calling this form an event handler such as onMouseOut,
 * you should call trackMousePosition(event) in order to ensure the X/Y coords
 * are up-to-date.
 *----------------------------------------------------------------------------*/

function isMouseInside(elem, border_sz) {
  if (!border_sz) border_sz = 0;
  var result = false;
  var t = getTop(elem) + border_sz;
  var l = getLeft(elem) + border_sz;
  var w = getWidth(elem) - (2*border_sz);
  var h = getHeight(elem) - (2*border_sz);
  if (document.all) {
    result = LSN.MOUSE_X > l && LSN.MOUSE_X < (l+w)
          && LSN.MOUSE_Y > t && LSN.MOUSE_Y < (t+h);
  } else {
    result = LSN.MOUSE_X >= l && LSN.MOUSE_X < (l+w)
          && LSN.MOUSE_Y >= t && LSN.MOUSE_Y < (t+h);
  }
//traceln( l +"/"+ LSN.MOUSE_X +"/"+ (l+w) +" | "+ " "+ t +"/"+ LSN.MOUSE_Y +"/"+ (t+h));
  return result;
}

/*------------------------------------------------------------------------------
 * getMouseXY - Get the current xy coordinates
 * @param e event
 *----------------------------------------------------------------------------*/

function getMouseXY(e) {
  var x = -1;
  var y = -1;
  if (!e) e = window.event;
  if (e) {
    if (e.pageX || e.pageY) {
      x = e.pageX;
      y = e.pageY;
    } else if (e.clientX || e.clientY) {
      x = e.clientX;
      y = e.clientY;
      if (document.body) {
        x += document.body.scrollLeft;
        y += document.body.scrollTop;
      }
      if (document.documentElement) {
        x += document.documentElement.scrollLeft;
        y += document.documentElement.scrollTop;
      }
    }
    return [x, y];
  }
  return undefined;
}
LSN.MOVE_TARGET = _newMoveTarget();

addEvent('window', 'mousemove', function(event) { _moveElement(event);});
addEvent('window', 'mouseup', "_removeMoveTarget();");

/**
 * _newMoveTarget - Create a new move target
 */

function _newMoveTarget() {
    t = new Object();
    t.elem     = undefined;
    t.orig_x   = 0;
    t.orig_y   = 0;
    t.orig_mx  = 0;
    t.orig_my  = 0;
    t.active   = false;
    return t;
}

/**
 * setMoveTarget - Begin moving an element
 */

function setMoveTarget(mozevent, elem, props) {
    stopWindowEvents();
    elem = getElement(elem);
    var vp = getViewportPosition();
    if( elem ) {
        LSN.MOVE_TARGET           = _newMoveTarget();
        LSN.MOVE_TARGET.elem      = elem;
        LSN.MOVE_TARGET.active    = true;
        LSN.MOVE_TARGET.orig_mx   = LSN.MOUSE_X;
        LSN.MOVE_TARGET.orig_my   = LSN.MOUSE_Y;
        LSN.MOVE_TARGET.orig_z    = elem.style.zIndex;
        LSN.MOVE_TARGET.min_x     = vp['left'];
        LSN.MOVE_TARGET.min_y     = vp['top'];

        var orig_x = getLeft(elem);
        var orig_y = getTop(elem);
        var ppos = getCSSAttribute(elem.offsetParent, 'position');
//traceln('ppos:'+ppos);
        if (ppos && (ppos == 'absolute' || ppos == 'relative')) {
          var px = getLeft(elem.offsetParent);
          var py = getTop(elem.offsetParent);
          orig_x -= px;
          orig_y -= py;
//traceln('adjust:'+px+'/'+py);
          LSN.MOVE_TARGET.min_x = vp['left'] - px;
          LSN.MOVE_TARGET.min_y = vp['top'] - py;
        }
        LSN.MOVE_TARGET.orig_x = orig_x;
        LSN.MOVE_TARGET.orig_y = orig_y;

        // max values are adjusted by 15 to account for running in
        // to the edge of the screen and causing a scrollbar to
        // be created.
        var dims = getPageSize();
        LSN.MOVE_TARGET.max_x = vp['left'] + vp['width'] - getWidth(elem) - getScrollbarWidth();
        LSN.MOVE_TARGET.max_y = vp['top'] + vp['height'] - getHeight(elem) - getScrollbarWidth();

        // Position the element absolutely
        elem.style.position   = "absolute";
        elem.style.left = (LSN.MOVE_TARGET.orig_x).toString(10) + 'px';
        elem.style.top  = (LSN.MOVE_TARGET.orig_y).toString(10) + 'px';
        elem.style.zIndex  = LSN.LAYER_TOP;

        // Set event handlers
        if (props) {
          if (typeof(props.onmove) == 'function') {
            LSN.MOVE_TARGET.onmove = props.onmove;
          }
          if (typeof(props.ondrop) == 'function') {
            LSN.MOVE_TARGET.ondrop = props.ondrop;
          }
        }
    }
}

function _moveElement(event) {
    if(!LSN.MOVE_TARGET || !LSN.MOVE_TARGET.active) return;

    trackMousePosition(event);
    var delta_x = LSN.MOUSE_X - LSN.MOVE_TARGET.orig_mx;
    var delta_y = LSN.MOUSE_Y - LSN.MOVE_TARGET.orig_my;
    var elem    = LSN.MOVE_TARGET.elem;
    var new_x   = LSN.MOVE_TARGET.orig_x + delta_x;
    var new_y   = LSN.MOVE_TARGET.orig_y + delta_y;

    if (new_x > LSN.MOVE_TARGET.max_x) new_x = LSN.MOVE_TARGET.max_x;
    if (new_y > LSN.MOVE_TARGET.max_y) new_y = LSN.MOVE_TARGET.max_y;
    if (new_x < LSN.MOVE_TARGET.min_x) new_x = LSN.MOVE_TARGET.min_x;
    if (new_y < LSN.MOVE_TARGET.min_y) new_y = LSN.MOVE_TARGET.min_y;

    elem.style.left = (new_x).toString(10) + 'px';
    elem.style.top  = (new_y).toString(10) + 'px';

    if (LSN.MOVE_TARGET.onmove) {
      LSN.MOVE_TARGET.onmove(LSN.MOVE_TARGET);
    }
}

function _removeMoveTarget() {
    if (!LSN.MOVE_TARGET) return;
    restoreWindowEvents();
    elem = LSN.MOVE_TARGET.elem;
    if (elem && elem.style) {
      elem.style.zIndex = LSN.MOVE_TARGET.orig_z;
    }
    if (LSN.MOVE_TARGET.ondrop) {
      LSN.MOVE_TARGET.ondrop(LSN.MOVE_TARGET);
    }
    LSN.MOVE_TARGET = _newMoveTarget();
}

var EVENT_BUFFER = new Object();

function stopWindowEvents() {
  if( document.all ) {
    EVENT_BUFFER.doc_onselectstart = document.onselectstart;
    EVENT_BUFFER.win_onmousedown = window.onmousedown;
    document.onselectstart = function(){return false;};
    window.onmousedown = function(){return false;};
  } else {
    EVENT_BUFFER.doc_onmousedown = document.onmousedown;
    document.onmousedown = function(){return false;};
  }
}

function restoreWindowEvents() {
  if(!LSN.MOVE_TARGET || !LSN.MOVE_TARGET.active) return;
  if( document.all ) {
    document.onselectstart = EVENT_BUFFER.doc_onselectstart; 
    window.onmousedown = EVENT_BUFFER.win_onmousedown; 
  } else {
    document.onmousedown = EVENT_BUFFER.doc_onmousedown;
  }
}
/* Copyright 2007 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

LSN.DIALOGS = new Object();

/* ------------------------------------------------------------------------------
 * Dialog - An interactive widget
 *
 *  var dlg = new Dialog('/mydialog.html');
 *  dlg.addEvent('oncancel', function() {dlg.hide()}; // default behavior
 *  dlg.addEvent('onok', function() {alert(join(';',dlg.value); dlg.hide()};
 *  dlg.show();
 *
 * This object extends Request
 * --------------------------------------------------------------------------- */

function Dialog(uri) {
  this.widget = new Widget(uri);
  this.events = new Array();
  this.id = 'dlg' + Math.floor(Math.random()*10000);
  this.widget.request.addParameter('dlgid', this.id);
  this.values = new Object();
  this.ctrls = [];
  this.btns = [];
  this.kp = new KeyPress();
  this.handleKeypress = {'ok':true, 'cancel':true};
  LSN.DIALOGS[this.id] = this;
}

Dialog.prototype.addEvent = function(name, func) {
  if(!this.events[name]) this.events[name] = new Array();
  this.events[name].push(func);
}

Dialog.prototype.doEvent = function(name, event) {

  /* For convenience, gather values if an ok button was clicked */
  if (name == 'ok') {
    this.getValues();
  }

  /* Fire user events */
  if (this.events[name]) {
    for (var i = 0; i < this.events[name].length; i++) {
      this.events[name][i](event);
    }
  }

  /* For convenience, close the dialog if an ok or cancel buttons was clicked */
  if (name == 'ok' || name == 'cancel') {
    this.hide();
  }

  /* Set focus keyboard handlers when the dialog is shown */
  if (name == 'show') {
    if (this.ctrls.length > 0) {
      this.ctrls[0].focus();
    } else if (this.btns.length > 0) {
      this.btns[0].focus();
    }
  }
}

Dialog.prototype.refetch = function() {
  if (this.widget.request.response) {
    this.destroy();
    this.widget.fetch();
  }
};

Dialog.prototype.show = function() {

  /* If the dialog has been hidden, simply un-hide it */
  var elem = getElement(this.id);
  if (elem) {
    elem.style.display = 'block';
    this.doEvent('show');
    return;
  }

  /* Fetch the dialog from the server (only once) */
  if (!this.widget.request.response) {
    this.widget.fetch();
  }

  /* Append dialog to the document body */
  var dlgDiv = createElement('div', {
    'id':         this.id,
    'innerHTML':  this.widget.innerHTML
  });
  getBody().appendChild(dlgDiv);
  this.kp.attach(dlgDiv);

  /* Extract buttons and input controls */
  this.ctrls = getChildrenByAttrs(this.id, {'name': '~values\/[a-z]+'});
  this.btns = getChildrenByAttrs(this.id, {'name': '~action\/[a-z]+'});

  /* Assign event handlers to buttons */
  for (var i = 0; i < this.btns.length; i++) {
    var name = this.btns[i].name;
    var action = name.match(/action\/([a-z]+)/);
    var js = 'LSN.DIALOGS["'+this.id+'"].doEvent("'+action[1]+'")';
    this.btns[i].onclick = new Function(js);
    if (this.handleKeypress[action[1]]) {
      if (action[1] == 'ok') {
        this.kp.setHandler('enter', js);
      } else if (action[1] == 'cancel') {
        this.kp.setHandler('esc', js);
      } else {
        throw "Cannot auto-handle kepress event: " + action[1];
      }
    }
  }

  this.doEvent('show');
};

Dialog.prototype.getValues = function() {
  for (var i = 0; i < this.ctrls.length; i++) {
    var ptr = this.values;
    var path = this.ctrls[i].name.split('/');
    for (var j = 1; j < path.length; j++) {
      ptr[path[j]] = defined(path[j+1])
        ? isNaN(path[j+1])
          ? new Object()
          : new Array()
        : getValue(this.ctrls[i].id);
      ptr = ptr[path[j]];
    }
  }
  return this.values;
};

Dialog.prototype.hide = function() {
  getElement(this.id).style.display = 'none';
  this.doEvent('hide');
};

Dialog.prototype.destroy = function() {
  var dlg = getElement(this.id);
  if (dlg) dlg.parentNode.removeChild(dlg);
};
/* Copyright 2007 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

function Error(msg) {
  if (typeof(msg) == 'string') {
    this.message = msg;
  } else if (msg instanceof Object) {
    for (var key in msg) {
      this[key] = msg[key];
    }
  }
}

Error.prototype = {
  'status':   '',
  'message':  'An error ocurred'
};
/* Copyright 2007 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

/* ------------------------------------------------------------------------------
 * ModExec - Server-side script request
 * var req = new ModExec(uri);
 *
 * This object extends Request
 * --------------------------------------------------------------------------- */

function ModExec(uri) {
  var obj = new Request('/Action-modexec');
  obj.result = undefined;
  obj.addParameter('sub', uri);
  obj.submit = function() {
    this.response = fetchObject(this.uri, this.parameters);
    if (!this.response.success) throw new Error(this.response);
    this.result = this.response.value;
    return this.result;
  };
  return obj;
}
/**
 * Navigator.js - JavaScript Object: Navigator.
 *
 * Programming Standards:
 *
 *  The constructor is the same name as the file (w/o the .js extension).
 *
 *  Private functions are prefixed with an underscore.
 *
 *  Variables are all lower-case, and separated with an underscore.
 *
 *  Methods are camel-case, with the first word lower-cased.
 */

/**
 * Navigator
 *
 * Constructor.
 *
 * @param   frame_id <code>String</code>ID attribute of target HTMLFrame
 * @param   data <code>Array</code> Array of ScreenImpl.jsObject's
 * @return  <code>Navigator</code>
 */

function Navigator( frame_id, data, custom ) {

    /* -------------------------------------------------------------------------
     * Public
     * ---------------------------------------------------------------------- */

    /* Options */

    this.use_filters    = false;        /* Transition filters */

    /* Functions */

    this.show           = _show;        /* Show the current screen */

    this.reset          = _reset;       /* Internally points to the first screen */
    this.first          = _first;       /* Go to the first screen */
    this.last           = _last;        /* Go to the last screen */
    this.prev           = _prev;        /* Go to the previous screen */
    this.next           = _next;        /* Go to the next screen */
    this.jump           = _jump;        /* Jump to a screen by ID (*not* index) */
    this.transition     = _transition;  /* Event hook */

    /* -------------------------------------------------------------------------
     * Custom (provided) functions
     * ---------------------------------------------------------------------- */

    for( var func in custom ) {

        var func_body = func == "onTransition" ?
            custom[func] : "this.transition();" + custom[func];

        /* replace embedded quotes and strip newlines */
        var escaped = func_body.replace( /([^\\])\"/g, "$1\\\"" )
                               .replace( /(\\n|\n)/g, "" );

        eval( "this." + func + " = new Function( \"" + escaped + "\" )" );

    }

    /* -------------------------------------------------------------------------
     * Protected
     * ---------------------------------------------------------------------- */

    /* Members */

    this.frame_id       = frame_id;
    this.target_doc     = getContentDocument( frame_id );
    this.target_win     = getContentWindow( frame_id );
    this.frame          = document.getElementById( frame_id );
    this.data           = data;
    this.idx_current    = 0;
    this.idx_from       = 0;
    this.idx_first      = 0;
    this.idx_last       = data.length - 1;
    this.screen         = data[0];
    this.motion         = "begin";
    this.filtering      = false;

    /* Functions */

    this.navto          = _navto;
    this.onDisplay      = _onDisplay;

    /**
     * possible filters (IE only):
     *
     *  http://msdn.microsoft.com/workshop/author/filter/reference/reference.asp
     */

    this.filters        = new Array();

    this.filters['begin']    = "Blinds(duration=.15,bands=1,direction=down)";
    this.filters['left']     = "Blinds(duration=.15,bands=1,direction=right)";
    this.filters['right']    = "Blinds(duration=.15,bands=1,direction=left)";
    this.filters['return']   = "Blinds(duration=.15,bands=1,direction=up)";

    /* ---------------------------------------------------------------------- */

    return this;

}

/**
 * _first - Navigate to the first screen.
 */

function _first() {

    this.navto( this.idx_first );

}

/**
 * _last - Navigate to the last screen.
 */

function _last() {

    this.navto( this.idx_last );

}

/**
 * _prev - Navigate to the previous screen.
 */

function _prev() {

    this.navto( this.idx_current - 1 );

}

/**
 * _next - Navigate to the next screen.
 */

function _next() {

    this.navto( this.idx_current + 1 );

}

/**
 * _jump - Navigate to the screen specified by ID.
 *
 * @param   screen_id <code>String</code> Screen ID
 */

function _jump( screen_id ) {

    for( var idx in this.data ) {

        if( this.data[idx].screen_id == screen_id ) {

            this.navto( idx );

            break;

        }

    }

}

/**
 * _reset - Get back to the first screen, but don't display it.
 */

function _reset() {

    this.idx_current    = this.idx_first;
    this.idx_from       = this.idx_current;
    this.screen         = this.data[this.idx_current];

    this.motion = "begin"; /* default state */

}

/**
 * _navto - Navigate to the screen specified by index.
 *
 * @param   index <code>int</code> Array index (zero based)
 */

function _navto( index ) {

    if( index < this.idx_first )    index = this.idx_first;
    if( index > this.idx_last )     index = this.idx_last;

    this.motion = ( index > this.idx_current )  ? "right" :
                  ( index < this.idx_current )  ? "left"  :
                                                  "return";

    this.idx_from       = this.idx_current;
    this.idx_current    = index;
    this.screen         = this.data[index];

    this.show();

}

/**
 * _show - Show the current screen.
 */

function _show() {

    this.transition();

    if( this.target_doc ) {

      if( this.use_filters ) {

        this.filtering = applyFilters( this.frame, this.filters[this.motion] );

      }

      if( this.target_doc.open( "text/html", "replace" ) ) {

          if( this.screen ) {
            
            trace( "<span style='color: blue'>[" + this.idx_current + "]"
                + " " + this.screen.screen_id + "</span>" );

            this.target_doc.write( this.screen.html );

          } else {

            trace( "<span style='color: red'>[" + this.idx_current + "]"
                + " screen missing</span>" );

            this.target_doc.write( 
                "<a style=\"position: absolute; top: 250px; left: 250px;\""
                    + "href=\"javascript:history.go(-1)\">Screen Missing</a>" );

          }

          this.target_doc.close();

      }

      if( this.filtering ) {

        trace( " filter: " + this.motion + "(" + this.filters[this.motion] + ")" );

        this.frame.onfilterchange = this.onDisplay;

        playFilters( this.frame );

      }

    }

    this.motion = "return";

}

/**
 * _onDisplay - Complete the 'show' concept.
 *
 * Separted so that it can be called from either the target documents onload
 * method, or by the asynchronous onfilterchange event.
 */

function _onDisplay() {
  
  if( this.filtering && this.tagName != "IFRAME" ) {

    return;

  }

  var win = typeof( this.target_win ) == "undefined" ?
    getContentWindow( this.id ) : this.target_win;

  try {

    trace( " " + typeof( win.begin ) + " begin()" );

    win.begin();

  } catch( err ) {

    trace( err );

  }

  this.filtering = false;

}

/**
 * _transition - Called when transitioning to another screen.
 *
 * Also triggered when a custom function is called.
 *
 * There is not a default "onTransition" method.  Provide this to the constructor
 * in the array of custom functions as an element named "onTransition".
 */

function _transition() {

    if( this.target_win ) {

        if( typeof( this.target_win.end ) == "function" ) {

          trace( " " + typeof( this.target_win.end ) + " end()" );

          this.target_win.end();

        }

    }

    if( typeof( this.onTransition ) == "function" ) {

        this.onTransition();

    }

}
/* Copyright 2007 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

/*------------------------------------------------------------------------------
 * Request - HTTP Request object
 * var post = new Request()
 * var post = new Request(uri)
 *----------------------------------------------------------------------------*/

function Request(uri) {
  this.uri        = uri;
  this.parameters = {values: new Array()};
  this.response   = undefined;
}

/* ------------------------------------------------------------------------------
 * addParameter - Add a CGI parameter
 * --------------------------------------------------------------------------- */

Request.prototype.addParameter = function(key, value) {
  this.parameters[key] = value;
}

/* ------------------------------------------------------------------------------
 * addValues - Add post value parameters from HTML elements
 * addValues id1, [id2, ...]
 * --------------------------------------------------------------------------- */

Request.prototype.addValues = function() {
  for (var i = 0; i < arguments.length; i++) {
    if (arguments[i] instanceof Array) {
      for (var j = 0; j < arguments[i].length; j++) {
        this.addValue(arguments[i][j]);
      }
    } else {
      this.addValue(arguments[i]);
    }
  }
};

/* ------------------------------------------------------------------------------
 * addValue - Add a post value parameter from an HTML element
 * addValue id
 * --------------------------------------------------------------------------- */

Request.prototype.addValue = function(id) {
  var field = getField(id);
  if (field) {
    this.parameters.values[field.name] = field.value;
  }
};

/* ------------------------------------------------------------------------------
 * submit - Submit the post
 * submit
 * --------------------------------------------------------------------------- */

Request.prototype.submit = function() {
  this.response = this.parameters['return'] == 'js'
    ? fetchObject(this.uri, this.parameters)
    : fetch(this.uri, this.parameters);
  return this.response;
};
/* Tree.js - JavaScript Object: Tree. */
/* Copyright 2006 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

/**
 * Tree - Construct an object from an XMLHttpRequest response.
 * @param doc document object
 */

function Tree(doc) {

  if (doc) {
    var node = doc.firstChild;
    while (node) {

      /* key */
      var key = null;
      if (node.attributes) {
        for (var i = 0; i < node.attributes.length; i++) {
          if( node.attributes[i].nodeName == 'id' ) {
            key = node.attributes[i].nodeValue;
            break;
          }
        }
      }
      if (!key) key = node.nodeName;

      /* value */
      if (null != node.nodeValue) {
        this[key] = node.nodeValue;
      } else {
        if (node.childNodes && node.childNodes.length == 1) {
          var onlyChild = node.firstChild;
          if ((onlyChild.nodeName == '#text') ||
             (onlyChild.nodeName == '#cdata-section')) {
            this[key] = onlyChild.nodeValue;
          } else {
            this[key] = new Tree(node);
          }
        } else {
          this[key] = new Tree(node);
        }
      }

      node = node.nextSibling;
    }
  }

  return this;
}
/* Copyright 2007 Livesite Networks, LLC. All rights reserved. */
/* Written by: Ryan Gies */

/* ------------------------------------------------------------------------------
 * Widget - A Hub web resource which may contain HTML, JavaScript, and  
 * Cascading Style Sheets.
 *
 *  var dlg = new Widget('/mydialog.html');
 *  dlg.attach(getBody());
 *
 * This object extends Request
 * --------------------------------------------------------------------------- */

function Widget(uri) {
  this.request = new Request(uri);
  this.request.addParameter('return', 'js');
}

Widget.prototype.fetch = function() {
  var resp = this.request.submit();
  this.innerHTML = resp.value;
  if (resp.head) {
    if (resp.head.links) {
      if (resp.head.links.js) {
        for(var i=0; i < resp.head.links.js.length; i++) {
          includeScriptURI(resp.head.links.js[i]);
        }
      }
      if (resp.head.links.css) {
        for(var i=0; i < resp.head.links.css.length; i++) {
          includeStyleURI(resp.head.links.css[i]);
        }
      }
    }
    if (resp.head.css) {
      includeStyle(resp.head.css);
    }
    if (resp.head.js) {
      includeScript(resp.head.js);
    }
  }
};
/*
 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
 * in FIPS PUB 180-1
 * Version 2.1a Copyright Paul Johnston 2000 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for details.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}

/*
 * Perform a simple self-test to see if the VM is working
 */
function sha1_vm_test()
{
  return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
}

/*
 * Calculate the SHA-1 of an array of big-endian words, and a bit length
 */
function core_sha1(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << (24 - len % 32);
  x[((len + 64 >> 9) << 4) + 15] = len;

  var w = Array(80);
  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;
  var e = -1009589776;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;
    var olde = e;

    for(var j = 0; j < 80; j++)
    {
      if(j < 16) w[j] = x[i + j];
      else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
      var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
                       safe_add(safe_add(e, w[j]), sha1_kt(j)));
      e = d;
      d = c;
      c = rol(b, 30);
      b = a;
      a = t;
    }

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
    e = safe_add(e, olde);
  }
  return Array(a, b, c, d, e);

}

/*
 * Perform the appropriate triplet combination function for the current
 * iteration
 */
function sha1_ft(t, b, c, d)
{
  if(t < 20) return (b & c) | ((~b) & d);
  if(t < 40) return b ^ c ^ d;
  if(t < 60) return (b & c) | (b & d) | (c & d);
  return b ^ c ^ d;
}

/*
 * Determine the appropriate additive constant for the current iteration
 */
function sha1_kt(t)
{
  return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
         (t < 60) ? -1894007588 : -899497514;
}

/*
 * Calculate the HMAC-SHA1 of a key and some data
 */
function core_hmac_sha1(key, data)
{
  var bkey = str2binb(key);
  if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
  return core_sha1(opad.concat(hash), 512 + 160);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Convert an 8-bit or 16-bit string to an array of big-endian words
 * In 8-bit function, characters >255 have their hi-byte silently ignored.
 */
function str2binb(str)
{
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
  return bin;
}

/*
 * Convert an array of big-endian words to a string
 */
function binb2str(bin)
{
  var str = "";
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < bin.length * 32; i += chrsz)
    str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
  return str;
}

/*
 * Convert an array of big-endian words to a hex string.
 */
function binb2hex(binarray)
{
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i++)
  {
    str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
           hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8  )) & 0xF);
  }
  return str;
}

/*
 * Convert an array of big-endian words to a base-64 string
 */
function binb2b64(binarray)
{
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i += 3)
  {
    var triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16)
                | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
                |  ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
    }
  }
  return str;
}
