/*  Prototype JavaScript framework, version 1.4.0
 *  (c) 2005 Sam Stephenson <sam@conio.net>
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://prototype.conio.net/
 *
/*--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.4.0',
  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',

  emptyFunction: function() {},
  K: function(x) {return x}
}

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

var Abstract = new Object();

Object.extend = function(destination, source) {
  for (property in source) {
    destination[property] = source[property];
  }
  return destination;
}

Object.inspect = function(object) {
  try {
    if (object == undefined) return 'undefined';
    if (object == null) return 'null';
    return object.inspect ? object.inspect() : object.toString();
  } catch (e) {
    if (e instanceof RangeError) return '...';
    throw e;
  }
}

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

Function.prototype.bindAsEventListener = function(object) {
  var __method = this;
  return function(event) {
    return __method.call(object, event || window.event);
  }
}

Object.extend(Number.prototype, {
  toColorPart: function() {
    var digits = this.toString(16);
    if (this < 16) return '0' + digits;
    return digits;
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  }
});

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0; i < arguments.length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }

    return returnValue;
  }
}

/*--------------------------------------------------------------------------*/

var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.callback();
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
}

/*--------------------------------------------------------------------------*/

function $() {
  var elements = new Array();

  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);

    if (arguments.length == 1)
      return element;

    elements.push(element);
  }

  return elements;
}
Object.extend(String.prototype, {
  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  stripScripts: function() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(eval);
  },

  escapeHTML: function() {
    var div = document.createElement('div');
    var text = document.createTextNode(this);
    div.appendChild(text);
    return div.innerHTML;
  },

  unescapeHTML: function() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
  },

  toQueryParams: function() {
    var pairs = this.match(/^\??(.*)$/)[1].split('&');
    return pairs.inject({}, function(params, pairString) {
      var pair = pairString.split('=');
      params[pair[0]] = pair[1];
      return params;
    });
  },

  toArray: function() {
    return this.split('');
  },

  camelize: function() {
    var oStringList = this.split('-');
    if (oStringList.length == 1) return oStringList[0];

    var camelizedString = this.indexOf('-') == 0
      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
      : oStringList[0];

    for (var i = 1, len = oStringList.length; i < len; i++) {
      var s = oStringList[i];
      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
    }

    return camelizedString;
  },

  inspect: function() {
    return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
  }
});

String.prototype.parseQuery = String.prototype.toQueryParams;

var $break    = new Object();
var $continue = new Object();

var Enumerable = {
  each: function(iterator) {
    var index = 0;
    try {
      this._each(function(value) {
        try {
          iterator(value, index++);
        } catch (e) {
          if (e != $continue) throw e;
        }
      });
    } catch (e) {
      if (e != $break) throw e;
    }
  },

  all: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      result = result && !!(iterator || Prototype.K)(value, index);
      if (!result) throw $break;
    });
    return result;
  },

  any: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      if (result = !!(iterator || Prototype.K)(value, index))
        throw $break;
    });
    return result;
  },

  collect: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      results.push(iterator(value, index));
    });
    return results;
  },

  detect: function (iterator) {
    var result;
    this.each(function(value, index) {
      if (iterator(value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  },

  findAll: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (iterator(value, index))
        results.push(value);
    });
    return results;
  },

  grep: function(pattern, iterator) {
    var results = [];
    this.each(function(value, index) {
      var stringValue = value.toString();
      if (stringValue.match(pattern))
        results.push((iterator || Prototype.K)(value, index));
    })
    return results;
  },

  include: function(object) {
    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  },

  inject: function(memo, iterator) {
    this.each(function(value, index) {
      memo = iterator(memo, value, index);
    });
    return memo;
  },

  invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.collect(function(value) {
      return value[method].apply(value, args);
    });
  },

  max: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (value >= (result || value))
        result = value;
    });
    return result;
  },

  min: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (value <= (result || value))
        result = value;
    });
    return result;
  },

  partition: function(iterator) {
    var trues = [], falses = [];
    this.each(function(value, index) {
      ((iterator || Prototype.K)(value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  },

  pluck: function(property) {
    var results = [];
    this.each(function(value, index) {
      results.push(value[property]);
    });
    return results;
  },

  reject: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (!iterator(value, index))
        results.push(value);
    });
    return results;
  },

  sortBy: function(iterator) {
    return this.collect(function(value, index) {
      return {value: value, criteria: iterator(value, index)};
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck('value');
  },

  toArray: function() {
    return this.collect(Prototype.K);
  },

  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (typeof args.last() == 'function')
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      iterator(value = collections.pluck(index));
      return value;
    });
  },

  inspect: function() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }
}

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0; i < iterable.length; i++)
      results.push(iterable[i]);
    return results;
  }
}

Object.extend(Array.prototype, Enumerable);

Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0; i < this.length; i++)
      iterator(this[i]);
  },

  clear: function() {
    this.length = 0;
    return this;
  },

  first: function() {
    return this[0];
  },

  last: function() {
    return this[this.length - 1];
  },

  compact: function() {
    return this.select(function(value) {
      return value != undefined || value != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(value.constructor == Array ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  indexOf: function(object) {
    for (var i = 0; i < this.length; i++)
      if (this[i] == object) return i;
    return -1;
  },

  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

  shift: function() {
    var result = this[0];
    for (var i = 0; i < this.length - 1; i++)
      this[i] = this[i + 1];
    this.length--;
    return result;
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  }
});
var Hash = {
  _each: function(iterator) {
    for (key in this) {
      var value = this[key];
      if (typeof value == 'function') continue;

      var pair = [key, value];
      pair.key = key;
      pair.value = value;
      iterator(pair);
    }
  },

  keys: function() {
    return this.pluck('key');
  },

  values: function() {
    return this.pluck('value');
  },

  merge: function(hash) {
    return $H(hash).inject($H(this), function(mergedHash, pair) {
      mergedHash[pair.key] = pair.value;
      return mergedHash;
    });
  },

  toQueryString: function() {
    return this.map(function(pair) {
      return pair.map(encodeURIComponent).join('=');
    }).join('&');
  },

  inspect: function() {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map(Object.inspect).join(': ');
    }).join(', ') + '}>';
  }
}

function $H(object) {
  var hash = Object.extend({}, object || {});
  Object.extend(hash, Enumerable);
  Object.extend(hash, Hash);
  return hash;
}
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    do {
      iterator(value);
      value = value.succ();
    } while (this.include(value));
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $R = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
}

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
      function() {return new XMLHttpRequest()}
    ) || false;
  },

  activeRequestCount: 0
}

Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responderToAdd) {
    if (!this.include(responderToAdd))
      this.responders.push(responderToAdd);
  },

  unregister: function(responderToRemove) {
    this.responders = this.responders.without(responderToRemove);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (responder[callback] && typeof responder[callback] == 'function') {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) {}
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate: function() {
    Ajax.activeRequestCount++;
  },

  onComplete: function() {
    Ajax.activeRequestCount--;
  }
});

Ajax.Base = function() {};
Ajax.Base.prototype = {
  setOptions: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      parameters:   ''
    }
    Object.extend(this.options, options || {});
  },

  responseIsSuccess: function() {
    return this.transport.status == undefined
        || this.transport.status == 0
        || (this.transport.status >= 200 && this.transport.status < 300);
  },

  responseIsFailure: function() {
    return !this.responseIsSuccess();
  }
}

Ajax.Request = Class.create();
Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
    this.request(url);
  },

  request: function(url) {
    var parameters = this.options.parameters || '';
    if (parameters.length > 0) parameters += '&_=';

    try {
      this.url = url;
      if (this.options.method == 'get' && parameters.length > 0)
        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;

      Ajax.Responders.dispatch('onCreate', this, this.transport);

      this.transport.open(this.options.method, this.url,
        this.options.asynchronous);

      if (this.options.asynchronous) {
        this.transport.onreadystatechange = this.onStateChange.bind(this);
        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
      }

      this.setRequestHeaders();

      var body = this.options.postBody ? this.options.postBody : parameters;
      this.transport.send(this.options.method == 'post' ? body : null);

    } catch (e) {
      this.dispatchException(e);
    }
  },

  setRequestHeaders: function() {
    var requestHeaders =
      ['X-Requested-With', 'XMLHttpRequest',
       'X-Prototype-Version', Prototype.Version];

    if (this.options.method == 'post') {
      requestHeaders.push('Content-type',
        'application/x-www-form-urlencoded');

      /* Force "Connection: close" for Mozilla browsers to work around
       * a bug where XMLHttpReqeuest sends an incorrect Content-length
       * header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType)
        requestHeaders.push('Connection', 'close');
    }

    if (this.options.requestHeaders)
      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);

    for (var i = 0; i < requestHeaders.length; i += 2)
      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState != 1)
      this.respondToReadyState(this.transport.readyState);
  },

  header: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) {}
  },

  evalJSON: function() {
    try {
      return eval(this.header('X-JSON'));
    } catch (e) {}
  },

  evalResponse: function() {
    try {
      return eval(this.transport.responseText);
    } catch (e) {
      this.dispatchException(e);
    }
  },

  respondToReadyState: function(readyState) {
    var event = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();

    if (event == 'Complete') {
      try {
        (this.options['on' + this.transport.status]
         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }

      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
        this.evalResponse();
    }

    try {
      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
      Ajax.Responders.dispatch('on' + event, this, transport, json);
    } catch (e) {
      this.dispatchException(e);
    }

    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
    if (event == 'Complete')
      this.transport.onreadystatechange = Prototype.emptyFunction;
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Updater = Class.create();

Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  initialize: function(container, url, options) {
    this.containers = {
      success: container.success ? $(container.success) : $(container),
      failure: container.failure ? $(container.failure) :
        (container.success ? null : $(container))
    }

    this.transport = Ajax.getTransport();
    this.setOptions(options);

    var onComplete = this.options.onComplete || Prototype.emptyFunction;
    this.options.onComplete = (function(transport, object) {
      this.updateContent();
      onComplete(transport, object);
    }).bind(this);

    this.request(url);
  },

  updateContent: function() {
    var receiver = this.responseIsSuccess() ?
      this.containers.success : this.containers.failure;
    var response = this.transport.responseText;

    if (!this.options.evalScripts)
      response = response.stripScripts();

    if (receiver) {
      if (this.options.insertion) {
        new this.options.insertion(receiver, response);
      } else {
        Element.update(receiver, response);
      }
    }

    if (this.responseIsSuccess()) {
      if (this.onComplete)
        setTimeout(this.onComplete.bind(this), 10);
    }
  }
});

Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(container, url, options) {
    this.setOptions(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = {};
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(request) {
    if (this.options.decay) {
      this.decay = (request.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = request.responseText;
    }
    this.timer = setTimeout(this.onTimerEvent.bind(this),
      this.decay * this.frequency * 1000);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
document.getElementsByClassName = function(className, parentElement) {
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
  return $A(children).inject([], function(elements, child) {
    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
      elements.push(child);
    return elements;
  });
}

/*--------------------------------------------------------------------------*/

if (!window.Element) {
  var Element = new Object();
}

Object.extend(Element, {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      Element[Element.visible(element) ? 'hide' : 'show'](element);
    }
  },

  hide: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      element.style.display = 'none';
    }
  },

  show: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      element.style.display = '';
    }
  },

  remove: function(element) {
    element = $(element);
    element.parentNode.removeChild(element);
  },

  update: function(element, html) {
    $(element).innerHTML = html.stripScripts();
    setTimeout(function() {html.evalScripts()}, 10);
  },

  getHeight: function(element) {
    element = $(element);
    return element.offsetHeight;
  },

  classNames: function(element) {
    return new Element.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).include(className);
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).add(className);
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).remove(className);
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    for (var i = 0; i < element.childNodes.length; i++) {
      var node = element.childNodes[i];
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        Element.remove(node);
    }
  },

  empty: function(element) {
    return $(element).innerHTML.match(/^\s*$/);
  },

  scrollTo: function(element) {
    element = $(element);
    var x = element.x ? element.x : element.offsetLeft,
        y = element.y ? element.y : element.offsetTop;
    window.scrollTo(x, y);
  },

  getStyle: function(element, style) {
    element = $(element);
    var value = element.style[style.camelize()];
    if (!value) {
      if (document.defaultView && document.defaultView.getComputedStyle) {
        var css = document.defaultView.getComputedStyle(element, null);
        value = css ? css.getPropertyValue(style) : null;
      } else if (element.currentStyle) {
        value = element.currentStyle[style.camelize()];
      }
    }

    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
      if (Element.getStyle(element, 'position') == 'static') value = 'auto';

    return value == 'auto' ? null : value;
  },

  setStyle: function(element, style) {
    element = $(element);
    for (name in style)
      element.style[name.camelize()] = style[name];
  },

  getDimensions: function(element) {
    element = $(element);
    if (Element.getStyle(element, 'display') != 'none')
      return {width: element.offsetWidth, height: element.offsetHeight};

    // All *Width and *Height properties give 0 on elements with display none,
    // so enable the element temporarily
    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = '';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = 'none';
    els.position = originalPosition;
    els.visibility = originalVisibility;
    return {width: originalWidth, height: originalHeight};
  },

  makePositioned: function(element) {
    element = $(element);
    var pos = Element.getStyle(element, 'position');
    if (pos == 'static' || !pos) {
      element._madePositioned = true;
      element.style.position = 'relative';
      // Opera returns the offset relative to the positioning context, when an
      // element is position relative but top and left have not been defined
      if (window.opera) {
        element.style.top = 0;
        element.style.left = 0;
      }
    }
  },

  undoPositioned: function(element) {
    element = $(element);
    if (element._madePositioned) {
      element._madePositioned = undefined;
      element.style.position =
        element.style.top =
        element.style.left =
        element.style.bottom =
        element.style.right = '';
    }
  },

  makeClipping: function(element) {
    element = $(element);
    if (element._overflow) return;
    element._overflow = element.style.overflow;
    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
      element.style.overflow = 'hidden';
  },

  undoClipping: function(element) {
    element = $(element);
    if (element._overflow) return;
    element.style.overflow = element._overflow;
    element._overflow = undefined;
  }
});

var Toggle = new Object();
Toggle.display = Element.toggle;

/*--------------------------------------------------------------------------*/

Abstract.Insertion = function(adjacency) {
  this.adjacency = adjacency;
}

Abstract.Insertion.prototype = {
  initialize: function(element, content) {
    this.element = $(element);
    this.content = content.stripScripts();

    if (this.adjacency && this.element.insertAdjacentHTML) {
      try {
        this.element.insertAdjacentHTML(this.adjacency, this.content);
      } catch (e) {
        if (this.element.tagName.toLowerCase() == 'tbody') {
          this.insertContent(this.contentFromAnonymousTable());
        } else {
          throw e;
        }
      }
    } else {
      this.range = this.element.ownerDocument.createRange();
      if (this.initializeRange) this.initializeRange();
      this.insertContent([this.range.createContextualFragment(this.content)]);
    }

    setTimeout(function() {content.evalScripts()}, 10);
  },

  contentFromAnonymousTable: function() {
    var div = document.createElement('div');
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    return $A(div.childNodes[0].childNodes[0].childNodes);
  }
}

var Insertion = new Object();

Insertion.Before = Class.create();
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
  initializeRange: function() {
    this.range.setStartBefore(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment, this.element);
    }).bind(this));
  }
});

Insertion.Top = Class.create();
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(true);
  },

  insertContent: function(fragments) {
    fragments.reverse(false).each((function(fragment) {
      this.element.insertBefore(fragment, this.element.firstChild);
    }).bind(this));
  }
});

Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.appendChild(fragment);
    }).bind(this));
  }
});

Insertion.After = Class.create();
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
  initializeRange: function() {
    this.range.setStartAfter(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment,
        this.element.nextSibling);
    }).bind(this));
  }
});

/*--------------------------------------------------------------------------*/

Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $(element);
  },

  _each: function(iterator) {
    this.element.className.split(/\s+/).select(function(name) {
      return name.length > 0;
    })._each(iterator);
  },

  set: function(className) {
    this.element.className = className;
  },

  add: function(classNameToAdd) {
    if (this.include(classNameToAdd)) return;
    this.set(this.toArray().concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set(this.select(function(className) {
      return className != classNameToRemove;
    }).join(' '));
  },

  toString: function() {
    return this.toArray().join(' ');
  }
}

Object.extend(Element.ClassNames.prototype, Enumerable);
var Field = {
  clear: function() {
    for (var i = 0; i < arguments.length; i++)
      $(arguments[i]).value = '';
  },

  focus: function(element) {
    $(element).focus();
  },

  present: function() {
    for (var i = 0; i < arguments.length; i++)
      if ($(arguments[i]).value == '') return false;
    return true;
  },

  select: function(element) {
    $(element).select();
  },

  activate: function(element) {
    element = $(element);
    element.focus();
    if (element.select)
      element.select();
  }
}

/*--------------------------------------------------------------------------*/

var Form = {
  serialize: function(form) {
    var elements = Form.getElements($(form));
    var queryComponents = new Array();

    for (var i = 0; i < elements.length; i++) {
      var queryComponent = Form.Element.serialize(elements[i]);
      if (queryComponent)
        queryComponents.push(queryComponent);
    }

    return queryComponents.join('&');
  },

  getElements: function(form) {
    form = $(form);
    var elements = new Array();

    for (tagName in Form.Element.Serializers) {
      var tagElements = form.getElementsByTagName(tagName);
      for (var j = 0; j < tagElements.length; j++)
        elements.push(tagElements[j]);
    }
    return elements;
  },

  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name)
      return inputs;

    var matchingInputs = new Array();
    for (var i = 0; i < inputs.length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) ||
          (name && input.name != name))
        continue;
      matchingInputs.push(input);
    }

    return matchingInputs;
  },

  disable: function(form) {
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.blur();
      element.disabled = 'true';
    }
  },

  enable: function(form) {
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.disabled = '';
    }
  },

  findFirstElement: function(form) {
    return Form.getElements(form).find(function(element) {
      return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    Field.activate(Form.findFirstElement(form));
  },

  reset: function(form) {
    $(form).reset();
  }
}

Form.Element = {
  serialize: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);

    if (parameter) {
      var key = encodeURIComponent(parameter[0]);
      if (key.length == 0) return;

      if (parameter[1].constructor != Array)
        parameter[1] = [parameter[1]];

      return parameter[1].map(function(value) {
        return key + '=' + encodeURIComponent(value);
      }).join('&');
    }
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);

    if (parameter)
      return parameter[1];
  }
}

Form.Element.Serializers = {
  input: function(element) {
    switch (element.type.toLowerCase()) {
      case 'submit':
      case 'hidden':
      case 'password':
      case 'text':
        return Form.Element.Serializers.textarea(element);
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element);
    }
    return false;
  },

  inputSelector: function(element) {
    if (element.checked)
      return [element.name, element.value];
  },

  textarea: function(element) {
    return [element.name, element.value];
  },

  select: function(element) {
    return Form.Element.Serializers[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
  },

  selectOne: function(element) {
    var value = '', opt, index = element.selectedIndex;
    if (index >= 0) {
      opt = element.options[index];
      value = opt.value;
      if (!value && !('value' in opt))
        value = opt.text;
    }
    return [element.name, value];
  },

  selectMany: function(element) {
    var value = new Array();
    for (var i = 0; i < element.length; i++) {
      var opt = element.options[i];
      if (opt.selected) {
        var optValue = opt.value;
        if (!optValue && !('value' in opt))
          optValue = opt.text;
        value.push(optValue);
      }
    }
    return [element.name, value];
  }
}

/*--------------------------------------------------------------------------*/

var $F = Form.Element.getValue;

/*--------------------------------------------------------------------------*/

Abstract.TimedObserver = function() {}
Abstract.TimedObserver.prototype = {
  initialize: function(element, frequency, callback) {
    this.frequency = frequency;
    this.element   = $(element);
    this.callback  = callback;

    this.lastValue = this.getValue();
    this.registerCallback();
  },

  registerCallback: function() {
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  onTimerEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
}

Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.Observer = Class.create();
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});

/*--------------------------------------------------------------------------*/

Abstract.EventObserver = function() {}
Abstract.EventObserver.prototype = {
  initialize: function(element, callback) {
    this.element  = $(element);
    this.callback = callback;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {
    var elements = Form.getElements(this.element);
    for (var i = 0; i < elements.length; i++)
      this.registerCallback(elements[i]);
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        case 'password':
        case 'text':
        case 'textarea':
        case 'select-one':
        case 'select-multiple':
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
}

Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
if (!window.Event) {
  var Event = new Object();
}

Object.extend(Event, {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,

  element: function(event) {
    return event.target || event.srcElement;
  },

  isLeftClick: function(event) {
    return (((event.which) && (event.which == 1)) ||
            ((event.button) && (event.button == 1)));
  },

  pointerX: function(event) {
    return event.pageX || (event.clientX +
      (document.documentElement.scrollLeft || document.body.scrollLeft));
  },

  pointerY: function(event) {
    return event.pageY || (event.clientY +
      (document.documentElement.scrollTop || document.body.scrollTop));
  },

  stop: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      event.returnValue = false;
      event.cancelBubble = true;
    }
  },

  // find the first node with the given tagName, starting from the
  // node the event was triggered on; traverses the DOM upwards
  findElement: function(event, tagName) {
    var element = Event.element(event);
    while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
      element = element.parentNode;
    return element;
  },

  observers: false,

  _observeAndCache: function(element, name, observer, useCapture) {
    if (!this.observers) this.observers = [];
    if (element.addEventListener) {
      this.observers.push([element, name, observer, useCapture]);
      element.addEventListener(name, observer, useCapture);
    } else if (element.attachEvent) {
      this.observers.push([element, name, observer, useCapture]);
      element.attachEvent('on' + name, observer);
    }
  },

  unloadCache: function() {
    if (!Event.observers) return;
    for (var i = 0; i < Event.observers.length; i++) {
      Event.stopObserving.apply(this, Event.observers[i]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    var element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.attachEvent))
      name = 'keydown';

    this._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    var element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.detachEvent))
      name = 'keydown';

    if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
      element.detachEvent('on' + name, observer);
    }
  }
});

/* prevent memory leaks in IE */
Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
  // set to true if needed, warning: firefox performance problems
  // NOT neeeded for page scrolling, only if draggable contained in
  // scrollable elements
  includeScrollOffsets: false,

  // must be called before calling withinIncludingScrolloffset, every time the
  // page is scrolled
  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  realOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return [valueL, valueT];
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return [valueL, valueT];
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        p = Element.getStyle(element, 'position');
        if (p == 'relative' || p == 'absolute') break;
      }
    } while (element);
    return [valueL, valueT];
  },

  offsetParent: function(element) {
    if (element.offsetParent) return element.offsetParent;
    if (element == document.body) return element;

    while ((element = element.parentNode) && element != document.body)
      if (Element.getStyle(element, 'position') != 'static')
        return element;

    return document.body;
  },

  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = this.realOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = this.cumulativeOffset(element);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

  clone: function(source, target) {
    source = $(source);
    target = $(target);
    target.style.position = 'absolute';
    var offsets = this.cumulativeOffset(source);
    target.style.top    = offsets[1] + 'px';
    target.style.left   = offsets[0] + 'px';
    target.style.width  = source.offsetWidth + 'px';
    target.style.height = source.offsetHeight + 'px';
  },

  page: function(forElement) {
    var valueT = 0, valueL = 0;

    var element = forElement;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;

      // Safari fix
      if (element.offsetParent==document.body)
        if (Element.getStyle(element,'position')=='absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      valueT -= element.scrollTop  || 0;
      valueL -= element.scrollLeft || 0;
    } while (element = element.parentNode);

    return [valueL, valueT];
  },

  clone: function(source, target) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || {})

    // find page position of source
    source = $(source);
    var p = Position.page(source);

    // find coordinate system to use
    target = $(target);
    var delta = [0, 0];
    var parent = null;
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas
    if (Element.getStyle(target,'position') == 'absolute') {
      parent = Position.offsetParent(target);
      delta = Position.page(parent);
    }

    // correct by body offsets (fixes Safari)
    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

    // set position
    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
  },

  absolutize: function(element) {
    element = $(element);
    if (element.style.position == 'absolute') return;
    Position.prepare();

    var offsets = Position.positionedOffset(element);
    var top     = offsets[1];
    var left    = offsets[0];
    var width   = element.clientWidth;
    var height  = element.clientHeight;

    element._originalLeft   = left - parseFloat(element.style.left  || 0);
    element._originalTop    = top  - parseFloat(element.style.top || 0);
    element._originalWidth  = element.style.width;
    element._originalHeight = element.style.height;

    element.style.position = 'absolute';
    element.style.top    = top + 'px';;
    element.style.left   = left + 'px';;
    element.style.width  = width + 'px';;
    element.style.height = height + 'px';;
  },

  relativize: function(element) {
    element = $(element);
    if (element.style.position == 'relative') return;
    Position.prepare();

    element.style.position = 'relative';
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);

    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.height = element._originalHeight;
    element.style.width  = element._originalWidth;
  }
}

// Safari returns margins on body which is incorrect if the child is absolutely
// positioned.  For performance reasons, redefine Position.cumulativeOffset for
// KHTML/WebKit only.
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
  Position.cumulativeOffset = function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      if (element.offsetParent == document.body)
        if (Element.getStyle(element, 'position') == 'absolute') break;

      element = element.offsetParent;
    } while (element);

    return [valueL, valueT];
  }
}/******************************************
FLEX HISTORY OBJECT JS EMBED
*******************************************/
// $Revision: 1.49 $
// Vars
Vars = function(qStr) {
	this.numVars = 0;
	if(qStr != null) {
		var nameValue, name;
		var pairs = qStr.split('&');
		var pairLen = pairs.length;
		for(var i = 0; i < pairLen; i++) {
			var pair = pairs[i];
			if( (pair.indexOf('=')!= -1) && (pair.length > 3) ) {
				var nameValue = pair.split('=');
				var name = nameValue[0];
				var value = nameValue[1];
				if(this[name] == null && name.length > 0 && value.length > 0) { 
					this[name] = value;
					this.numVars++;
				}
			}
		} 
	}
}
Vars.prototype.toString = function(pre) {
	var result = '';
	if(pre == null) { pre = ''; }
	for(var i in this) {
		if(this[i] != null && typeof(this[i]) != 'object' && typeof(this[i]) != 'function' && i != 'numVars') {
			result += pre + i + '=' + this[i] + '&';
		}
	}
	if(result.length > 0) result = result.substr(0, result.length-1);
	return result;
}
function getSearch(wRef) {
	var searchStr = '';
	if(wRef.location.search.length > 1) {
		searchStr = new String(wRef.location.search);
		searchStr = searchStr.substring(1, searchStr.length);
	}
	return searchStr;
}
var lc_id = Math.floor(Math.random() * 100000).toString(16);
if (this != top)
{
	top.Vars = Vars;
	top.getSearch = getSearch;
	top.lc_id = lc_id;
}/**
 * SWFObject v1.4: Flash Player detection and embed - http://blog.deconcept.com/swfobject/
 *
 * SWFObject is (c) 2006 Geoff Stearns and is released under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * **SWFObject is the SWF embed script formarly known as FlashObject. The name was changed for
 *   legal reasons.
 */
if(typeof deconcept=="undefined"){var deconcept=new Object();}
if(typeof deconcept.util=="undefined"){deconcept.util=new Object();}
if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil=new Object();}
deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a,_b){
if(!document.createElement||!document.getElementById){return;}
this.DETECT_KEY=_b?_b:"detectflash";
this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY);
this.params=new Object();
this.variables=new Object();
this.attributes=new Array();
if(_1){this.setAttribute("swf",_1);}
if(id){this.setAttribute("id",id);}
if(w){this.setAttribute("width",w);}
if(h){this.setAttribute("height",h);}
if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));}
this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion(this.getAttribute("version"),_7);
if(c){this.addParam("bgcolor",c);}
var q=_8?_8:"high";
this.addParam("quality",q);
this.setAttribute("useExpressInstall",_7);
this.setAttribute("doExpressInstall",false);
var _d=(_9)?_9:window.location;
this.setAttribute("xiRedirectUrl",_d);
this.setAttribute("redirectUrl","");
if(_a){this.setAttribute("redirectUrl",_a);}};
deconcept.SWFObject.prototype={setAttribute:function(_e,_f){
this.attributes[_e]=_f;
},getAttribute:function(_10){
return this.attributes[_10];
},addParam:function(_11,_12){
this.params[_11]=_12;
},getParams:function(){
return this.params;
},addVariable:function(_13,_14){
this.variables[_13]=_14;
},getVariable:function(_15){
return this.variables[_15];
},getVariables:function(){
return this.variables;
},getVariablePairs:function(){
var _16=new Array();
var key;
var _18=this.getVariables();
for(key in _18){
_16.push(key+"="+_18[key]);}
return _16;
},getSWFHTML:function(){
var _19="";
if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){
if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","PlugIn");}
_19="<embed type=\"application/x-shockwave-flash\" src=\""+this.getAttribute("swf")+"\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\"";
_19+=" id=\""+this.getAttribute("id")+"\" name=\""+this.getAttribute("id")+"\" ";
var _1a=this.getParams();
for(var key in _1a){_19+=[key]+"=\""+_1a[key]+"\" ";}
var _1c=this.getVariablePairs().join("&");
if(_1c.length>0){_19+="flashvars=\""+_1c+"\"";}
_19+="/>";
}else{
if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");}
_19="<object id=\""+this.getAttribute("id")+"\" classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\""+this.getAttribute("width")+"\" height=\""+this.getAttribute("height")+"\">";
_19+="<param name=\"movie\" value=\""+this.getAttribute("swf")+"\" />";
var _1d=this.getParams();
for(var key in _1d){_19+="<param name=\""+key+"\" value=\""+_1d[key]+"\" />";}
var _1f=this.getVariablePairs().join("&");
if(_1f.length>0){_19+="<param name=\"flashvars\" value=\""+_1f+"\" />";}
_19+="</object>";}
return _19;
},write:function(_20){
if(this.getAttribute("useExpressInstall")){
var _21=new deconcept.PlayerVersion([6,0,65]);
if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){
this.setAttribute("doExpressInstall",true);
this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl")));
document.title=document.title.slice(0,47)+" - Flash Player Installation";
this.addVariable("MMdoctitle",document.title);}}
if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){
var n=(typeof _20=="string")?document.getElementById(_20):_20;
n.innerHTML=this.getSWFHTML();
return true;
}else{
if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}}
return false;}};
deconcept.SWFObjectUtil.getPlayerVersion=function(_23,_24){
var _25=new deconcept.PlayerVersion([0,0,0]);
if(navigator.plugins&&navigator.mimeTypes.length){
var x=navigator.plugins["Shockwave Flash"];
if(x&&x.description){_25=new deconcept.PlayerVersion(x.description.replace(/([a-z]|[A-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));}
}else{try{
var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
for(var i=3;axo!=null;i++){
axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+i);
_25=new deconcept.PlayerVersion([i,0,0]);}}
catch(e){}
if(_23&&_25.major>_23.major){return _25;}
if(!_23||((_23.minor!=0||_23.rev!=0)&&_25.major==_23.major)||_25.major!=6||_24){
try{_25=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}
catch(e){}}}
return _25;};
deconcept.PlayerVersion=function(_29){
this.major=parseInt(_29[0])!=null?parseInt(_29[0]):0;
this.minor=parseInt(_29[1])||0;
this.rev=parseInt(_29[2])||0;};
deconcept.PlayerVersion.prototype.versionIsValid=function(fv){
if(this.major<fv.major){return false;}
if(this.major>fv.major){return true;}
if(this.minor<fv.minor){return false;}
if(this.minor>fv.minor){return true;}
if(this.rev<fv.rev){return false;}return true;};
deconcept.util={getRequestParameter:function(_2b){
var q=document.location.search||document.location.hash;
if(q){
var _2d=q.indexOf(_2b+"=");
var _2e=(q.indexOf("&",_2d)>-1)?q.indexOf("&",_2d):q.length;
if(q.length>1&&_2d>-1){
return q.substring(q.indexOf("=",_2d)+1,_2e);
}}return "";}};
if(Array.prototype.push==null){
Array.prototype.push=function(_2f){
this[this.length]=_2f;
return this.length;};}
var getQueryParamValue=deconcept.util.getRequestParameter;
var FlashObject=deconcept.SWFObject; // for backwards compatibility
var SWFObject=deconcept.SWFObject;

/**
 * @fileoverview
 * This JavaScript library lets an application  control an embedded ArcWeb Explorer Flash 8 component in a Web page.
 * <p>
 * The following is the "hello world" example of ArcWeb Explorer using JavaScript:
 * <p>
 * <em>Note: If you copy and paste the code below, you must save it in a file that is accessible from a Web server. The code will not work if you launch it from the file system.</em>
 * <pre>
 * &lt;html&gt;
 * &lt;head&gt;
 *     &lt;title&gt;ArcWeb Explorer - Show Map&lt;/title&gt;
 *     &lt;script src="http://www.arcwebservices.com/awx/explorer-1.0.js" type="text/javascript"&gt;&lt;/script&gt;
 *     &lt;script type="text/javascript"&gt;
 *         function onBodyLoad()
 *         {
 *             AWUtils.insertMap("explorer", "mykey");
 *         }
 *             var myExplorer = new AWMap("explorer");
 *             var myLatLon = new AWLatLon(42.367044, -71.052742);
 *             myExplorer.centerAndScale(myLatLon, 10000);
 *     &lt;/script&gt;
 * &lt;/head&gt;
 * &lt;body onload="onBodyLoad()"&gt;
 * &lt;div align="center" id="explorer" style="width: 800px; height: 600px"&gt;ArcWebExplorer Flash Object&lt;/div&gt;
 * &lt;/body&gt;
 * &lt;/html&gt;
 * </pre>
 * @version 1.0
 */
/**
 * Construct a new AWMap object.
 *
 * @class AWMap is a class that encapsulates the functions to communicate with the ArcWeb Explorer Flash component. 
 */

var AWMap = Class.create();


/**
 * Static constant field representing the version number of this library.
 * @type String
 */
AWMap.Version = "1.0";
/**
 * Static constant field representing Navigation Widget
 * @type String
 */
AWMap.WIDGET_NAVIGATION = "NavigationWidget";
/**
 * Static constant field representing Find Widget
 * @type String
 */
AWMap.WIDGET_FIND = "findWidget";
/**
 * Static constant field representing Map Type Widget
 * @type String
 */
AWMap.WIDGET_MAPTYPES = "mapTypeWidget";
/**
 * Static constant field representing Upload Widget
 * @type String
 */
AWMap.WIDGET_IMPORTDATA = "uploadWidet";
/**
 * Static constant field representing Route Widget
 * @type String
 */
AWMap.WIDGET_DIRECTIONS = "routeWidget";
/**
 * Static constant field representing widgetBar Widget
 * @type String
 */
AWMap.WIDGET_WIDGETBAR = "widgetBarWidget";
/**
 * Static constant field representing Banner Widget
 * @type String
 */
AWMap.WIDGET_BANNER = "bannerWidget";

/**
 * Static constant field representing Legend Widget. This widget comes into play only with the ThematicGroupLayer.
 * @type String
 */
AWMap.WIDGET_LEGEND = "legendWidget";

/**
 * @constructor Create an AWMap instance using the divId of the embedded ArcWeb Explorer Flash object.
 * @param {String} divId the divId of the embedded ArcWeb Explorer Flash object.
 * @return An instance of AWMap.
 * @type AWMap
 *  &lt;b&gt; Field Details &lt;/b&gt;
 *  String: Version	
 *  Static constant field representing the version number of this library.
 *  &lt;\n&gt;	
 *  String: WIDGET_NAVIGATION
 *  Static constant field representing Navigation Widget. 
 *  &lt;\n&gt;	
 *  String: WIDGET_FIND
 *  Static constant field representing Find Widget. 
 *  &lt;\n&gt;	
 *  String: WIDGET_MAPTYPES
 *  Static constant field representing MapType Widget. 
 *  &lt;\n&gt;	
 *  String: WIDGET_IMPORTDATA
 *  Static constant field representing Upload Widget. 
 *  &lt;\n&gt;	
 *  String: WIDGET_DIRECTIONS
 *  Static constant field representing Route Widget. 
 *  &lt;\n&gt;
 *  String: WIDGET_WIDGETBAR
 *  Static constant field representing WidgetBar Widget. 
 *  &lt;\n&gt;
 *  String: WIDGET_BANNER
 *  Static constant field representing Banner Widget. 
 *  &lt;\n&gt;
 */

AWMap.prototype = {
/**
 * @ignore
 */
    initialize: function( divId )
    {
        if( typeof divId == "string" )
        {
            this.explorer = $(divId + "_Map");
        }
        else
        {
            this.explorer = divId;
        }
    },
/**
 * Center the map at a latitude/longitude location, and render it at a specific scale.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * myExplorer.centerAndScale( new AWLatLon(42.367044, -71.052742), 10000);
 * </pre>
 * @param {AWLatLon} latlon the latitude/longitude of the center of the map.
 * @param {Number} scale the rendering scale.  If you want to render the map at 1:10000, the scale value is 10000.
 */
    centerAndScale: function( latlon, scale )
    {
        var resp = this.explorer.centerAndScale(latlon, scale);
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * Recenter or pan the map to a new latitude/longitide location.
 * If the new location is within the extent of the map, the map animates to be centered at the new location;
 * otherwise, the map is refreshed and centered at the new location.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * myExplorer.centerAndScale( new AWLatLon(42.367044, -71.052742), 10000);
 * window.setTimeout(function() {
 *   myExplorer.recenterOrPanToLatLon(new AWLatLon(42.368044, -71.053742));
 * }, 3000);
 * </pre>
 * @param {AWLatLon} latlon the new latitude/longitude of the center of the map.
 */
    recenterOrPanToLatLon: function( latlon )
    {
        var resp = this.explorer.recenterOrPanToLatLon(latlon);
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * Add a marker to the map.  A marker is a point on the map with a defined style.
 * The style and behavior (mouseOver, mouseClick, mouseOut) of the marker is defined using the addMarkerStyle function.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * var latlon = new AWLatLon(42.36704409, -71.05274248);
 * myExplorer.centerAndScale(latlon, 10000);
 * myExplorer.addMarker( new AWMarker( "myId", new AWLatLon(42.367044, -71.052742)));
 * </pre>
 * @param {AWMarker|Array} marker the marker or array or markers to add to the map.
 */
    addMarker: function( marker )
    {
        var resp;
        resp = this.explorer.addMarker(marker);
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },

/**
 * Add a set of markers from a url.
 * <pre>
 * var myExplorer = new AWExplorer("map"); // here "map" is the ID of the flash object.
 * myExplorer.addMarkerFromGeorss( "http://earthquake.usgs.gov/recenteqsww/catalogs/eqs7day-M5.xml");
 * </pre>
 * @param {String} url the location of the markers.
 */
    addMarkerFromGeorss: function( url )
    {
        this.explorer.addMarkerFromGeorss(url);
    },
/**
 * Remove a marker or a set of markers from the map.
 * <pre>
 * var myExplorer = new AWMap("explorer");
 * myExplorer.removeMarker( "myMarkerId");
 * </pre>
 * @param {String|Array} id the marker identifier or an array of marker identifiers.
 */
    removeMarker: function( id )
    {
        if( id instanceof Array )
        {
            this.explorer.removeMarker(id);
        }
        else
        {
            this.explorer.removeMarker([id]);
        }
    },

/**
 * Add a location to the map. A Location is an address, a phone number, or an IP address with a defined style and behavior.
 * <pre>
 * function startUp()
 * {
 * 	var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * 	// Define and register a marker style.
 * 	var markerStyle = new AWImgMarkerStyle();
 * 	markerStyle.id = "myMarkerStyleId";
 * 	markerStyle.source = "http://www.arcwebservices.com/awx/images/id.png";
 * 	markerStyle.width = 16;
 * 	markerStyle.height = 16;
 * 	markerStyle.anchorX = 8;
 * 	markerStyle.anchorY = 8;
 * 	myExplorer.addMarkerStyle(markerStyle);
 * 	// Add the location of the city of Boston, MA as a marker on the map.
 * 	var location = new AWLocation();
 * 	location.location = "Boston, MA";
 * 	location.markerStyleId = markerStyle.myMarkerStyleId;
 * 	myExplorer.findLocation(location, "onFindLocation");
 * }
 * function onFindLocation(event)
 * {
 *  var myExplorer = new AWMap("explorer");
 *  myExplorer.recenterOrPanToLatLon(new AWLatLon(event.lat, event.lon));
 * }
 * </pre>
 * @param {AWLocation} location the location to add to the map.
 * @param {String} callback the name of the javascript function that is called when the location is added to the map.
 * The function prototype is 'function functionName( event)'
 * @see AWImgMarkerStyle
 */
    findLocation: function( location, callback )
    {
        this.explorer.findLocation(location, callback);
    },
/**
 * Add a polyline to the map. A polyline is defined by a set of points and has a thickness, a color, and a transparency factor.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * // Create a red, 3 pixel wide, 75% transparent polyline based on 2 points.
 * var polyline = new AWPolyline(
 * [ new AWLatLon(37.4419, -122.1419), new AWLatLon(37.4519, -122.1519) ],
 * 3,
 * 0xFF0000,
 * 75);
 * myExplorer.addPolyline(polyline);
 * </pre>
 * @param {AWPolyline} polyline the polyline to add to the map.
 */
    addPolyline: function( polyline )
    {
        var resp;
        if( polyline instanceof Array )
        {
            resp = this.explorer.addPolyline(polyline);
        }
        else
        {
            resp = this.explorer.addPolyline([polyline]);
        }
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * Remove a polyline from the map.
 * @param {String|Array} id is the ID of the polyline to be removed.
 */
    removePolyline: function( id )
    {
        if( id instanceof Array )
        {
            this.explorer.removePolyline(id);
        }
        else
        {
            this.explorer.removePolyline([id]);
        }
    },
/**
 * Add a polygon to the map. A polygon is defined by a set of points and has a fill color and a fill transparency.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * // Create a green filled, 50% transparent fill based on 3 points.
 * var polygon = new AWPolygon(
 * [ new AWLatLon(37.4419, -122.1419), new AWLatLon(37.4519, -122.1519), new AWLatLon(37.4519, -122.1619) ],
 * 0x00FF00,
 * 50);
 * myExplorer.addPolygon( polygon);
 * </pre>
 * @param {AWPolygon} polygon the polygon to add to the map.
 */
    addPolygon: function( polygon )
    {
        var resp;
        if( polygon instanceof Array )
        {
            resp = this.explorer.addPolygon(polygon);
        }
        else
        {
            resp = this.explorer.addPolygon([polygon]);
        }
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * Remove a polygon from the map.
 * @param {String|Array} id is the ID of the polygon to remove.
 */
    removePolygon: function( id )
    {
        if( id instanceof Array )
        {
            this.explorer.removePolygon(id);
        }
        else
        {
            this.explorer.removePolygon([id]);
        }
    },
/**
 * Add a marker style to the map.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 *
 * var markerStyle = new AWImgMarkerStyle();
 * markerStyle.id = "myMarkerStyleId";
 * markerStyle.source = "http://www.arcwebservices.com/awx/images/id.png";
 * markerStyle.width = 16;
 * markerStyle.height = 16;
 * markerStyle.anchorX = 8;
 * markerStyle.anchorY = 8;
 * myExplorer.addMarkerStyle(markerStyle);
 * </pre>
 * @param {AWImgMarkerStyle} markerStyle the marker style to register with the map.
 */
    addMarkerStyle: function( markerStyle )
    {
        var resp = this.explorer.addMarkerStyle(markerStyle);
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * Add a polyline style to the map.
 * @param {AWPolylineStyle} polylineStyle the polyline style to add to the map.
 */
    addPolylineStyle: function( polylineStyle )
    {
        this.explorer.addPolylineStyle(polylineStyle);
    },
/**
 * Add a polygon style to the map.
 * @param {AWPolygonStyle} polygonStyle the polygon style to add to the map.
 */
    addPolygonStyle: function( polygonStyle )
    {
        this.explorer.addPolygonStyle(polygonStyle);
    },
/**
 * Remove all markers from the map.
 */
    removeAllMarkers: function()
    {
        this.explorer.removeAllMarkers();
    },
/**
 * Remove all polylines from the map.
 */
    removeAllPolylines: function()
    {
        this.explorer.removeAllPolylines();
    },
/**
 * Remove all polygons from the map.
 */
    removeAllPolygons: function()
    {
        this.explorer.removeAllPolygons();
    },
/**
 * Hide all the map Widgets.
 */
    hideAllWidgets: function()
    {
        this.explorer.hideAllWidgets();
    },
/**
 * Show all the map Widgets.
 */
    showAllWidgets: function()
    {
        this.explorer.showAllWidgets();
    },
/**
 * Show a map Widget. Note that the Banner Widget does not move on x and y.
 * @param {String} widget the widget to be shown. Valid values are WIDGET_NAVIGATION, WIDGET_FIND, WIDGET_MAPTYPES, WIDGET_IMPORTDATA, WIDGET_DIRECTIONS, WIDGET_WIDGETBAR, WIDGET_BANNER, WIDGET_LEGEND.
 * @param {Number} x position in pixels from the top left corner.
 * @param {Number} y position in pixels from the top left corner.
 */
    showWidget: function( widget, x, y )
    {
        this.explorer.showWidget(widget, x, y);
    },
/**
 * Hide a map widget.
 * @param {String} widget to hide.
 */
    hideWidget: function( widget )
    {
        this.explorer.hideWidget(widget);
    },
/**
 * Get the current coordinates of the center of the map.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * var latlon = myExplorer.getLatLonCenter();
 * alert( latlon.lat+" "+latlon.lon);
 * </pre>
 * @return the center of the map coordinates.
 * @type AWLatLon
 */
    getLatLonCenter: function()
    {
        return this.explorer.getLatLonCenter();
    },
/**
 * Get the  min/max latitude/longitude values of the current map view.
 * An instance of AWLatLonExtent is returned, and it contains the properties <code>minLat, minLon, maxLat, maxLon</code>
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * var extent = myExplorer.getLatLonExtent();
 * alert( extent.minLat+" "+extent.minLon+" "+extent.maxLat+" "+extent.maxLon);
 * </pre>
 * @return the min/max lat/lon values of the current map.
 * @type AWLatLonExtent
 */
    getLatLonExtent: function()
    {
        return this.explorer.getLatLonExtent();
    },
/**
 * Set map extent
 * @param {AWLatLonExtent} latlonExtent The extent to be set.
 */
    setLatLonExtent : function( extent )
    {
        var resp = this.explorer.setLatLonExtent(extent);
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * Get the current scale of the map.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * alert( "the current map scale is 1:"+myExplorer.getScale());
 * </pre>
 * @return the current scale of the map.
 * @type Number
 */
    getScale: function()
    {
        return this.explorer.getScale();
    },
/**
 * Helper function to get the scale value for a given extent.
 * An application might have a set of points that needs to be displayed on the map, and the application wants to
 * ensure that all the points are visible on the map.  This function will come in handy given the extent of the points.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * var ext = someFuntionThatReturnsLatLonExtent();
 * var lat = (ext.minLat + ext.maxLat) / 2;
 * var lon = (ext.minLon + ext.maxLon) / 2;
 * var scale = myExplorer.getScaleForLatLonExtent( ext);
 * myExplorer.centerAndScale( new AWLatLon( lat,lon), scale);
 * </pre>
 * @param {AWLatLonExtent} latlonExtent the extent to evaluate.
 * @return the scale for an extent.
 * @type Number
 */
    getScaleForLatLonExtent: function( latlonExtent )
    {
        return this.explorer.getScaleForLatLonExtent(latlonExtent);
    },
/**
 * True makes the markers visible, false makes them invisible.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * // Place a marker on the map with identifier 'myId'
 * myExplorer.addMarker( new AWMarker( "myId", new AWLatLon(42.367044, -71.052742)));
 * ...
 * // Hide the marker with identifier 'myId'
 * myExplorer.setMarkerVisibility( "myId", false);
 * </pre>
 * @param {String} id the marker identifier.
 * @param {Boolean} visible true to make the marker visible, false otherwise.
 */
    setMarkerVisibility: function( id, visible )
    {
        this.explorer.setMarkerVisibility(id, visible);
    },
/**
 * Set the marker source (image) as over or out based on a key and value.
 * <pre>
 * </pre>
 * @param {String} id the marker identifier.
 * @param {String} out "out" to display the out source, "over" to display the over source.
 */
    setMarkerSource: function( id, out )
    {
        this.explorer.setMarkerSource(id, out);
    },
/**
 * Set the marker properties.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * // Place a marker on the map with user defined data containing a property named 'id' and whose value is 'bos'
 * myExplorer.addMarker( new AWMarker( "myId", new AWLatLon(42.367044, -71.052742), "markerStyleId", {desc:"some desc"}));
 * ...
 * //  set the new lat/lon properties of the marker to move it to a new location.
 * myExplorer.setMarkerProperties( "myId", {data.desc:"another desc"});
 *
 * </pre>
 * @param {String} id the marker identifier.
 * @param {Object} properties the properties to set.
 */
    setMarkerProperties: function( id, properties )
    {
        this.explorer.setMarkerProperties(id, properties);
    },
/**
 * Get a marker property.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * // Place a marker on the map with user defined data containing a property named 'id' and whose value is 'bos'
 * myExplorer.addMarker( new AWMarker( "myId", new AWLatLon(42.367044, -71.052742), "markerStyleId", {desc:"some desc"}));
 * ...
 * //  set the new lat/lon properties of the marker to move it to a new location.
 * myExplorer.setMarkerProperties( "myId", {data.desc:"another desc"});
 * myExplorer.getMarkerProperty("myId", "data");
 *
 * </pre>
 * @param {String} id the marker identifier.
 * @param {String} property to get.
 */
    getMarkerProperty: function( id, property )
    {
         return this.explorer.getMarkerProperty(id, property);
    },	
/**
 * Set the marker location.
 * <pre>
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * // Place a marker on the map with user defined data containing a property named 'id' and whose value is 'bos'
 * myExplorer.addMarker( new AWMarker( "myId", new AWLatLon(42.367044, -71.052742)));
 * ...
 * //  set the new lat/lon properties of the marker to move it to a new location.
 * myExplorer.setMarkerLatLon( "myId", 42.367144, -71.052842);
 *
 * </pre>
 * @param {String} id the marker identifier.
 * @param {Number} lat the latitude value.
 * @param {Number} lon the longitude value.
 */
    setMarkerLatLon: function( id, lat, lon )
    {
        var resp = this.explorer.setMarkerLatLon(id, lat, lon);
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * Function to call the mouse click handler associated with the marker.  The marker is located using a key value pair.
 * <pre>
 * function onMarkerClick( event )
 * {
 *  var s = "lat=" + AWUtils.deg2DMS(event.lat) + "\n";
 *  s += "lon=" + AWUtils.deg2DMS(event.lon) + "\n";
 *  s += "pixelX=" + event.pixelX + "\n";
 *  s += "pixelY=" + event.pixelY + "\n";
 *  s += "id=" + event.data.id + "\n";
 *  alert(s);
 * }
 * var myExplorer = new AWMap("explorer"); // here "explorer" is the ID of the div explorer is embedded in.
 * // Create and register a marker style.
 * var markerStyle = new AWImgMarkerStyle();
 * markerStyle.id = "myMarkerStyleId";
 * markerStyle.source = "http://www.arcwebservices.com/awx/images/id.png"; Valid icon details can be found on this <a href="/v2006/help/index.htm#awx/markers.htm" target="_blank">list</a>.
 * markerStyle.width = 16;
 * markerStyle.height = 16;
 * markerStyle.anchorX = 8;
 * markerStyle.anchorY = 8;
 * // Set the name of the function to call when the user clicks on the marker.
 * markerStyle.mouseClick = "onMarkerClick";
 * myExplorer.addMarkerStyle(markerStyle);
 * // Add a marker to the map with user defined attribute 'id' set to 'bos'
 * myExplorer.addMarker( new AWMarker( "myId", new AWLatLon(42.367044, -71.052742), markerStyle.id));
 *
 * ...
 *
 * myExplorer.clickMarker( "myId");  // call mouse click handler.
 * </pre>
 * @param {String} id the marker identifier.
 */
    clickMarker: function( id )
    {
        this.explorer.clickMarker(id);
    },
/**
 * Function to register a callback function to be invoked whenever the map center and scale values change.
 * <pre>
 * </pre>
 * @param {String} funcName the name of the function to call.
 */
    addMapChangedListener: function( funcName )
    {
        this.explorer.addMapChangedListener(funcName);
    },
/**
 * Function to set groupLayer properties at run time. A new request will been sent if needed.
 * <pre>
 * var myExplorer = new AWMap("explorer");
 * myExplorer.setGroupLayerProperties("vectorGroupLayer",{alpha:50});
 * </pre>
 * @param {String} groupLayer the name of the groupLayer.
 * @param {Object} properties the key/value object of the properties to be changed. Valid properties are groupLayer dependent.(see <a href="/v2006/help/index.htm#awx/grouplayers.htm" target="_blank"> groupLayer properties table</a>) 

 */
    setGroupLayerProperties: function( groupLayer, properties )
    {
        this.explorer.setGroupLayerProperties(groupLayer, properties);
    },
/**
 * Function to add a groupLayer to the map at run time. 
 * <pre>
 *	var myExplorer = new AWMap("explorer");
 *	myExplorer.addGroupLayer("vectorGroupLayer", "ArcWeb:bam", {alpha:50},1);
 *  //Note - Group Layer type variable(glt) must be set as "none" in the insertMap method to use this method.
 * </pre>
 * @param {String} groupLayer the name of the groupLayer.(see <a href="/v2006/help/index.htm#awx/grouplayers.htm" target="_blank">groupLayer properties table</a> for valid group layer names.)
 * @param {String} dataSource the datasource for the groupLayer. (optional, default data sources will be used if missing). Valid values are listed in the <a href="/v2006/help/index.htm#awx/datasources.htm" target="_blank">Datasource description</a>.
 * @param {Object} properties the key/value object of the properties to be changed. Valid properties are groupLayer dependent. (see <a href="/v2006/help/index.htm#awx/grouplayers.htm" target="_blank">groupLayer properties table</a>) (optional)
 * @param {Number} depth Sets the depth of the groupLayer added(optional, default is 0, ie the bottom). 

 */
    addGroupLayer: function( groupLayer, dataSource, properties, depth )
    {
       return this.explorer.addGroupLayer(groupLayer, dataSource, properties, depth);
    },
/**
 * Function to remove a single groupLayer.
 *
 * <pre>
 *	var myExplorer = new AWMap("explorer");
 *	myExplorer.removeGroupLayer("vectorGroupLayer");
 * </pre>
 * @param {String} groupLayer the name of the groupLayer (see the <a href="/v2006/help/index.htm#awx/grouplayers.htm" target="_blank">groupLayer properties table</a> for valid group layer names.)
 */
    removeGroupLayer: function( groupLayerType )
    {
        this.explorer.removeGroupLayer(groupLayerType);
    },
/**
 * Function to remove all groupLayers
 */
    removeAllGroupLayers: function()
    {
        this.explorer.removeAllGroupLayers();
    },
/**
 * Function to get a named property from a given groupLayer
 *
 * <pre>
 * var myExplorer = new AWMap("explorer");
 * var legendUrl = myExplorer.getGroupLayerProperty("thematicGroupLayer", "legendUrl");
 * </pre> 
 * @param {String} groupLayer the name of the groupLayer 
 * @param return the property if it was defined (object or array) (see the <a href="/v2006/help/index.htm#awx/grouplayers.htm" target="_blank">groupLayer properties table</a> for valid group layer names and properties. All properties mentioned in that table can be retrieved using this method. In addition to those properties you can also return layerVisibilityInfo (for thematic and mapImage groupLayers) and legendUrl (for thematic groupLayers).
 */
    getGroupLayerProperty: function( groupLayer, propertyName )
    {
        return this.explorer.getGroupLayerProperty(groupLayer, propertyName);
    },
/**
 * Function to add a callback for mouse up events. Properties returned: mouseX, mouseY, longitude, latitude.
 * <pre>
 * 	  var myExplorer = new AWMap("explorer");
 *    var myLatLon = new AWLatLon(42.367044, -71.052742);
 *    myExplorer.centerAndScale(myLatLon, 10000);
 *    myExplorer.addMouseUpCallBack("onMouseUp");
 * </pre>
 * @param {String} javascript callback name
 */
    addMouseUpCallBack: function( callback )
    {
        this.explorer.addMouseUpCallBack(callback);
    },
/**
 * Function to add a callback for mouse down events. Properties returned: mouseX, mouseY, longitude, latitude.
 * <pre>
 * 	  var myExplorer = new AWMap("explorer");
 *    var myLatLon = new AWLatLon(42.367044, -71.052742);
 *    myExplorer.centerAndScale(myLatLon, 10000);
 *    myExplorer.addMouseDownCallBack("onMouseUp");
 * </pre>
 * @param {String} javascript callback name
 */
    addMouseDownCallBack: function( callback )
    {
        this.explorer.addMouseDownCallBack(callback);
    },
/**
 * Function to zoom to the world extent.
 * <pre>
 * 	  var myExplorer = new AWMap("explorer");
 * 	  myExplorer.showWorldExtent();
 * </pre>
 */
    showWorldExtent: function()
    {
        this.explorer.showWorldExtent();
    },
/**
 * Function to change the mouse handler. Possible mouse handlers: "NoopMouseHandler", "SmoothPanMouseHandler", "RubberBandMouseHandler", "AddMarkerMouseHandler","RedLineMouseHandler". Note that these are case-sensitive.
 * <pre>
 * var myExplorer = new AWMap("explorer");
 * myExplorer.setMouseHandler("SmoothPanMouseHandler");
 * </pre>
 * @param {String} handler The handler to change to.
 * @param {Object} properties The properties of the marker in case of AddMarkerMouseHandler. Sets the marker icon, label prefix and suffix. The default, an expanding swf marker will kick in incase these parameters are not specified.
 */
    setMouseHandler: function( handler, properties )
    {
        this.explorer.setMouseHandler(handler, properties);
    },
/**
 * Function that allows routing between markers. Markers must first be added to the map then the ids are used for routing.
 * Properties of the response object are: polyLineIds[], routeDescription, totalTime, totalDistance, latLonExtent.
 * 
 * <pre>
 *   var myExplorer = new AWMap('explorer');
 *   
 *   var myLatLon = new AWLatLon(42.375, -71.06);
 *   myExplorer.centerAndScale(myLatLon, 20000);
 *   
 *   startMarker = new AWMarker();
 *   startMarker.latlon = new AWLatLon(42.36704409, -71.05274248);
 *   startMarker.id = "m_1";
 *   startMarker.data = {label:"Start"};
 *   myExplorer.addMarker(startMarker);
 *   
 *   endMarker = new AWMarker();
 *   endMarker.latlon = new AWLatLon(42.384, -71.071);
 *   endMarker.id = "m_2";
 *   endMarker.data = {label:"End"};
 *   myExplorer.addMarker(endMarker);
 *   var properties = {routeType:"shortest"};
 *   myExplorer.findRoute([startMarker.id,endMarker.id], "onRoute", null, null,properties);
 *   
 * function onRoute(event)
 * {
 *   alert("Total Time: "+event.totalTime+"\nTotal Distance: "+event.totalDistance); 
 * }
 * </pre>
 * @param {Array} MarkerIds Array of marker IDs to route
 * @param {String} callback JS function name for callback (optional)
 * @param {String} PolylineStyleId to be used for the route line. To use the default style specify as "null". If nothing is specified the route will not show.
 * @param {String} Route DataSource (optional). Valid values - ArcWeb:MDS.Streets.AS,ArcWeb:NT.Streets.EU,ArcWeb:NT.Streets.NA,ArcWeb:TA.Streets.EU and ArcWeb:TA.Streets.NA. The default is ArcWeb:TA.Streets.NA.  
 * @param {Object} properties extra routing properties, listed below(optional)<br>
 * 	hwyPref - number. Contains the preference for using highways. Valid values are between "1" and "100". The value of "1" means to avoid highways if possible, and the value of "100" means to use highways as much as possible. Default value is "80". If you set the value to "0", hwyPref defaults to "80". hwyPref is not used with routeType "shortest".<br>
 *  reorderStops - boolean. Determines if intermediate waypoints are reordered to optimize for distance. Default value is false. Not considered if request contains less than four markers.<br>
 *  routeType - string.(quickest/shortest)<br>
 *  trafficDataSource - string. (also an indicator whether traffic data is on/off). Valid Value is "ArcWeb:TC.Traffic.US".  <br>
 *  units - string.(km/miles)<br>
 *  trafficSeverity - number. Contains the traffic incident severity ratings to avoid. Valid values are "1" (severe), "2" (high), "3" (medium), or "4" (low). Traffic incidents at and above the set severity are avoided in a route, for example, "2" avoids high and severe incidents. "0" avoids all incidents. The default is "3".<br>
 */
    findRoute: function( markerIds, callback, polylineStyleId, dataSource, properties )
    {
        this.explorer.findRoute(markerIds, callback, polylineStyleId, dataSource, properties);
    },

/**
 * @ignore
 * Get the data object out of a polyLine
 * @param {String} polyLineId
 * @return the data object
 */
    getPolylineData:  function( polylineId )
    {
        return this.explorer.getPolylineData(polylineId);
    },

/**
 * Get the Y value of a corresponding latitude.
 *
 * <pre>
 * alert("getY(42.367044) = " + myExplorer.getY(42.367044));
 * </pre>
 *
 * @param {Number} latitude
 * @return the Y value
 */
    getY: function( latitude )
    {
        return this.explorer.getY(latitude);
    },
/**
 * Get the X value of a corresponding longitude.
 *
 * <pre>
 * alert("getX(-71.052742) = " + myExplorer.getX(-71.052742));
 * </pre>
 *
 * @param {Number} longitude
 * @return the X value
 */
    getX: function( longitude )
    {
        return this.explorer.getX(longitude);
    },
/**
 * Get the longitude of a corresponding x value, the origin being the top left corner.
 *
 * <pre>
 * alert("getLon(400) = " + myExplorer.getLon(400));
 * </pre>
 *
 * @param {Number} pixelX
 * @return the longitude
 */
    getLon: function( pixelX )
    {
        return this.explorer.getLon(pixelX);
    },
/**
 * Get the latitude of a corresponding Y value, the origin being the top left corner.
 *
 * <pre>
 * alert("getLat(600) = " + myExplorer.getLat(600));
 * </pre>
 *
 * @param {Number} pixelY
 * @return the latitude
 */
    getLat: function( pixelY )
    {
        return this.explorer.getLat(pixelY);
    },
/**
 * Add points to an existing polyline at run time
 * <pre>
 * </pre>
 * @param {String} polylineId the polyline ID in which to add points.
 * @param {points|Array} points the point or array of points to add to polyline.
 */
    addLatLonToPolyline: function( polylineId, points )
    {
        var resp;
        resp = this.explorer.addLatLonToPolyline(polylineId, points);
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * Change polyline style at run time
 * <pre>
 * </pre>
 * @param {String} polylineId the polyline ID in which to add points.
 * @param {String} polylineStyleId the polylineStyle to change the polyline to
 */
    changePolylineStyle: function( polylineId, polylineStyleId )
    {
        var resp;
        resp = this.explorer.changePolylineStyle(polylineId, polylineStyleId);
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * Add points to an existing polygon at run time
 * <pre>
 * </pre>
 * @param {String} polygonId the polygon ID in which to add points to.
 * @param {points|Array} points the point or array of points to add to polygon.
 */
    addLatLonToPolygon: function( polygonId, points )
    {
        var resp;
        resp = this.explorer.addLatLonToPolygon(polygonId, points);
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * Change polygon style at run time
 * <pre>
 * </pre>
 * @param {String} polylineId the polyline ID in which to add points.
 * @param {String} polylineStyleId the polylineStyle to change the polyline to
 */
    changePolygonStyle: function( polygonId, polygonStyleId )
    {
        var resp;
        resp = this.explorer.changePolygonStyle(polygonId, polygonStyleId);
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * Test to see if a marker intersects a polygon.
 * <pre>
 * myExplorer = new AWMap('explorer');
 * myExplorer.intersects("myMarker", "myPolygon")
 * </pre>
 * @param {String} markerId the ID of the marker under consideration
 * @param {String} polygonId the ID of a polygon. This method checks if the marker specified by markerId, lies within this polygon
 */
    intersects: function( markerId, polygonId )
    {
        return  this.explorer.intersects(markerId, polygonId);
    },
/**
 * Call a custom method on a SWF Marker.
 * <pre>
 * var myExplorer = new AWMap('explorer');
 * myExplorer.callMethodOnMarker("myMarkerID", "doEchoObj", {parameter1:"FooBar"});
 * </pre>
 * @param {String} markerID the markerID to call the function on
 * @param {String} functionName the name of the function to be called
 * @param {Object} args the arguments to be passed into the function
 */
    callMethodOnMarker: function( markerID, functionName, args )
    {
        var resp;
        resp = this.explorer.callMethodOnMarker(markerID, functionName, args);
        if( resp !== null )
        {
            throw new Error(resp);
        }
    },
/**
 * @ignore
 * Get the current polyline index.
 * @return {Number} the current polyline index.
 */
    getCurrentPolylineIndex : function()
    {
        return this.explorer.getCurrentPolylineIndex();
    },
/**
 * @ignore
 * Get the gemotry of a polyline.
 * @param {String} the polyline identifier.
 * @return {Array} an array of LatLon objects.
 */
    getPolylineGeometry : function( polylineId )
    {
        return this.explorer.getPolylineGeometry(polylineId);
    },
	
/**
 * Toogle the level of the mouse click layer. This can be very useful if you are adding large polygons but are not interested in being able to click on them to retrieve data. For example, you can set the clickable layer to 'top', so you can pan clicking anywhere on the map including on polygons you have inserted.
 * @param {String} level, either 'top' or 'bottom'
 */
	toggleMouseClickLayer : function( level )
	{
		var resp;
        resp = this.explorer.toggleMouseClickLayer(level);
        if( resp !== null )
        {
            throw new Error(resp);
        }
	},
	
/**
 * addFlashObject lets you add a swf file onto the map at an arbitrary X/Y pixel location, not lat/lon location.
 * <pre>
 * var myExplorer = new AWMap('map');
 * myExplorer.addFlashObject("myLogo.swf",{x:20,y:20,alpha:25});
 * </pre>
 * @param {String} source the source URL of the flash object to load 
 * @param {Object} properties the properties of this flash object (x, y, alpha)
 */
	addFlashObject : function( source, properties )
	{
		var resp;
        resp = this.explorer.addFlashObject(source, properties);
        if( resp !== null )
        {
            throw new Error(resp);
        }
	},
	
/**
 * adds printing support to AWX
 * <pre>
 * var myExplorer = new AWMap("explorer");
 * myExplorer.printMap();
 * <pre>
 */
	printMap : function()
	{
		this.explorer.printMap();
	}
};

/**
 * Construct a new AWImgMarkerStyle object.
 * @class This style renders a marker as an image on the map.
 * Using this style, an application can define an image source, a mouse over event, callback functions
 * for a mouse click event, and a move over or out of the marker.
 * <pre>
 * function onMarkerClick( event )
 * {
 *  var s = "lat=" + AWUtils.deg2DMS(event.lat) + "\n";
 *  s += "lon=" + AWUtils.deg2DMS(event.lon) + "\n";
 *  s += "pixelX=" + event.pixelX + "\n";
 *  s += "pixelY=" + event.pixelY + "\n";
 *  s += "id=" + event.data.id + "\n";
 *  s += "url=" + event.data.url + "\n";
 *  alert(s);
 * }
 * function onMarkerOver( event )
 * {
 *  var s = "lat=" + AWUtils.deg2DMS(event.lat) + "\n";
 *  s += "lon=" + AWUtils.deg2DMS(event.lon) + "\n";
 *  alert(s);
 * }
 * function onMarkerOut( event )
 * {
 *  var s = "lat=" + AWUtils.deg2DMS(event.lat) + "\n";
 *  s += "lon=" + AWUtils.deg2DMS(event.lon) + "\n";
 *  alert(s);
 * }
 * // Locate ArcWeb Explorer component.
 * var myExplorer = new AWMap('map');
 * // Create an image marker style.
 * var markerStyle = new AWImgMarkerStyle();
 * markerStyle.id = "myMarkerStyleId";
 * markerStyle.source = "images/id-g.png";
 * markerStyle.mouseOverSource = "images/id-r.png";
 * markerStyle.mouseClick = "onMarkerClick";
 * markerStyle.mouseOver = "onMarkerOver";
 * markerStyle.mouseOut = "onMarkerOut";
 * // Register the style with the map.
 * myExplorer.addMarkerStyle(markerStyle);
 * // Create a marker
 * var marker = new AWMarker();
 * marker.latlon = latlon;
 * marker.markerStyleId = markerStyle.myMarkerStyleId;
 * // Marker has user defined data in key value pair format. Here, for example, label has the value "ESRI". It could be any string.
 * marker.data = {label:"ESRI",url:"http://www.esri.com"};
 * Put the marker on the map.
 * myExplorer.addMarker(marker);
 * </pre>
 * @constructor
 * @return An instance of AWImgMarkerStyle.
 */
function AWImgMarkerStyle()
{
    /**
     * The style type.  This is a private field.
     * @type String
     * @private
     */
    this.type = "img";
    /**
     * The style identifier.
     * @type String
     */
    this.id = "esri:img";
    /**
     * The image source. This can be any URL to a PGN image. The images can be accessed at the path "images/image-name.png". Valid icon details can be found on this <a href="/v2006/help/index.htm#awx/markers.htm" target="_blank">list</a>.
     * @type String
     */
    this.source = "images/id.png";
    /**
     * The transparency of the marker, where 0 indicates full transparency, 100 full opacity. Default is 100.
     * @type Number
     */
    this.alpha = 100;
    /**
     * The width in pixels of the source image. Icon details can be found on this <a href="/v2006/help/index.htm#awx/markers.htm" target="_blank">list</a>.
     * @type Number
     */
    this.width = 16;
    /**
     * The height in pixels of the source image. Icon details can be found on this <a href="/v2006/help/index.htm#awx/markers.htm" target="_blank">list</a>.
     * @type Number
     */
    this.height = 16;
    /**
     * The horizontal anchor location in pixels within the image. Icon details can be found on this <a href="/v2006/help/index.htm#awx/markers.htm" target="_blank">list</a>.
     * @type Number
     */
    this.anchorX = 8;
    /**
     * The vertical anchor location in pixels within the image. Icon details can be found on this <a href="/v2006/help/index.htm#awx/markers.htm" target="_blank">list</a>.
     * @type Number
     */
    this.anchorY = 8;
    /**
     * The horizontal distance in pixels that a marker should have to display a bubble. Default is 0.
     * @type Number
     */
    this.bubbleWidth = 0;
    /**
     * The vertical distance in pixels that a marker should have to display a bubble. Default is 0.
     * @type Number
     */
    this.bubbleHeight = 0;
    /**
     * The name of the callback function to execute when a mouse click event occurs.
     * @type String
     */
    this.mouseClick = "";
    /**
     * The name of the callback function to execute when a mouse over event occurs.
     * @type String
     */
    this.mouseOver = "";
    /**
     * The name of the callback function to execute when a mouse out event occurs.
     * @type String
     */
    this.mouseOut = "";
    /**
     * The mouse over image source. This can be any URL to a PNG image. The images can be accessed at the path "images/image-name.png". Valid icon details can be found on this <a href="/v2006/help/index.htm#awx/markers.htm" target="_blank">list</a>.
     * @type String
     */
    this.mouseOverSource = "";
}

/**
 * @ignore
 */
function AWPOIMarkerStyle()
{
    this.id = "esri:poi";
    this.type = "poi";
    this.source = "poi.swf";
    this.width = 16;
    this.height = 16;
    this.anchorX = 8;
    this.anchorY = 8;
    this.index = null;
    this.label = null;
    this.description = null;
    this.url = null;
    this.movie = null;
    this.sound = null;
}

/**
 * @ignore
 */
function AWSWFMarkerStyle()
{
    this.id = "esri:swf";
    this.type = "swf";
    this.source = "marker.swf";
    this.width = 16;
    this.height = 16;
    this.anchorX = 8;
    this.anchorY = 8;
}

/**
 * Create a new AWLatLon instance based on a latitude and longitude value.
 * @class AWLatLon is a class that encapsulates location information.
 * @constructor
 * @param {Number} lat the latitude value.
 * @param {Number} lon the longitude value.
 * @return An instance of AWLatLon.
 * @type AWLatLon
 */
function AWLatLon( lat, lon )
{
    /**
     * The latitude value.
     * @type Number
     */
    this.lat = lat;
    /**
     * The longitude value.
     * @type Number
     */
    this.lon = lon;
}

/**
 * Create a new AWLatLonExtent instance based on the minimum and maximum latitude and longitude values.
 * @class AWLatLonExtent is a class that encapsulates a location extent.
 * @constructor
 * @param {Number} minLat the minimum latitude.
 * @param {Number} minLon the minimum longitude.
 * @param {Number} maxLat the maximum latitude.
 * @param {Number} maxLon the maximum longitude.
 * @return An instance of AWLatLonExtent.
 * @type AWLatLonExtent
 */
function AWLatLonExtent( minLat, minLon, maxLat, maxLon )
{
    /**
     * The extent's minimum latitude value.
     * @type Number
     */
    this.minLat = minLat;
    /**
     * The extent's minimum longitude value.
     * @type Number
     */
    this.minLon = minLon;
    /**
     * The extent's maximum latitude value.
     * @type Number
     */
    this.maxLat = maxLat;
    /**
     * The extent's maximum longitude value.
     * @type Number
     */
    this.maxLon = maxLon;
}

/**
 * Create a AWMarker instance based on a location, a marker style id, and user defined data.
 * Note: the default tooltip over a marker displays the lat/lon value. However, you can
 * override this behavior by adding a user defined data object with a property named 'label'.
 * The value of this property is used as text for the tooltip popup. In addition, a multiline
 * tooltip can be generated from a label value, where each line is separated from the next
 * using a '\n' character, such as: "Hello\nWorld".
 * @class AWMarker is a class that encapsulates marker information.
 * <pre>
 * var marker = new AWMarker(
 * "myId" // the marker identifier.
 *  new AWLatLon(42.367044, -71.052742), // Location
 *  "myMarkerStyleId", // Style identifier
 *  {label:"Boston\nMA"} // User defined data object.
 * );
 * </pre>
 * @constructor
 * @param {String} id the marker identifier.
 * @param {AWLatLon} latlon the marker location.
 * @param {String} markerStyleId the ID of the registered marker style (optional).
 * @param {Object} data user defined data associated with this marker (optional).The description of parameters in this object can be found in this <a href="/v2006/help/index.htm#awx/awmarkerdesc.htm" target="_blank">list</a>
 * @return An instance of AWMarker.
 * @type AWMarker
 */
function AWMarker( id, latlon, markerStyleId, data )
{
    /**
     * The marker identifier.
     * @type String
     */
    this.id = id;
    /**
     * The marker location.
     * @type AWLatLon
     */
    this.latlon = latlon;
    /**
     * The marker style id.
     * @type String
     */
    this.markerStyleId = markerStyleId;
    /**
     * The marker user defined data (optional).
     * @type Object
     */
    this.data = data;
}

/**
 * @class AWLocation is a class that encapsulates marker location information.
 * A location can be an address, a lindline phone number, or an IP address.
 * AWLocation can be instantiated in the following ways:
 * <pre>
 * var myAddress = new AWLocation( "esri", "380 New York St, Redlands, CA", "styleId", {id:"esri",label:"ESRI"});
 * var myPhone = new AWLocation( "esri", "909 793 2853", "phoneStyleId");
 * var myIP = new AWLocation( "esri", "www.esri.com");
 * </pre>
 * @constructor
 * @param {String} id the location identifier.
 * @param {String} location the address, phone number or ip address.
 * @param {String} markerStyleId the ID of the registered marker style (optional).
 * @param {Object} data user defined data associated with this marker (optional). 
 * @return An instance of AWLocation.
 * @type AWLocation
 */
function AWLocation( id, location, markerStyleId, data )
{
    /**
     * The location identifier.
     * @type String
     */
    this.id = id;
    /**
     * Location can be an address, a lindline phone number, or an IP address.
     * @type String
     */
    this.location = location;
    /**
     * The marker style identifier. If the identifier is <code>null</code> a default internal identifier is used.
     * @type String
     */
    this.markerStyleId = markerStyleId;
    /**
     * Optional user defined data object.
     * @type Object
     */
    this.data = data;
}

/**
 * @class AWGradientStyle is a class to encapsulate gradient style information.
 * @constructor
 * @param {String} fillType "radial", "linear"
 * @param {Array} colors array of RGB colors.
 * @param {Array} alphas array of alpha values.
 * @param {Array} ratios array of ratio values.
 * @param {Object} matrix.
 * @param {String} spreadMethod "pad", "reflect", "repeat"
 * @param {String} interpolationMethod "RGB", "linearRGB"
 * @param {Number} focalPointRatio number between -1 and 1.
 */
function AWGradientStyle( fillType, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio )
{
    /**
     * The fill type. The acceptable values are "radial", "linear".
     * @type String
     */
    this.fillType = fillType;
    /**
     * Array of RGB colors.
     * @type Array
     */
    this.colors = colors;
    /**
     * Array of alpha values.
     * @type Array
     */
    this.alphas = alphas;
    /**
     * Array of ratios.
     * @type Array
     */
    this.ratios = ratios;
    /**
     * the matrix TODO - document that.
     * @type Object
     */
    this.matrix = matrix;
    /**
     * The spread method. The acceptable values are "pad", "reflect", "repeat"
     * @type String
     */
    this.spreadMethod = spreadMethod;
    /**
     * The interpolation method. The acceptable values are "RGB", "linearRGB".
     * @type String
     */
    this.interpolationMethod = interpolationMethod;
    /**
     * The focal point ratio. The acceptable values are between -1 and 1.
     * @type Number
     */
    this.focalPointRatio = focalPointRatio;
}
/**
 * @class AWPolylineStyle is a class that encapsulates polyline style information.
 * @constructor
 */
function AWPolylineStyle()
{
    /**
     * The polyline style identifier.
     * @type String
     */
    this.id = "esri:polyline";
    /**
     * The polyline thickness.
     * @type Number
     */
    this.thickness = 1;
    /**
     * The polyline color.
     * @type Number
     */
    this.rgb = 0x000000;
    /**
     * The polyline transparency.
     * @type Number
     */
    this.alpha = 100;
    /**
     * Stroke hinting in the IDE.
     * @type Boolean
     */
    this.pixelHinting = false;
    /**
     * Stroke scale behavior within parent. Valid values are, "none", "normal", "parent".
     * @type String
     */
    this.noScale = "none";
    /**
     * The caps style Valid values are, "round", "square", "none"
     * @type String
     */
    this.capsStyle = "none";
    /**
     * The joint style. Valid values are, "round", "miter", "none"
     * @type String
     */
    this.jointStyle = "none";
    /**
     * The miter limit. Valid values are between 0 and 255
     * @type Number
     */
    this.miterLimit = 0;
    /**
     * The polyline gradient style. To learn how to better manipulate the gradient style visit the <a href = "http://livedocs.macromedia.com/flash/8/" target = "_top">flash help pages</a>.
     * @type AWGradientStyle
     */
    this.gradientStyle = null;
    /**
     * The name of the callback function to execute when a mouse over event occurs.
     * @type String
     */
    this.mouseOver = null;
    /**
     * The name of the callback function to execute when a mouse click event occurs.
     * @type String
     */
    this.mouseClick = null;
    /**
     * The name of the callback function to execute when a mouse out event occurs.
     * @type String
     */
    this.mouseOut = null;
}
/**
 * @class AWPolygonStyle is a class that encapsulates polygon style information.
 * @constructor
 */
function AWPolygonStyle()
{
    /**
     * The polygon style identifier.
     * @type String
     */
    this.id = "esri:polygon";
    /**
     * The polygon color.
     * @type Number
     */
    this.rgb = 0x000000;
    /**
     * The polygon transparency.
     * @type Number
     */
    this.alpha = 100;
    /**
     * The polyline style identifier.
     * @type String
     */
    this.polylineStyleId = null;
    /**
     * The polygon gradient style. To learn how to better manipulate the gradient style visit the <a href = "http://livedocs.macromedia.com/flash/8/" target = "_top">flash help pages</a>.
     * @type AWGradientStyle
     */
    this.gradientStyle = null;
    /**
     * The name of the callback function to execute when a mouse over event occurs.
     * @type String
     */
    this.mouseOver = null;
    /**
     * The name of the callback function to execute when a mouse click event occurs.
     * @type String
     */
    this.mouseClick = null;
    /**
     * The name of the callback function to execute when a mouse out event occurs.
     * @type String
     */
    this.mouseOut = null;
}
/**
 * @class AWPolyline is a class that encapsulates polyline information.
 * <pre>
 * var myPolyline = new AWPolyline(
 * "myId", // The polyline identifier.
 * [ new AWLatLon(37.4419, -122.1419), new AWLatLon(37.4519, -122.1519) ],
 * "myPolylineStyleId",  // The polyline style identifier.
 * {name:"Some Name"} // user defined data.
 * );
 * </pre>
 * @constructor
 * @param {String} id the polyline identifier.
 * @param {Array} latlonArray an array of {@link AWLatLon} objects.
 * @param {AWPolylineStyle} polylineStyleId the polyline style identifier. (optional)
 * @param {Object} data user defined data attached to this polyline. (optional)
 * @return An instance of AWPolyline.
 * @type AWPolyline
 */
function AWPolyline( id, latlonArray, polylineStyleId, data )
{
    /**
     * The polyline identifier.
     * @type String
     */
    this.id = id;
    /**
     * Array of {@link AWLatLon} objects.
     * @type Array
     */
    this.latlonArray = latlonArray;
    /**
     * Polyline style identifier.
     * @type String
     */
    this.polylineStyleId = polylineStyleId;
    /**
     * User defined data.
     * @type Object
     */
    this.data = data;
}

/**
 * @class AWPolygon is a class that encapsulates polygon information.
 * <pre>
 * var myPolygon = new AWPolygon(
 * "myId", // The polygon identifier.
 * [ new AWLatLon(37.4419, -122.1419), new AWLatLon(37.4519, -122.1519), new AWLatLon(37.4519, -122.1619) ],
 * "myPolygonStyleId",  // The polygon style identifier.
 * {name:"Some Name"} // user defined data.
 * );
 * </pre>
 * @constructor
 * @param {String} id the polygon identifier.
 * @param {Array} latlonArray an array of {@link AWLatLon} objects.
 * @param {AWPolygonStyle} polygonStyleId the polygon style identifier. (optional)
 * @param {Object} data user defined data attached to this polyline. (optional). 
 * @return An instance of AWPolygon.
 * @type AWPolygon
 *  
 *
 */
function AWPolygon( id, latlonArray, polygonStyleId, data )
{
    /**
     * The polygon identifier.
     * @type String
     */
    this.id = id;
    /**
     * Array of {@link AWLatLon} objects.
     * @type Array
     */
    this.latlonArray = latlonArray;
    /**
     * Polygon style identifier.
     * @type String
     */
    this.polygonStyleId = polygonStyleId;
    /**
     * User defined data.
     * @type Object
     */
    this.data = data;
}

/**
 * @class Helper class containing static utility functions.
 */
function AWUtils()
{
}

/**
 * Static utility function to create a formatted string of a decimal degree value in DD MM SS.
 * @param {Number} dd the decimal degree number.
 * @param {String} l "lat" to suffix the string with N/S, "lon" to suffix the string with W/E.
 * @return A formatted string in DD MM SS format.
 * @type String
 */
AWUtils.deg2DMS = function( dd, l )
{
    var d = Math.abs(dd);
    var deg = Math.floor(d);
    d = d - deg;
    var min = Math.floor(d * 60);
    var av = d - min / 60;
    var sec = Math.floor(av * 60 * 60);
    if( sec == 60 )
    {
        min++;
        sec = 0;
    }
    if( min == 60 )
    {
        deg++;
        min = 0;
    }
    var smin = min < 10 ? "0" + min + "' " : min + "' ";
    var ssec = sec < 10 ? "0" + sec + "\" " : sec + "\" ";
    var c = (l == "lat") ? (dd < 0 ? "S" : "N") : (dd < 0 ? "W" : "E");
    return deg + "\xB0 " + smin + ssec + c;
};

/**
 * Static utility function to insert the required Flash Object.
 * Here, a flash object will be created with the ID "map"  and will be inserted
 * into a div element with ID "explorer".  The width and height are of type String as the user
 * can use "100%" for exmple for the width and height.
 * In addition, this will call a javascript function named "onCreationComplete" when the flash movie is loaded.
 * <pre>
 * AWUtils.insertMap("explorer", "mykey", {"showHeader":"false"});
 * </pre>
 * @param {String} divid the HTML div identifier in the document where the map is displayed.
 * @param {String} key the ArcWeb Explorer API key.
 * @param {Object} vars object containing key value pairs of Flash parameters (optional). The Flash parameters are detailed on this <a href="/v2006/help/index.htm#awx/flash.htm" target="_blank">list</a>
 * The valid keys are:
 * showHeader: true/false
 * mapType: street | hybrid | satellite
 * cx: center longitude value
 * cy: center latitude value.
 * sf: gis scale factor
 *
 *
 */
AWUtils.insertMap = function( divId, key, vars )
{
    var mySWFObject = new SWFObject("http://www.arcwebservices.com/awx/index.swf", divId + "_Map", "100%", "100%", "8,0,24", "#FFFFFF");

    mySWFObject.addVariable("key", key);

    if( vars == undefined || (vars != undefined && vars.jsCreationComplete == undefined) )
    {
        mySWFObject.addVariable("jsCreationComplete", "onCreationComplete");
    }
    if( arguments.length == 3 )
    {
        for( v in vars )
        {
            if( v == "wmode" && vars[v] == "true" )
            {
                mySWFObject.addParam("wmode", "transparent");
            }
            else
            {
                mySWFObject.addVariable(v, vars[v]);
            }
        }
    }
    mySWFObject.addParam("allowScriptAccess", "always");
	mySWFObject.addVariable("historyUrl", "http://www.arcwebservices.com/awx/flex-internal?action=history_html");
	mySWFObject.addVariable("lconid", lc_id);
	

    new Insertion.Bottom(divId, '<div id="__checkVersion" align="center" position:relative; top:20px; align:center">You do not have any version of the Flash Player installed.</div>')

    var so = new SWFObject("http://www.arcwebservices.com/awx/ExpressInstall.swf", "checkVersion", "235", "150", "8.0.24", "#FFFFFF", true);
    so.write("__checkVersion");

    mySWFObject.write(divId);
};
/**
 * Static utility function to add Flash callback function when Explorer is defined in a FORM tag in IE.
 */
AWUtils.addFlashCallbacks = function( divId )
{
    var flashId = divId + "_Map";
    var flashMap = $(flashId);
    window[flashId] = flashMap;
    for( var v in flashMap )
    {
        if( typeof flashMap[v] == 'function' )
        {
            __flash__addCallback(flashMap, v);
        }
    }
};
/**
 * @class Class to execute a function on a periodic basic.
 * The execution can be terminated using the clear method.
 */
var AWExecuter = Class.create();
AWExecuter.prototype = {
/**
 * @ignore
 * Internal function called when application calls a new AWExecuter.
 * @constructor
 * @param {String} callback the name of the function to call at specified frequency.
 * @param {Number} frequency the execution frequency in seconds.
 * @return An instance of AWExecuter.
 * @type AWExecuter
 */
    initialize: function( callback, frequency )
    {
        this.callback = callback;
        this.frequency = frequency;
        this.currentlyExecuting = false;
        this.interval = null;
        this.registerCallback();
    },
/**
 * @private
 */
    registerCallback: function()
    {
        this.interval = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
    },
/**
 * Terminate the execution.
 */
    clear: function()
    {
        clearInterval(this.interval);
    },
/**
 * @private
 */
    onTimerEvent: function()
    {
        if( !this.currentlyExecuting )
        {
            try
            {
                this.currentlyExecuting = true;
                this.callback();
            }
            finally
            {
                this.currentlyExecuting = false;
            }
        }
    }
};
