
 /* This is a generated file.  Do not edit.  Edit the individual js files and regenerate the home page. */
	/*  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 ? object.toString() : typeof object);
  } 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("'", '\\\'') + "'";
  },
	_each: function(iterator) {
	    for (var i = 0; i < this.length; i++){
			iterator(this.substring(i, i+1));
		}
	},
	chunkSplit: function(length, limit){
		var output = [];
		var str = this;
		var c = 0;
		while(str.length && (!limit || ++c < limit)){
			output.push(str.substring(0, length));
			str = str.substring(length);
		}
		if(limit){
			output.push(str);
		}
		return output;
	}
	
});

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() + '>';
  },
  
	unique: function(){
		return this.inject([], function(results, item){
			if(results.indexOf(item) < 0)
				results.push(item);
			return results;
		});
	}
}

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);
Object.extend(String.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,
      wait: false,
      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.url = url;
    this.hasStarted = false;
    this.setOptions(options);
    if(!this.options.wait){
      this.start();
    }
  },
  start: function() {
  	if(!this.hasStarted) {
  	  this.hasStarted = true;
  	  this.request(this.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.toUpperCase(), 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') {
    	
      /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
      /* This operation has been moved up here to fix a timing issue with IE 5.5 and executing 
       * respondToReadyState multiple times when complete 
       */
      this.transport.onreadystatechange = Prototype.emptyFunction;
      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);
  },
  
  abort: function(){
  	this.transport.abort();
  }
  
});

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.url = url;
    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);
    if(!this.options.wait)
      this.start();
  },
  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);
  }
});


/**
 * Queue for controlling AJAX actions.
 * You can pass an Ajax.Request or Ajax.Updater object.
 * I wouldn't recommend using a PeriodicalUpdater here.  I don't know what would happen.
 */

Ajax.Queue = Class.create();

Ajax.Queue.FILO = 1;	//First in, Last out
Ajax.Queue.FIFO = 2;	//First in, First out
Ajax.Queue.Single = 3;	//Only one action at a time.  When you add a new action, 
			// the current one will be terminated.

Object.extend(Ajax.Queue.prototype, Enumerable);
Object.extend(Ajax.Queue.prototype, {
	initialize: function(mode, wait){
			var _queue;
			var mode
			var started;

			this._queue = [];
			this.mode = mode;
			this.started = !wait;
	},
	_each:	function(iterator) {
		for (var i = 0; i < this._queue.length; i++)
			iterator(this._queue[i]);
	},
	first:		function(){ return this._queue[0] },
	last:		function(){ return this._queue[this._queue.length - 1] },
	indexOf:	function(object) {
				for (var i = 0; i < this._queue.length; i++)
					if (this._queue[i] == object) return i;
				return -1;
	},
	addAction: function(ajax_obj, options){
		var action = new Ajax.QueueAction(this, ajax_obj, options);
		
		switch(this.mode){
			case Ajax.Queue.FILO:
				if(this._queue.length)
					this._queue[this._queue.length-1].deactivate();
			case Ajax.Queue.FIFO:
				this._queue.push(action);
				break;
			case Ajax.Queue.Single:
				if(this._queue.length > 0){
					if(this._queue[0].is_complete){
						this._queue.shift();
					}
					else{
						var old_action = this._queue[0];
						old_action.action.abort();
						if(old_action.onOverride){
							setTimeout(old_action.onOverride, 1);
						}
						if(this._queue.length)
							this._queue.shift();

					}
				}
				this._queue.push(action);
				if(this.started)
					this._queue[0].activate();
				break;
		}
		
		this.update();
	},
	
	start: function(){
		this.started = true;
		this.update();
	},
	
	stop: function(){
		this.started = false;
	},
	
	update: function(){
		if(this.started){
			switch(this.mode){
				case Ajax.Queue.FILO:
					if(this._queue[this._queue.length-1]){
						if(this._queue[this._queue.length-1].is_complete){
							this._queue.pop();
						}
						if(!this._queue[this._queue.length-1].is_active){
							this._queue[this._queue.length-1].activate();
						}
					}
					break;
				case Ajax.Queue.FIFO:
					if(this._queue[0]){
						if(this._queue[0].is_complete){
							this._queue.shift();
						}
						if(!this._queue[0].is_active){
							this._queue[0].activate();
						}
					}
					break;
				case Ajax.Queue.Single:
					if(this.started){
						if(this._queue.length && !this._queue[0].is_active)
							this._queue[0].activate();
					}
					break;
			}
		}
	}

});

Ajax.QueueAction = Class.create();

Object.extend(Ajax.QueueAction.prototype, {

	initialize: function(queue, action, options){
		var queue;
		var action;
		var priority;		//This does nothing right now
		var onOverride;
		var events;
		var missed_events;
		var is_active;
		var is_complete;
		var debug_mode;

		this.queue = queue;
		this.action = action;
		this.is_active = false;
		this.is_complete = false;
		
		this.missed_events = [];
		this.events = {};

		if(options){
			this.priority = options.priority ? options.priority : 1;
			this.onOverride = options.onOverride ? options.onOverride : null;
			this.debug_mode = options.debug_mode || false;
		}
		

		this.events.onComplete = action.options.onComplete || Prototype.emptyFunction;
		action.options.onComplete = function(){ 
			this.handleEvent('onComplete', $A(arguments)); 
		}.bind(this);
		
		this.events.onSuccess = action.options.onSuccess || Prototype.emptyFunction;
		action.options.onSuccess = function(){ 
			this.handleEvent('onSuccess', $A(arguments)); 
		}.bind(this);
		
		this.events.onFailure = action.options.onFailure || Prototype.emptyFunction;
		action.options.onFailure = function(){ 
			this.handleEvent('onFailure', $A(arguments)); 
		}.bind(this);
		
		this.events.onException = action.options.onException || Prototype.emptyFunction;
		action.options.onException = function(){ 
			this.handleEvent('onException', $A(arguments)); 
		}.bind(this);
		
		this.events.onCreate = action.options.onCreate || Prototype.emptyFunction;
		action.options.onCreate = function(){ 
			this.handleEvent('onCreate', $A(arguments)); 
		}.bind(this);
		
	},
	
	activate: function(){
		this.is_active = true;
		this.action.start();
		while(this.missed_events.length){
			var me = this.missed_events.shift();
			this.applyEvent(me.event_key, me.params);
		}
	},
	
	deactivate: function(){
		//Debug.log('Deactivating ' + this.action.url + '\n' + this.missed_events);
		this.is_active = false;
	},
	
	handleEvent: function(event_key, params){
		var debug = this.action.url + '\n' + event_key + "\n" + params;
		if(this.is_active){
			debug = debug + '\nApplying';
			this.applyEvent(event_key, params);
		}
		else{
			debug = debug + '\nDelaying';
			this.delayEvent(event_key, params);
			debug = debug + '\nMissed Events:' + this.missed_events.pluck('event_key');
		}
		if(this.debug_mode) Debug.log(debug);
	},
	
	applyEvent: function(event_key, params){
		if(this.debug_mode) Debug.log(this.action.url + '\nTriggering ' + event_key);
		this.events[event_key].apply(this.action, params);
		if('onComplete' == event_key){
			this.is_complete = true;
			this.is_active = false;
			this.queue.update();
		}
	},
	
	delayEvent: function(event_key, params){
		this.missed_events.push({event_key: event_key, params: params});
		//Debug.log('Delaying ' + this.action.url + '\n' + this.missed_events.pluck('event_key'));
	}

});

/**
 * Expanded by Aaron J Pedersen to find class when more than one class has been defined
 * Example class="class1 class2" you can find either class1 or class2
 */
document.getElementsByClassName = function(className, parentElement, nodeType) {
	var search_elements;
	
	if(nodeType)
		search_elements = $NL(($(parentElement) || document.body).getElementsByTagName(nodeType));
	else if(document.all)
		search_elements = $NL(($(parentElement) || document.body).all);
	else
		search_elements = $NL(($(parentElement) || document.body).getElementsByTagName("*"));

	className = className.toUpperCase();
 
  return search_elements.inject([], function(elements, child) {
  	var classElements = $A(child.className.toUpperCase().split(' '));
  	classElements.each(function(classElement) {
		if (classElement == className) {
	    		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);
    }
    return this.observers[this.observers.length-1];
  },

  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';

    return this._observeAndCache(element, name, observer, useCapture);
  },
  
  stopObserving: function(element, name, observer, useCapture) {

    if(arguments.length == 1){
    	name = element[1];
    	observer = element[2];
    	useCapture = element[3];
    	element = element[0];
    }
    
    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];
  }
}


////////////////////////////////////////////////////
////	Custom Stuff below this line	////////////

/**
 * Define some globals for figuring out what type of element we have
 */

function Node() {}

Node.ELEMENT_NODE = 1;
Node.ATTRIBUTE_NODE = 2;
Node.TEXT_NODE = 3;
Node.CDATA_SECTION_NODE = 4;
Node.ENTITY_REFERENCE_NODE = 5;
Node.ENTITY_NODE = 6;
Node.PROCESSING_INSTRUCTION_NODE = 7;
Node.COMMENT_NODE = 8;
Node.DOCUMENT_NODE = 9;
Node.DOCUMENT_TYPE_NODE = 10;
Node.DOCUMENT_FRAGMENT_NODE = 11;
Node.NOTATION_NODE = 12;

/**
 * This section extends (or create in IE) the NodeList object
 * to allow for enumeration of read-only node lists (element.childNodes, etc)
 * A NodeList differs from an Array in a couple ways.
 * - It is specifically designed to hold Nodes (XML nodes or HTML elements)
 * - It is read only
 * - It is often "live" meaning that if the DOM changes, this list will often change
 *   without warning.
 * - It's much faster
 */
function IENodeList(node_list){
	var _real_node_list;
	this._real_node_list = node_list;
};

NodeList_Extensions = {
	elements:	function() {
					return this.inject([], function(elementNodes, element) {
					  if(element.nodeType == Node.ELEMENT_NODE)
						elementNodes.push(element);
					  return elementNodes;
					})
				},
	firstElement:	function(){
					return this.elements().first();
				},
	lastElement:	function(){
					return this.elements().last();
				},
	inspect:	Array.prototype.inspect				
};


Object.extend(IENodeList.prototype, Enumerable);
Object.extend(IENodeList.prototype, {
	_each:	function(iterator) {
		for (var i = 0; i < this._real_node_list.length; i++)
			iterator(this._real_node_list[i]);
	},
	first:		function(){ return this._real_node_list[0] },
	last:		function(){ return this._real_node_list[this._real_node_list.length - 1] },
	indexOf:	function(object) {
				for (var i = 0; i < this._real_node_list.length; i++)
					if (this._real_node_list[i] == object) return i;
				return -1;
			}
});
Object.extend(IENodeList.prototype, NodeList_Extensions);

if(typeof NodeList != 'undefined'){
	Object.extend(NodeList.prototype, Enumerable);	
	Object.extend(NodeList.prototype, {
		_each:		Array.prototype._each,
		first:		Array.prototype.first,
		last:		Array.prototype.last,
		indexOf:	Array.prototype.indexOf
	});
	Object.extend(NodeList.prototype, NodeList_Extensions);
}

/**
 * Build a browser independent NodeList object from a node list.
 * This does nothing in FireFox, but supplies a bunch of fixes in IE.
 */
function $NL(node_list){

	if(typeof IENodeList != 'undefined' || typeof node_list != 'NodeList'){
		return new IENodeList(node_list);
	}
	else{
		return node_list;
	}

}


/**
 * The Notification Center allows an object to subscribe to a system wide
 * message and have a function called when that message is broadcast.
 */
var _NotificationCenter = Class.create();
Object.extend(_NotificationCenter.prototype, {
	initialize: function(){
		this.subscribers = [];
	},
	
	addSubscriber: function(message, object, callback, once){
		if(!once || this.subscribers.any(function(sub){ return (message == sub.message && object == sub.object); }))
			this.subscribers.push({message: message, object: object, callback: callback});
	},
	
	/**
	 * Unsubscribe from a message.
	 * TODO: maybe there should be two functions: removeSubscriber and removeSubscriberForMessage
	 * 	the first one would unsubscribe that object from all messages and the second would
	 * 	act like this function does now.
	 */
	removeSubscriber: function(message, object){
		this.subscribers = this.subscribers.reject(function(subscriber){
			if(message == subscriber.message && object == subscriber.object)
				return true;
			else
				return false;
		});
	},
	
	/**
	 * Publish a notification.  This will activate the callback functions of any
	 * subscribers that are subscribed 'message'.
	 * The second parameter ('params'), should be an array of parameters that
	 * will be passed on to the callback functions of the subscribers.
	 */
	sendNotification: function(message, params){
		var sent = 0;
		this.subscribers.each(function(subscriber){
			if(message == subscriber.message){
				if(typeof subscriber.callback == 'string'){
					subscriber.object[subscriber.callback].apply(subscriber.object, [subscriber.message].concat(params));
					++sent;
				}
				else{
					subscriber.callback.apply(subscriber.object, [subscriber.message].concat(params));
					++sent;
				}
			}
		});
	}
});
var NotificationCenter = new _NotificationCenter();

function emptyElement(element){
	while(element.childNodes.length){
		element.removeChild(element.firstChild);
	}
}

var XML = {};
XML.getRootNode = function(responseXML){ 
	switch(responseXML.childNodes.length){
		case 1: return responseXML.childNodes[0]; break;
		case 2: return responseXML.childNodes[1]; break;
		default: return false; break;
	}
}


	/**
 * Function is for debugging.  
 * Will iterate over all properties of the given object and alert each to the UI.
 * @param {Object} obj Object to be debugged.
 */
function whatis (obj) {
	alert(obj)
	for(i in obj) {
		alert(i);	
	}
}	

/**
 * @constructor
 * This Class provides static methods to find the relative postion based on the current browser.
 */
var Dom = function() {
	
	
};
/**
  * Static Method finds the left most X-axis coordinate of the given object.
  * @param {Object} Object or String id of the DOM desired
  * @param topNode Object or String id to declare the top node to traverse too.
  * measurment will include the topNode
  * @return int - X-axis coordinate
  * @member Dom
  */  
Dom.getLeftX = function(id, topNode) {
	var obj = $(id);
	topNode = (topNode) ? $(topNode) : topNode;
  var curleft = 0;
  
	if (obj.offsetParent) {
		while (obj.offsetParent) {
			curleft += obj.offsetLeft
			obj = obj.offsetParent;
			if(topNode && obj == topNode)
			  break;
		}
	} else if (obj.x)
		curleft += obj.x;
	return curleft;
}
Dom.getLeftXAsPx = function(id, topNode) {
	return Dom.getLeftX(id, topNode) + "px";
}
/**
 * Static Method finds the right most X-axis coordinate of the given object.
 * @param {Object} id Object or Id of the DOM desired
 * @param topNode Object or String id to declare the top node to traverse too.
 * measurment will include the topNode
 * @return int - X-axis coordinate
 * @member Dom
 */
Dom.getRightX = function(id, topNode) {
	var obj = $(id);
  
  return Dom.getLeftX(obj, topNode) + obj.offsetWidth;
}
Dom.getRightXAsPx = function(id,topNode) {
	return Dom.getRightX(id,topNode) + "px";
}
 /**
 * Static Method finds the bottom most Y-axis coordinate of the given object.
 * @param {Object} Object or String id of the DOM desired
 * @param topNode Object or String id to declare the top node to traverse too.
 * measurment will include the topNode
 * @return int - Y-axis coordinate
 * @member Dom
 */ 
Dom.getBottomY = function(id,topNode) {
	var obj = $(id);
	  
	return Dom.getTopY(obj,topNode) + obj.offsetHeight;
}
Dom.getBottomYAsPx = function(id,topNode) {
	return Dom.getBottomY(id,topNode) + "px";
}
 /**
 * Static Method finds the top most Y-axis coordinate of the given object.
 * @param {Object} Object or String id of the DOM desired
 * @param topNode Object or String id to declare the top node to traverse too.
 * measurment will include the topNode
 * @return int - Y-axis coordinate
 * @member Dom
 */ 
Dom.getTopY = function(id,topNode) {
	var obj = $(id);
	topNode = $(topNode)
	var curtop = 0;
	var index = 0;
	if (obj.offsetParent) {
		while (obj.offsetParent) {
			index++;
			curtop += obj.offsetTop		  
			obj = obj.offsetParent;
			if(topNode && obj == topNode)
			  break;
		}
	} else if (obj.y)
	curtop += obj.y;
	return curtop;
}
Dom.getTopYAsPx = function(id,topNode) {
	return Dom.getTopY(id,topNode) + "px";
}
/**
 * Static Method finds the Left, Right, Top, Bottom positions of a certain object
 * and returns an object with 4 properties: <br />
 * .leftX <br />
 * .rightX <br />
 * .topY <br />
 * .bottomY <br />
 * @param {Object} id Object or String id of the DOM desired
 * @param topNode Object or String id to declare the top node to traverse too.
 * measurment will include the topNode
 * @return Object - with 4 properties .leftX, .rightX, .topY, bottomY
 * @member Dom
 */
Dom.getBoundries = function(id,topNode) {

	 var boundries = {
		leftX:   Dom.getLeftX(id,topNode),
		rightX:  Dom.getRightX(id,topNode),
		topY:    Dom.getTopY(id,topNode),
		bottomY: Dom.getBottomY(id,topNode),
		width: Dom.getRightX(id,topNode) - Dom.getLeftX(id,topNode),
		height: Dom.getBottomY(id,topNode) - Dom.getTopY(id,topNode)		
	}
	return boundries;	
}
Dom.isInBounds = function(id, x, y) {
	var rectangle = Dom.getBoundries(id);
	
	if(x<=rectangle.leftX || x>=rectangle.rightX)
	  return false;
	if(y<=rectangle.topY || y>=rectangle.bottomY)
	  return false;
	
	return true;
}
//TODO This code has been moved into prototype and should be deleted once we are
// sure there are no other users out there on the site.
function Node() {}

Node.ELEMENT_NODE = 1; 
Node.ATTRIBUTE_NODE = 2; 
Node.TEXT_NODE = 3; 
Node.CDATA_SECTION_NODE = 4; 
Node.ENTITY_REFERENCE_NODE = 5; 
Node.ENTITY_NODE = 6; 
Node.PROCESSING_INSTRUCTION_NODE = 7; 
Node.COMMENT_NODE = 8; 
Node.DOCUMENT_NODE = 9; 
Node.DOCUMENT_TYPE_NODE = 10; 
Node.DOCUMENT_FRAGMENT_NODE = 11; 
Node.NOTATION_NODE = 12;

Node.getFirstElementNode = function(elements) {
	// Hack for Safari's issue with converting to prototype's $A() for childNodes
	var array = new Array();
	for(var i=0; i<elements.length; i++) {
		array.push(elements[i]);
	}
	elements = $A(array);
	return elements.find(function(element) {	
      if(element.nodeType == Node.ELEMENT_NODE)
  		  return element;	
    });
}
Node.getAllElementNode = function(elements) {
   	// Hack for Safari's issue with converting to prototype's $A() for childNodes
    var array = new Array();
	for(var i=0; i<elements.length; i++) {
		array.push(elements[i]);
	}
	return $A(array).inject($(), function(elementNodes, element) {	
      if(element.nodeType == Node.ELEMENT_NODE)
  	    elementNodes.push(element);
      return elementNodes;
    })
}

var isFlashHidden = false;


function hideAllFlashInSafari() {
	if (!isFlashHidden && isMacBrowser()){
		var flashObjs = $A(document.getElementsByTagName('OBJECT'));
		
		flashObjs.each(function(flashObj) {
			flashObj.parentNode.style.visibility   = 'hidden';	
		})
		isFlashHidden = true;		
	}
}
function showAllFlashInSafari() {
	
	if (isFlashHidden){
		var flashObjs = $A(document.getElementsByTagName('OBJECT'));
		
		flashObjs.each(function(flashObj) {
			flashObj.parentNode.style.visibility = 'visible';		
		})		
		isFlashHidden = false;		
	}
}
function isMacBrowser() {
	if(navigator.userAgent.toLowerCase().indexOf('mac') > -1) {
		return true;	
	}
	return false;
}

var isSelectHidden = false;
var selectsFound;
function disableAllSelectElementsInIE() {
	if (!isSelectHidden && hideSelectElements()){
		
		if(!selectsFound) {
			var selectObjs = document.getElementsByTagName('SELECT');
			selectsFound = new Array();
			
			for(var i=0; i<selectObjs.length; i++) {
				selectsFound.push(selectObjs[i]);
			}
		}
		for(var i=0; i<selectsFound.length; i++) {
			selectsFound[i].style.visibility = 'hidden';
		}
		isSelectHidden = true;		
	}
}
function enableAllSelectElementsInIE() {
	
	if (isSelectHidden && selectsFound){
		for(var i=0; i<selectsFound.length; i++) {
				selectsFound[i].style.visibility = 'visible';	
		}
		isSelectHidden = false;
	}
		
}
function hideSelectElements() {
	if(document.all) {
		return true;	
	}
	return false;
}


function hideElementsForOverlays() {
	hideAllFlashInSafari();
	disableAllSelectElementsInIE();
}

function showElementsForOverlays() {
	showAllFlashInSafari();
	enableAllSelectElementsInIE();
}
function Address() {}

Address.getParameters = function() {
	var params = new Object;
	
	var search = window.location.search.replace('?','');
	
	if(search != '') {
		var items = search.split('&');
		
		for(var i=0; i<items.length; i++) {
			var keyValue = items[i].split('=');
			
			params[keyValue[0]] = keyValue[1];
		}
	}
	return params;
}

function MovieUtils() {}


MovieUtils.buildFlashMovie = function(destination, params, noPlugin) {
	 	
	 	if(Plugin.isInstalled('Flash') && Plugin.getVersion('Flash') >= 7) {
			var objectCall = 'AC_FL_RunContent(~params~);';
			var objectParams = '';
			
			for(param in params) {
				objectParams += "'" + param + "',";
				objectParams += "'" + params[param] + "',"
			}
			objectParams += "'" + destination + "'";
			objectCall = objectCall.replace('~params~', objectParams);
			
			eval(objectCall);
	 	
	 	}
	 	else if(noPlugin){
	 		MovieUtils.buildNoPlugin(destination,'flash', params['width'], params['height']);
	 		return;
	 	}
	 	
}
 
MovieUtils.buildViewPointMovie = function(destination,params,noPlugin) {
 	
 	if(Plugin.isInstalled('MetaStream')) {
	 	var vmp = new MTSPlugin(params.movie, params.width*1, params.height*1, params.broadcast, params.alt, params.contentType);
		$(destination).innerHTML = vmp.OutputStream();
		
		return vmp;
 	}
 	else if(noPlugin){
 		MovieUtils.buildNoPlugin(destination,'viewpoint', params['width'], params['height']);
 	}
}
MovieUtils.buildQuickTimeMovie = function(destination,params,noPlugin) {
 	
	if(Plugin.isInstalled('QuickTime') && Plugin.getVersionAsFloat('QuickTime') >= 5) {
	    //** Show QTVR **
		var newAnimation = '<OBJECT CLASSID="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" WIDTH=' + params.width*1 + ' HEIGHT=' + params.height*1 + ' CODEBASE="http://www.apple.com/qtactivex/qtplugin.cab">\n';
		newAnimation = newAnimation + '<PARAM name="SRC" VALUE="' + params.movie + '">\n';
		newAnimation = newAnimation + '<PARAM name="AUTOPLAY" VALUE="true">\n';
		newAnimation = newAnimation + '<PARAM name="CONTROLLER" VALUE="false">\n';
		newAnimation = newAnimation + '<EMBED SRC="' + params.movie + '" WIDTH=' + params.width*1 + ' HEIGHT=' + params.height*1 + ' AUTOPLAY="true" CONTROLLER="false" PLUGINSPAGE="http://www.apple.com/quicktime/download/">\n';
		newAnimation = newAnimation + '</EMBED>\n';
		newAnimation = newAnimation + '</OBJECT>\n';
		
		$(destination).innerHTML = newAnimation;
		return new Object();
   	}
   	else if(noPlugin) {
   		MovieUtils.buildNoPlugin('spinsGalleryViewer', 'quicktime');
   	}
 	
}
MovieUtils.buildMediaPlayerMovie = function(destination,params, noPlugin) {
	
	if(Plugin.isInstalled('Windows Media')) {
		
		var embed = '<object id="MediaPlayer" width=~width~ height=~height~ assid="CLSID:226BF52A52-394A-11D3-B153-00C04F79FAA6 standby="Loading Windows Media Player components..." type="application/x-oleobject">'
				  +  '<param name="url" value="~movie~">'
				  +  '<param name="showcontrols" value="true">'
				  +  '<param name="autoStart" value="true">'
				  +  '<PARAM NAME="uiMode" VALUE="mini">'
				  +  '<embed type="application/x-mplayer2" src="~movie~" name="MediaPlayer" width=~width~ height=~height~></embed>'
				  +  '</object>';
				  
		embed = embed.replace(/~movie~/g, params['movie']);
		embed = embed.replace(/~width~/g, params['width']);
		embed = embed.replace(/~height~/g, params['height']);
		
		$(destination).innerHTML = embed;
	}
	else if(noPlugin){
		MovieUtils.buildNoPlugin(destination,'mediaplayer', params['width'], params['height']);
	}	
	
}

MovieUtils.buildNoPlugin = function(destination, type,width, height) {
	
	var div = '<DIV style="~style~"><DIV>~content~</DIV></DIV>';
	var content = '';
	var style = 'padding-left:5px;padding-right:5px;';
	if(width) {
		style += 'width:'+ (width - 10) + 'px;'
	}
	if(height) {
		style += 'height:'+ (height - 10) + 'px;'
	}
	switch (type) {
		case 'flash':
			content = '<a href="' + MovieUtils.getPluginDownloadLink(type) + '" target="_blank">Download Plug-in</a>'
			break;
		case 'quicktime':			
			content = '<A href="' + MovieUtils.getPluginDownloadLink(type) + '" target="_blank">Download Plug-in</a>'
			break;
		case 'viewpoint':
			content = '<A href="' + MovieUtils.getPluginDownloadLink(type) + '" target="_blank" ></a>'
			break;
		case 'mediaplayer':
			content = '<A href="' + MovieUtils.getPluginDownloadLink(type) + '" target="_blank">Download Plug-in</a>'
			break;	
		default:
			break;
	}
	div = div.replace('~style~', style);
	div = div.replace('~content~', content);
	
	if(destination) {
		$(destination).innerHTML = div;
	}
	else {
		document.write(div);
	}
	
}
MovieUtils.getPluginDownloadLink = function(type) {
	
	switch (type) {
		case 'flash':
			return 'http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash';
			break;

		case 'quicktime':
			var url = 'http://www.apple.com/quicktime/download/';
			var version = 0;
			if(navigator.appVersion && navigator.appVersion.indexOf('MSIE') > -1) {
				var arVersion = navigator.appVersion.split("MSIE")
				var version = parseFloat(arVersion[1])
				
				if(version <= 5.5) {
					url =  'http://www.apple.com/support/downloads/quicktime652forwindows.html';	
				}
			}
			return url;
			break;

		case 'viewpoint':
			return 'http://www.viewpoint.com/cgi-bin/redirector.pl';
			break;

		case 'mediaplayer':
			return 'http://www.microsoft.com/windows/windowsmedia/player/download/download.aspx'
			break;

		default:
			break;
	}

}
function pluginPopup(url) {
	
}
function hasObject(parent, objectStr) {
	
	if(parent[objectStr])
		return true;
	else
		return false;
}
	/*
 * Site Constants  
 */
 menuTimeout = 250;
 IMG_ROOT = '/images/';
 IMG_SHARE = '/images/'
 var PAGE_ID = '';
 var MODEL_ID = '';
 var PAGE_LOAD = false;
/**
 * Function when called will find all Image tags and cache all images and any Over states that follows a given naming convention.
 * Such as xxxxxx.gif and xxxxxxOver.gif 
 * @type void
 */
 
DebugOnloadEventTiming = Class.create();
Object.extend(DebugOnloadEventTiming.prototype, {
	initialize: function() {
		this.startTime;
		this.endTime;
	},
	startTime: function() {
		this.startTime = new Date();
	},
	endTime: function() {
		this.endTime = new Date();
	},
	getElapseTime: function() {
		return this.endTime.getTime() - this.startTime.getTime();
	},
	printResults: function() {
		Debug.debug('onLoad Events Start Time:  ' + this.startTime.getDay() + '/' + this.startTime.getMonth() + '/' + this.startTime.getYear()
									   + ' ' + this.startTime.getHours() + ':' + this.startTime.getMinutes() + ':' + this.startTime.getSeconds()+ ':' + this.startTime.getMilliseconds() );
									   
		Debug.debug('onLoad Events End Time:  ' + this.endTime.getDay() + '/' + this.endTime.getMonth() + '/' + this.endTime.getYear()
									   + ' ' + this.endTime.getHours() + ':' + this.endTime.getMinutes() + ':' + this.endTime.getSeconds()+ ':' + this.endTime.getMilliseconds() );								   

		Debug.debug('onLoad Events Total Elapse Time:  ' + this.getElapseTime() + '(' + (this.getElapseTime()/1000) + ' seconds)');		

	}
});
var debugOnloadEventTiming = new DebugOnloadEventTiming();
 
OnPageLoadEvents = Class.create();
Object.extend(OnPageLoadEvents.prototype, {
	initialize: function(){
		this.actions = new Array();
		Event.observe(window, 'load', function(){this._executeActions()}.bind(this), false);
	},
	addAction: function(func) {
		
		this.actions.push(func);
	}, 
	_executeActions: function() {
		for(var i=0; i<this.actions.length; i++) {
			var action = this.actions[i];
			action.apply(window,[]);
		}
	}	
});
var onPageLoadEvents = new OnPageLoadEvents();

onPageLoadEvents.addAction(function() {debugOnloadEventTiming.startTime()});
onPageLoadEvents.addAction(function() {PAGE_LOAD = true;});




function debugOnloadStartTime() {
	var startTime
	
}

function cacheAllImages() {
	var cacheit = function(image, tag){
		if(image.src.indexOf(tag) == -1){
			var img = new Image();
			img.src = image.src.replace(new RegExp('(.*?)(\.(gif|png|jpg))', 'i'), '$1'+tag+'$2');
		}
	}
	$NL(document.getElementsByClassName('hover_Ov', document, 'img')).each(function(element){ 
		cacheit(element, 'Ov'); 
		Event.observe(element, 'mouseover', function(){swapOn(element, 'Ov'); });
		Event.observe(element, 'mouseout', function(){swapOut(element, 'Ov'); });
	});
	$NL(document.getElementsByClassName('hover_Over', document, 'img')).each(function(element){
		cacheit(element, 'Over'); 
		Event.observe(element, 'mouseover', function(){swapOn(element, 'Over'); });
		Event.observe(element, 'mouseout', function(){swapOut(element, 'Over'); });
	});
	$NL(document.getElementsByClassName('hover_On', document, 'img')).each(function(element){ cacheit(element, 'On') });
}
onPageLoadEvents.addAction(cacheAllImages);
//vent.observe(window, 'load', cacheAllImages, false);
/**
 * Function can be used to swap states of any image that follows a given naming convention. 
 * Such as xxxxxx.gif (off state) and xxxxxxOver.gif (on state).
 * You can use the function on an image itself like so:  
 * &gt;img src="./images/vn_btnAll.gif" onmouseOver="swapOver(this);" onmouseOut="swapOver(this);" &lt;
 * or you can add it to any element, like say, an A Href, like so:
 *  &lt;a href="./goSomeWhere.html" onmouseOver="swapOver('imageId');" onmouseOut="swapOver('imageId');" &lt; &gt;img src="..../" id="imageId" &lt; &gt;a&lt;
 * @param img String/Object
 * @type void
 */
function swapOver(img, suffix) {
	if(!suffix) { suffix = 'Over'; }
	var img = $(img);
	if(img.src.indexOf(suffix) > -1 || img.src == img.getAttribute('hover_src')) {
		if(img.getAttribute('nohover_src'))
			img.src = img.getAttribute('nohover_src');
		else
			img.src = img.src.replace(suffix, '');
	}
	else {
		if(img.getAttribute('hover_src')){
			img.setAttribute('nohover_src', img.src);
			img.src = img.getAttribute('hover_src');
		}
		else{
			var array = img.src.split('.');
			var src = "";		
			// Loop through all but the last
			for(var i=0; i<(array.length - 1); i++) {
				if(i!=0)
				 src += '.';
				src += array[i];
			}
			img.src = src + suffix + '.' + array[array.length-1];
		}
	}
}

function swapOn(img, suffix) {
	if(!suffix) { suffix = 'Over'; }
	var img = $(img);
	if(img.src.indexOf(suffix) > -1) {
		// Do nothing.
	}
	else if(img.getAttribute('hover_src')){
		img.src = img.getAttribute('hover_src');
	}
	else {
		var array = img.src.split('.');
		var src = "";		
		// Loop through all but the last
		for(var i=0; i<(array.length - 1); i++) {
			if(i!=0)
			 src += '.';
			src += array[i];
		}
		img.src = src + suffix + '.' + array[array.length-1];
	}
}

function swapOut(img, suffix) {
	if(!suffix) { suffix = 'Over'; }
	var img = $(img);
	if(img.src.indexOf(suffix) > -1 || img.src == img.getAttribute('hover_src')) {
		if(img.getAttribute('nohover_src'))
			img.src = img.getAttribute('nohover_src');
		else
			img.src = img.src.replace(suffix, '');
	}
}

function swapOut_click(event, img, suffix){
	if(!suffix) { suffix = 'Over'; }
	var img = $(img);
	if(img.src.indexOf(suffix) > -1) {
		if(!Dom.isInBounds(img, Event.pointerX(event), Event.pointerY(event))){
			img.src = img.src.replace(suffix, '');
		}
	}

}

Object.extend(Element, {
	removeChildren: function(element){
		while(element.childNodes.length){
			Element.remove(element.childNodes[0]);
		}
	}
});

/**
*	Replaces ~search_string~ with replace_string in input_string.
*	Returns result.
*/

Object.extend(String.prototype, {
	templateReplace: function(search_string, replace_string){
		//var regEx = new RegExp('~' + search_string + '~', 'g')
		var output = this.replace('~' + search_string + '~', replace_string);

		return output;
	}
});


function Delegate() {}
Delegate.create = function (o, f) {
	var a = new Array() ;
	var l = arguments.length ;
	for(var i = 2 ; i < l ; i++) a[i - 2] = arguments[i] ;
	return function() {
		var aP = [].concat(arguments, a) ;
		f.apply(o, aP);
	}
}

Tween = function(obj, prop, func, begin, finish, duration, suffixe){
	this.init(obj, prop, func, begin, finish, duration, suffixe)
}
var t = Tween.prototype;

t.obj = new Object();
t.prop='';
t.func = function (t, b, c, d) { return c*t/d + b; };
t.begin = 0;
t.change = 0;
t.prevTime = 0;
t.prevPos = 0;
t.looping = false;
t._duration = 0;
t._time = 0;
t._pos = 0;
t._position = 0;
t._startTime = 0;
t._finish = 0;
t.name = '';
t.suffixe = '';
t._listeners = new Array();	
t.setTime = function(t){
	this.prevTime = this._time;
	if (t > this.getDuration()) {
		if (this.looping) {
			this.rewind (t - this._duration);
			this.update();
			this.broadcastMessage('onMotionLooped',{target:this,type:'onMotionLooped'});
		} else {
			this._time = this._duration;
			this.update();
			this.stop();
			this.broadcastMessage('onMotionFinished',{target:this,type:'onMotionFinished'});
		}
	} else if (t < 0) {
		this.rewind();
		this.update();
	} else {
		this._time = t;
		this.update();
	}
}
t.getTime = function(){
	return this._time;
}
t.setDuration = function(d){
	this._duration = (d == null || d <= 0) ? 100000 : d;
}
t.getDuration = function(){
	return this._duration;
}
t.setPosition = function(p){
	this.prevPos = this._pos;
	var a = this.suffixe != '' ? this.suffixe : '';
	this.obj[this.prop] = Math.round(p) + a;
	this._pos = p;
	this.broadcastMessage('onMotionChanged',{target:this,type:'onMotionChanged'});
}
t.getPosition = function(t){
	if (t == undefined) t = this._time;
	return this.func(t, this.begin, this.change, this._duration);
};
t.setFinish = function(f){
	this.change = f - this.begin;
};
t.geFinish = function(){
	return this.begin + this.change;
};
t.init = function(obj, prop, func, begin, finish, duration, suffixe){
	if (!arguments.length) return;
	this._listeners = new Array();
	this.addListener(this);
	if(suffixe) this.suffixe = suffixe;
	this.obj = obj;
	this.prop = prop;
	this.begin = begin;
	this._pos = begin;
	this.setDuration(duration);
	if (func!=null && func!='') {
		this.func = func;
	}
	this.setFinish(finish);
}
t.start = function(){
	this.rewind();
	this.startEnterFrame();
	this.broadcastMessage('onMotionStarted',{target:this,type:'onMotionStarted'});
	this._is_animating = true;
	//alert('in');
}
t.rewind = function(t){
	this.stop();
	this._time = (t == undefined) ? 0 : t;
	this.fixTime();
	this.update();
}
t.fforward = function(){
	this._time = this._duration;
	this.fixTime();
	this.update();
}
t.update = function(){
	this.setPosition(this.getPosition(this._time));
	}
t.startEnterFrame = function(){
	this.stopEnterFrame();
	this.isPlaying = true;
	this.onEnterFrame();
}
t.onEnterFrame = function(){
	if(this.isPlaying) {
		this.nextFrame();
		setTimeout(Delegate.create(this, this.onEnterFrame), 0);
	}
}
t.nextFrame = function(){
	this.setTime((this.getTimer() - this._startTime) / 1000);
	}
t.stop = function(){
	this.stopEnterFrame();
	if(this._is_animating){
		this._is_animating = false;
		this.broadcastMessage('onMotionStopped',{target:this,type:'onMotionStopped'});
	}
}
t.stopEnterFrame = function(){
	this.isPlaying = false;
}

t.continueTo = function(finish, duration){
	this.begin = this._pos;
	this.setFinish(finish);
	if (this._duration != undefined)
		this.setDuration(duration);
	this.start();
}
t.resume = function(){
	this.fixTime();
	this.startEnterFrame();
	this.broadcastMessage('onMotionResumed',{target:this,type:'onMotionResumed'});
}
t.yoyo = function (){
	this.continueTo(this.begin,this._time);
}

t.addListener = function(o){
	this.removeListener (o);
	return this._listeners.push(o);
}
t.removeListener = function(o){
	var a = this._listeners;	
	var i = a.length;
	while (i--) {
		if (a[i] == o) {
			a.splice (i, 1);
			return true;
		}
	}
	return false;
}
t.broadcastMessage = function(){
	var arr = new Array();
	for(var i = 0; i < arguments.length; i++){
		arr.push(arguments[i])
	}
	var e = arr.shift();
	var a = this._listeners;
	var l = a.length;
	for (var i=0; i<l; i++){
		if(a[i][e])
		a[i][e].apply(a[i], arr);
	}
}
t.fixTime = function(){
	this._startTime = this.getTimer() - this._time * 1000;
}
t.getTimer = function(){
	return new Date().getTime() - this._time;
}

Tween.regularEaseIn = function(t,b,c,d){
	return c*(t/=d)*t + b;
	}
Tween.regularEaseOut = function(t,b,c,d){
	return -c *(t/=d)*(t-2) + b;
	}

Tween.regularEaseInOut = function(t,b,c,d){
	if ((t/=d/2) < 1) return c/2*t*t + b;
	return -c/2 * ((--t)*(t-2) - 1) + b;
	}
	
//OPACITY TWEEN
OpacityTween.prototype = new Tween();
OpacityTween.prototype.constructor = Tween;
OpacityTween.superclass = Tween.prototype;

function OpacityTween(obj,func,fromOpacity,toOpacity,duration){
	this.targetObject = obj;
	this.init(new Object(),'x',func,fromOpacity,toOpacity,duration);
}
var o = OpacityTween.prototype;
o.targetObject = {};
o.onMotionChanged = function(evt){
	var v = evt.target._pos;
	var t = this.targetObject;
	t.style['opacity'] = v / 100;
	t.style['-moz-opacity'] = v / 100;
	if(t.filters) t.filters.alpha['opacity'] = v;
}

//Sequence
function Sequence(){
	this.children = new Array();
	this.currentChildIndex = 0;
	this._listeners = new Array();
	this.nextObject = new Object();
	this.addListener(this);
}
var s = Sequence.prototype;
s.addChild = function(tween){
	this.children.push(tween)
}
s.removeChild = function(tween){
	var a = this.children;	
	var i = a.length;
	while (i--) {
		if (a[i] == tween) {
			a.splice (i, 1);
			return true;
		}
	}
	return false;
}
s.start = function(){
	this.rewind();
	this.play();
	this.broadcastMessage('onMotionStarted',{target:this,type:'onMotionStarted'});
}
s.next = function(){
	this.children[this.currentChildIndex].removeListener(this.nextObject);
	if(this.currentChildIndex < this.children.length-1){
		this.currentChildIndex++;
		this.play();
	}
	else{
		this.stop();
		this.broadcastMessage('onMotionFinished',{target:this,type:'onMotionFinished'});
	}
}
s.play = function(){
	this.nextObject = new Object();
	this.nextObject.onMotionFinished = Delegate.create(this, this.next);
	this.children[this.currentChildIndex].addListener(this.nextObject);
	this.children[this.currentChildIndex].start();
}
s.stop = function(){
	this.children[this.currentChildIndex].stop();
	this.broadcastMessage('onMotionStopped',{target:this,type:'onMotionStopped'});
}
s.rewind = function(){
	this.children[this.currentChildIndex].removeListener(this.nextObject);
	this.currentChildIndex = 0;
	for(var i = 0; i < this.children.length; i++){
		this.children[i].rewind();
	}
}
s.fforward = function(){
	this.children[this.currentChildIndex].removeListener(this.nextObject);
	for(var i = 0; i < this.children.length; i++){
		this.children[i].fforward();
	}
	this.currentChildIndex = this.children.length - 1;
}
s.resume = function(){
	this.children[this.currentChildIndex].resume();
	this.broadcastMessage('onMotionResumed',{target:this,type:'onMotionStopped'});
}
s.addListener = function(o){
	this.removeListener (o);
	return this._listeners.push(o);

}
s.removeListener = function(o){
	var a = this._listeners;	
	var i = a.length;
	while (i--) {
		if (a[i] == o) {
			a.splice (i, 1);
			return true;
		}
	}
	return false;
}
s.broadcastMessage = function(){
	var arr = new Array();
	for(var i = 0; i < arguments.length; i++){
		arr.push(arguments[i])
	}
	var e = arr.shift();
	var a = this._listeners;
	var l = a.length;
	for (var i=0; i<l; i++){
		if(a[i][e])
		a[i][e].apply(a[i], arr);
	}
}

/*//////////////////////////
	PARALLEL
///////////////////////////*/
function Parallel(){
	this.children = new Array();
	this.numChildren = 0;
	this._listeners = new Array();
	this.addListener(this);
	this.isPlaying = false;
}
var s = Parallel.prototype;
s.endObject = new Object();
s.addChild = function(tween){
	this.children.push(tween)
	this.numChildren++;
}
s.start = function(){
	this.play();
	this.broadcastMessage('onMotionStarted', {target:this, type:'onMotionStarted'});
}
s.play = function(){
	for(var u = 0; u < this.numChildren; u++){
		if(u==(this.numChildren-1)){
			this.endObject = new Object();
			this.endObject.onMotionFinished = Delegate.create(this, this.end);
			this.children[u].addListener(this.endObject);
		}
		this.children[u].start();
	}
	this.isPlaying = true;
}

s.end = function(){
	this.children[this.numChildren-1].removeListener(this.endObject);
	this.broadcastMessage('onMotionFinished', {target:this, type:'onMotionFinished'});
	this.isPlaying = false;
}
s.stop = function(){
	this.enumAction('stop');
	this.broadcastMessage('onMotionStopped', {target:this, type:'onMotionStopped'});
	this.isPlaying = false;
}
s.rewind = function(){
	this.enumAction('rewind');
	}
s.fforward = function(){
	this.enumAction('fforward');
	}
s.resume = function(){
	this.enumAction('resume');
	this.broadcastMessage('onMotionResumed', {target:this, type:'onMotionResumed'});
	}
s.yoyo = function(){
	this.enumAction('yoyo');
	}


s.enumAction = function(action){
	for(var u = 0; u < this.numChildren; u++){
		this.children[u][action]();
	}
}

s.addListener = function(o){
	this.removeListener (o);
	return this._listeners.push(o);

}
s.removeListener = function(o){
	var a = this._listeners;	
	var i = a.length;
	while (i--) {
		if (a[i] == o) {
			a.splice (i, 1);
			return true;
		}
	}
	return false;
}
s.broadcastMessage = function(){
	var arr = new Array();
	for(var i = 0; i < arguments.length; i++){
		arr.push(arguments[i])
	}
	var e = arr.shift();
	var a = this._listeners;
	var l = a.length;
	for (var i=0; i<l; i++){
		if(a[i][e])
		a[i][e].apply(a[i], arr);
	}
}
	/* Header navigation */

/* Global variables */
var hideMeDelay		= 250; // Submenu close time in miliseconds-->
var subMenuObj 		= "";
var currentButton = "";

/* Add dynamically onclick event to the header buttons */
//onPageLoadEvents.addAction(addOnClickHandlers);
//vent.observe(window, 'load', addOnClickHandlers);
function addOnClickHandlers(){
	var headerDiv = $('hn_menu');	
	var href = headerDiv.getElementsByTagName("a");	
		href[0].onmouseover = function(){dropDownMenu(this,'hn_btnFS','hn_subFs')};
		href[0].onmouseout  = function(){delayHideSub('hn_btnFS')};
		href[1].onmouseover = function(){dropDownMenu(this,'hn_btnCPO','hn_subCpo')};
		href[1].onmouseout  = function(){delayHideSub('hn_btnCPO')};
		href[2].onmouseover = function(){dropDownMenu(this,'hn_btnOwn','hn_subOwners')};
		href[2].onmouseout  = function(){delayHideSub('hn_btnOwn')};
		href[3].onmouseover = function(){dropDownMenu(this,'hn_btnAL','hn_subAbout')};
		href[3].onmouseout  = function(){delayHideSub('hn_btnAL')};
}
/* End add onclick */

function dropDownMenu(obj, thisButton, thisSub){	/* Starting point when a user hover over a menu button */
	navigationManager.hideNavigation();    
	if (window.event){ /* IE */
		event.cancelBubble=true; /* IE-Bubbling is disabled for this event, preventing the next event handler in the hierarchy from receiving the event*/
		clearHideSub();
		if (typeof subMenuObj!="undefined" && subMenuObj!=""){subMenuObj.style.visibility="hidden";} /* Hide last sub between button switch */
		if (currentButton!=""){ swapOver(currentButton); } /* Switch last button to normal state */
		subMenuObj=document.getElementById? document.getElementById(thisSub) : thisSub; /* Define new drop down menu object */
	}
	else{ /* w3c */
		clearHideSub();
		if (typeof subMenuObj!="undefined" && subMenuObj!=""){subMenuObj.style.visibility="hidden";}
		if (currentButton!=""){swapOver(currentButton);}
		subMenuObj=document.getElementById? document.getElementById(thisSub) : thisSub;
	}

	showHideSub(subMenuObj.style, thisButton);

	return clickReturnValue();
}

function clearHideSub(){ /* Clears the counter, hide any sub menus opened, and allows other sub menus to re-use it */
	if (typeof delayHide!="undefined"){clearTimeout(delayHide);}
}

function showHideSub(obj, thisButton){
	currentButton=thisButton; /* Assign the new current button globally */
	obj.visibility="visible"; /* Show the sub menu related to the current button */
	swapOver(thisButton);/*return setImage(thisButton,"hilite"); /* Hilite the onmouseovered menu button */
}
function clickReturnValue(){ /* Fix older browser issues */
	return false;
}
function delayHideSub(btnRef){ /* Sets a delay for hiding both "on state" button and its sub */
	delayHide=setTimeout("hideSub('" + btnRef + "')",hideMeDelay);
}
function hideSub(btnRef){ /* Hide current button and its related sub menu */
	if (typeof subMenuObj!="undefined" && subMenuObj!=""){
		currentButton = "";
		subMenuObj.style.visibility = "hidden";
		swapOver(btnRef); /*return setImage(btnRef,"normal");*/
	}
}

function initOnStates(){/* Function that sets On State to the current section button */
	switch(MODEL_ID){
		case 'About':
			$('hn_btnAL').setAttribute('hover_src', $('hn_btnAL').src.replace(new RegExp('(.*)(\.gif)', 'i'), '$1Over$2'));/* Sets the button name to hn_btnALOver */
			$('hn_btnAL').src = $('hn_btnAL').src.replace(new RegExp('(.*)(\.gif)', 'i'), '$1On$2');/* Sets the button name to hn_btnALOn */
			break;
		case 'Owners':
			$('hn_btnOwn').setAttribute('hover_src', $('hn_btnOwn').src.replace(new RegExp('(.*)(\.gif)', 'i'), '$1Over$2'));/* Sets the button name to hn_btnALOver */
			$('hn_btnOwn').src = $('hn_btnOwn').src.replace(new RegExp('(.*)(\.gif)', 'i'), '$1On$2');/* Sets the button name to hn_btnOwnOn */
			break;
		case 'CPO':
			$('hn_btnCPO').setAttribute('hover_src', $('hn_btnCPO').src.replace(new RegExp('(.*)(\.gif)', 'i'), '$1Over$2'));/* Sets the button name to hn_btnCPOOver */
			$('hn_btnCPO').src = $('hn_btnCPO').src.replace(new RegExp('(.*)(\.gif)', 'i'), '$1On$2');/* Sets the button name to hn_btnCPOOn */
			break;
		case 'Dealers':
			$('hn_FD').src = $('hn_FD').src.replace(new RegExp('(.*)(\.gif)', 'i'), '$1On$2');/* Sets the button name to hn_btnFDOn */
			break;
	}
}
onPageLoadEvents.addAction(initOnStates);
//vent.observe(window, 'load', initOnStates);
/* End Header Navigation */
	/* Footer navigation */

function checkFooterState(){
	var urlRoot = window.LEXUS_ROOT_URL || '';
	
	switch(MODEL_ID){
		case "Privacy":
			$("fnBtnPrivacy").firstChild.firstChild.src = urlRoot + '/lexus-share/images/nav/footerNav/fn_btnPrivacyOn.gif';
		break;
		case "AboutThisSite":
			$("fnBtnAbout").firstChild.firstChild.src = urlRoot + '/lexus-share/images/nav/footerNav/fn_btnAboutOn.gif';
		break;		
		case "Contact":
			$("fnBtnContact").firstChild.firstChild.src = urlRoot + '/lexus-share/images/nav/footerNav/fn_btnContactOn.gif';
		break;
		case "FAQ":
			$("fnBtnFAQ").firstChild.firstChild.src = urlRoot + '/lexus-share/images/nav/footerNav/fn_btnFAQOn.gif'
		break;
		default: ;//do nothing
	}
}
function addFooterEvents() {
	document.getElementsByClassName('', 'ftNav', 'DIV')
	
}

onPageLoadEvents.addAction(checkFooterState);
//vent.observe(window, 'load', checkFooterState);
/* End Header Navigation */
	//v1.0
//Copyright 2006 Adobe Systems, Inc. All rights reserved.
function AC_AddExtension(src, ext)
{
  if (src.indexOf('?') != -1)
    return src.replace(/\?/, ext+'?'); 
  else
    return src + ext;
}

function AC_Generateobj(objAttrs, params, embedAttrs,destination) 
{ 
  var str = '<object ';
  for (var i in objAttrs) {
   	if(i != 'name') {
    	str += i + '="' + objAttrs[i] + '" ';
   	}
  }
  str += '>';
  for (var i in params) {
    if(i != destination)
    	str += '<param name="' + i + '" value="' + params[i] + '" /> ';
  }
  str += '<embed ';
  for (var i in embedAttrs) {
  	if(i != destination) {
    	str += i + '="' + embedAttrs[i] + '" ';
  	}
  }
  str += ' ></embed></object>';

  if($(destination)) {
  	$(destination).innerHTML = str;
  }
  else {
  	document.write(str);
  }
}

function AC_FL_RunContent(){
  var ret = 
    AC_GetArgs
    (  arguments, ".swf", "movie", "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
     , "application/x-shockwave-flash"
    );
  AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs, arguments[arguments.length -1]);
}

function AC_SW_RunContent(){
  var ret = 
    AC_GetArgs
    (  arguments, ".dcr", "src", "clsid:166B1BCA-3F9C-11CF-8075-444553540000"
     , null
    );
  AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}

function AC_GetArgs(args, ext, srcParamName, classid, mimeType){
  var ret = new Object();
  ret.embedAttrs = new Object();
  ret.params = new Object();
  ret.objAttrs = new Object();
  for (var i=0; i < args.length; i=i+2){
    var currArg = args[i].toLowerCase();    

    switch (currArg){	
      case "classid":
        break;
      case "pluginspage":
        ret.embedAttrs[args[i]] = args[i+1];
        break;
      case "src":
      case "movie":	
        args[i+1] = AC_AddExtension(args[i+1], ext);
        ret.embedAttrs["src"] = args[i+1];
        ret.params[srcParamName] = args[i+1];
        break;
      case "onafterupdate":
      case "onbeforeupdate":
      case "onblur":
      case "oncellchange":
      case "onclick":
      case "ondblClick":
      case "ondrag":
      case "ondragend":
      case "ondragenter":
      case "ondragleave":
      case "ondragover":
      case "ondrop":
      case "onfinish":
      case "onfocus":
      case "onhelp":
      case "onmousedown":
      case "onmouseup":
      case "onmouseover":
      case "onmousemove":
      case "onmouseout":
      case "onkeypress":
      case "onkeydown":
      case "onkeyup":
      case "onload":
      case "onlosecapture":
      case "onpropertychange":
      case "onreadystatechange":
      case "onrowsdelete":
      case "onrowenter":
      case "onrowexit":
      case "onrowsinserted":
      case "onstart":
      case "onscroll":
      case "onbeforeeditfocus":
      case "onactivate":
      case "onbeforedeactivate":
      case "ondeactivate":
      case "type":
      case "codebase":
        ret.objAttrs[args[i]] = args[i+1];
        break;
      case "width":
      case "height":
      case "align":
      case "vspace": 
      case "hspace":
      case "class":
      case "title":
      case "accesskey":
      case "name":
      case "id":
      case "tabindex":
        ret.embedAttrs[args[i]] = ret.objAttrs[args[i]] = args[i+1];
        break;
      default:
        ret.embedAttrs[args[i]] = ret.params[args[i]] = args[i+1];
    }
  }
  ret.objAttrs["classid"] = classid;
  if (mimeType) ret.embedAttrs["type"] = mimeType;
  return ret;
}

	//v1.1
//Copyright 2006 Adobe Systems, Inc. All rights reserved.
function AC_AX_RunContent(){
  var ret = AC_AX_GetArgs(arguments);
  AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}

function AC_AX_GetArgs(args){
  var ret = new Object();
  ret.embedAttrs = new Object();
  ret.params = new Object();
  ret.objAttrs = new Object();
  for (var i=0; i < args.length; i=i+2){
    var currArg = args[i].toLowerCase();    

    switch (currArg){	
      case "pluginspage":
      case "type":
      case "src":
        ret.embedAttrs[args[i]] = args[i+1];
        break;
      case "data":
      case "codebase":
      case "classid":
      case "id":
      case "onafterupdate":
      case "onbeforeupdate":
      case "onblur":
      case "oncellchange":
      case "onclick":
      case "ondblClick":
      case "ondrag":
      case "ondragend":
      case "ondragenter":
      case "ondragleave":
      case "ondragover":
      case "ondrop":
      case "onfinish":
      case "onfocus":
      case "onhelp":
      case "onmousedown":
      case "onmouseup":
      case "onmouseover":
      case "onmousemove":
      case "onmouseout":
      case "onkeypress":
      case "onkeydown":
      case "onkeyup":
      case "onload":
      case "onlosecapture":
      case "onpropertychange":
      case "onreadystatechange":
      case "onrowsdelete":
      case "onrowenter":
      case "onrowexit":
      case "onrowsinserted":
      case "onstart":
      case "onscroll":
      case "onbeforeeditfocus":
      case "onactivate":
      case "onbeforedeactivate":
      case "ondeactivate":
        ret.objAttrs[args[i]] = args[i+1];
        break;
      case "width":
      case "height":
      case "align":
      case "vspace": 
      case "hspace":
      case "class":
      case "title":
      case "accesskey":
      case "name":
      case "tabindex":
        ret.embedAttrs[args[i]] = ret.objAttrs[args[i]] = args[i+1];
        break;
      default:
        ret.embedAttrs[args[i]] = ret.params[args[i]] = args[i+1];
    }
  }
  return ret;
}

			/**
		 * This is the controller class for the Secondary (side) Navigation section.
		 * There will always be exactly one of these objects available, so
		 * I'm instanciating it as the class is created.  This may change in the future.
		 */
		var SecondaryNav = new function (){ 
		
			var root_element;
			var sections;
			var expanders;
			var model_id;
			var page_id;
			var ignore_page_id;
			
			var accordian_func;
			
			var open_section;
			
			/**
			 * Initialize our secondary navigation controller object
			 */
			this.init = function(event){
				/**
				 * Gather referenced to important elements
				 */
				this.root_element = $('sn_wrapper');
				this.sections = document.getElementsByClassName('subsection', this.root_element);
				this.expanders = document.getElementsByClassName('expander', this.root_element);
				
				/**
				 * Get the model id and apply it to the root element.
				 */
				Try.these(
					function(){
						this.model_id = MODEL_ID;
					}.bind(this),
					function(){
						this.model_id = false;
					}
				);
				
				Try.these(
					function(){
						this.page_id = PAGE_ID;
					}.bind(this),
					function(){
						this.page_id = '';
					}.bind(this)
				);
				
				Try.these(
					function(){
						this.ignore_page_id = IGNORE_PAGE_ID;
					},
					function(){
						this.ignore_page_id = false;
					}
				);
				
			
				if(this.model_id){
					Element.addClassName(this.root_element, this.model_id);

//					var head_img = $('sn_imgHeader');
//					head_img.src = head_img.src.replace(new RegExp('.*?\#(.*)'), '$1').replace('MODEL', this.model_id);
//					head_img.setAttribute('alt', head_img.alt.templateReplace('model', this.model_id));
				}

				/**
				 * Set initial open section
				 * Look for a section that has the classname "open"
				 */
				for(i in this.sections){
					if(this.sections[i].className){
						if(Element.hasClassName(this.sections[i].parentNode, 'open')){
							if(this.page_id != 'CLOSEALL'){
								this.open_section = this.sections[i].parentNode;
								if(document.all){
									Element.removeClassName(this.open_section, 'open');
									Element.addClassName(this.open_section, 'open');
								}
							}
							else{
								Element.removeClassName(this.sections[i].parentNode, 'open');
							}
							break;
						}
					}
				}
								
				/**
				 * Setup an onclick event for the expanders so we can change the icon.
				 * Also, setup mouseover hovers for images
				 */
				for (i in this.expanders){
					//Event.observe(this.expanders[i], 'click', this.expand_onclick.bindAsEventListener(this), false);
					Event.observe(this.expanders[i], 'mouseover', function(){swapOn(this.firstChild, 'Ov')}.bind(this.expanders[i]));
					Event.observe(this.expanders[i], 'mouseout', function(){swapOut(this.firstChild, 'Ov')}.bind(this.expanders[i]));
					Event.observe(this.expanders[i], 'click', function(event){swapOut_click(event, this.firstChild, 'Ov')}.bindAsEventListener(this.expanders[i]));
				}
				
				document.getElementsByClassName('section_header', this.root_node, 'a').each(function(element){
					if(!Element.hasClassName(element, 'nohover')){
						Event.observe(element, 'mouseover', function(){swapOn(this.firstChild, 'Ov')}.bind(element));
						Event.observe(element, 'mouseout', function(){swapOut(this.firstChild, 'Ov')}.bind(element));
						Event.observe(element, 'click', function(event){swapOut_click(event, this.firstChild, 'Ov')}.bindAsEventListener(element));
					}
				});
				
				/**
				 * Remove focus from an element after it's clicked so
				 * it doesn't appear with that dotted box around it
				 *
				 * Also, replace the template string %model% with the name of the 
				 * current model page.
				 *
				 * Also, set the onstate of the current page from the name property
				 */
				var links = this.root_element.getElementsByTagName('a');
				for (var i = 0; i < links.length; ++i){
					if(links[i].href){
//						if(this.model_id)
//							links[i].href = links[i].href.templateReplace('model', this.model_id);
						
						Event.observe(links[i], 'click', this.link_onclick.bindAsEventListener(this));
						
						if(!this.ignore_page_id){
							if(this.page_id.length && links[i].name == this.page_id){
								Element.addClassName(links[i], 'onstate');
							
								//Find the section that should be open and open it
								var n = links[i].parentNode;
								while(n.parentNode){
									if(Element.hasClassName(n, 'section')){
										if(this.model_id != 'About' && this.model_id != 'FCV' && this.model_id != 'Dealers' && this.model_id != 'CPO' )
											this.setOpenSection(n, false, true);
										break;
									}
									else{
										n = n.parentNode;
									}
								}
							}
						}
						
						if(Element.hasClassName(links[i], 'section_header')){
							if(links[i].name == this.page_id){
								var img = $NL(links[i].childNodes).elements().first();
								img.src = img.src.replace(new RegExp('(.*)(.gif)', 'i'), '$1On$2');
								//img.setAttribute('hover_src', img.src.replace(new RegExp('(.*)On(.gif)', 'i'), '$1Ov$2'));
								img.setAttribute('hover_src', img.src);
							}
						}
					}
				}
				
				/**
				 * Setup utility list
				 */
				
				if($('topUtility_list')){
					
					//Do template replacement in alt tags
//					$NL($('topUtility_list').getElementsByTagName('img')).each(function(element){
//						element.setAttribute('alt', element.getAttribute('alt').templateReplace('model', this.model_id));
//					}.bind(this));
				
					//Set onstate
					$NL($('topUtility_list').getElementsByTagName('a')).each(function(element){
						if(element.name == this.page_id){
							Element.addClassName(element, 'onstate');
						}
					}.bind(this));
				
				}
				
				/**
				 * Setup onhover event for the utility list part 2
				 */
				if($('botUtility_list')){
					var links = $('botUtility_list').getElementsByTagName('a');
					for(var i = 0; i < links.length; ++i){
						Event.observe(links[i], 'mouseover', function(){swapOn(this.firstChild, 'Ov')}.bind(links[i]));
						Event.observe(links[i], 'mouseout', function(){swapOut(this.firstChild, 'Ov')}.bind(links[i]));
					}
				}
				
				//This is disabled because there is nothing in the init_onload function
				//so it would be a useless function call.
				//onPageLoadEvents.addAction(this.init_onload.bind(this);
				//vent.observe(window, 'load', this.init_onload.bind(this));

			}
			
			/**
			 * Second stage of init function.  Called automatically after page is finished loading.
			 */
			
			this.init_onload = function(){
				// Currently does nothing
			}
			
			/**
			 * Handles onclick event on expander elements.  Sets the new open
			 * section to class "open" which, as defined in the css will have
			 * a the - icon instead of the + icon.
			 */
			this.expand_onclick = function(event){
				/**
				 * Get the clicked element from the event
				 * for some reason, this does not return the 'a' tag
				 * instead, it returns whatever you click on
				 * (an image or list item or whatever)
				 */
				var element = Event.element(event);

				/**
				 * Get the section li from the clicked element
				 */
				if(Element.hasClassName(element.parentNode, 'section'))
					var section = element.parentNode;
				else
					var section = element.parentNode.parentNode;
				
				this.setOpenSection(section, true);
			}
			
			/**
			 * Sets which section should be open.
			 */
			this.setOpenSection = function(section, toggle, no_tween){
				
				//Possible fix for IE jumble bug
/*				if(!PAGE_LOAD){
					onPageLoadEvents.addAction(function(){
						if(document.all){
							Element.removeClassName(this.open_section, 'open');
							Element.addClassName(this.open_section, 'open');
						}
					}.bind(this));
				}
*/				
				no_tween =  true; //Uncomment this line to disable animations
//				var seq = new Sequence();
				
				/**
				 * Unset the 'open' class from all elements
				 */
				for(i in this.sections){
					if(this.sections[i].className && Element.hasClassName(this.sections[i].parentNode, 'open')){
						if(!no_tween){
							ce = this.sections[i];
							var close_height = ce.offsetHeight;
							var close_tween = new Tween(ce.style,'height', Tween.regularEaseOut, close_height, 0, .3, 'px');
							var j = i;

							close_tween.onMotionStopped = function(){ 
								ce.style.height = ''; 
								Element.removeClassName(this.sections[j].parentNode, 'open'); 
							}.bind(this);

							seq.addChild(close_tween);
						}
						else{
							Element.removeClassName(this.sections[i].parentNode, 'open');
						}
					}
				}
				
				/**
				 * Set top 'open' class to the open section
				 */
				if(this.open_section != section || !toggle){
					if(!no_tween){
						var e = $NL(section.childNodes).elements().detect(function(element){ return Element.hasClassName(element, 'subsection') });
						Element.addClassName(section, 'open');
						var open_height = e.scrollHeight;
						Element.removeClassName(section, 'open');
						var open_tween = new Tween(e.style,'height', Tween.regularEaseOut, 0, open_height, .3, 'px');
						
						open_tween.onMotionStopped = function(){ 
							e.style.height = ''; 
						};
						
						open_tween.onMotionStarted = function(){
							Element.addClassName(section, 'open');
							this.open_section = section;						
						}.bind(this);
						
						seq.addChild(open_tween);
					}
					else{
						Element.addClassName(section, 'open');
						this.open_section = section;
						if(document.all){
							Element.removeClassName(section, 'open');
							Element.addClassName(section, 'open');
						}
					}
				}
				else{
					this.open_section = null;
				}
				
//				if(seq.children.length)
//					seq.start();
			}
			
			/**
			 * Removes focus from links after they're clicked
			 * to avoid that nasty dotted line in FireFox.
			 */
			this.link_onclick = function(event){
				var element = Event.element(event);
				element.blur();
			}
			
		}

	/**
 * @fileoverview  vehicleNavigation.js contains all components for the Vehicle Navigation menu.
 * @author Aaron J Pedersen (apederson@dhapdigital.com)
 * <br/> <br/>
 * Documentation is generated by JSDoc (http://jsdoc.sourceforge.net/)
 */

/**
 * Class holds the needed information for a paticular Category of Cars.<br/>
 * Example: Luxury Sedans, which contain LS, GS, ES, and IS models of cars.
 * @constructor
 */
function VehicleCategory(id, name) {
	this.id = id;
	this.name = name;
	this.models = $A();
	this.domHotSpot = null;
	this.domNavigation = null;
	this.domOverlay = null;

  /**
   * Method adds a VehicleModel Object to an array.   
   * @param model VehicleModel Model Object representing a Lexus Model
   * @type void
   * @member VehicleCategory
   */
  this.addModel = function(model) {
  	  model.categoryId = this.id;
    	this.models.push(model);
  }
   /**
   * Method returns a VehicleModel Object from the current array. 
   * @param model VehicleModel Model Object representing a Lexus Model
   * @type VehicleModel
   * @member VehicleCategory
   */
  this.getModel = function(key) {
  	return this.models.find(function(model){
  		if(model.id.indexOf(key) >= 0)
  		  return model;
  	})
  }
}
VehicleCategory.prototype.toString = function() {
	return "Category (Object)";
}
/** Type Declarations Class/Instance **/
VehicleCategory.type = 'Category';
VehicleCategory.prototype.type = 'Category';
/*******************************************************************************/
/**
 * Class holds the needed info for a paticular Model of Car.<br/>
 * Example: LS.
 * @constructor
 */
function VehicleModel(id, name, startingPrice, endingPrice,code) {
	this.id = id.toLowerCase();
	this.name = name;
	this.startingPrice = startingPrice;
	this.endingPrice = endingPrice;
	this.code = code;
	this.categoryId = 0;
	this.features = $A();
	this.domHotSpot = null;
	this.domNavigation = null;
	this.domOverlay = null;
	
	/**
   * Method adds a VehicleFeature Object to an array.
   * @param feature VehicleFeature VehicleFeature Object representing a Lexus Model Feature
   * @type void
   * @member VehicleModel
   */
	this.addFeature = function(feature) {
		this.features.push(feature);
	}
	/**
	 * Method returns a string representing the price of the Lexus Model
	 * @type String
	 * @member VehicleModel
	 */
	this.getPriceAsString = function() {
		return "Starting at " + this.startingPrice + 
		       ((this.endingPrice) ? " - " + this.endingPrice : "" ) + ' ';
	}
}
VehicleModel.prototype.toString = function() {
	return "Model (Object)";
}
/** Type Declarations Class/Instance **/
VehicleModel.type = 'Model';
VehicleModel.prototype.type = 'Model';

/*******************************************************************************/

/**
 * Class holds current State of the navigation<br/>
 * @constructor
 */
function VehicleNavigationState () {
	this._navShowing = false;
	this._categoryShowing = false;
	this._modelShowing = false;
	this._currentActive = null;

	/**
	 * @member VehicleNavigationState
	 * Method sets the current state of the navigation.
	 * If false, method will also update categoryShowing and modelShowing attributes
	 * @param boolean - state True/False 
	 */
	this.setNavShowing = function (state) {
		this._navShowing = state;
		
		// update dependencies if false
		if(!state) {
			this.setCategoryShowing(false);
			this.setModelShowing(false);
			this.setCurrentActive(null);
		}
	}
	/**
	 * 
	 * Method sets categoryShowing attribute, to indicate if a Category Navigation is current visible.
	 * If True, will also set _navShowing to true and will set _modelShowing to false, since only a
	 * model or category can be shown at any point.
	 * @param boolean - state True/False 
	 * @member VehicleNavigationState
	 */
	this.setCategoryShowing = function (state) {
		this._categoryShowing = state;
		
		// update dependencies if true
		if(state) {
			this.setNavShowing(true);
			this.setModelShowing(false);
		}
	}
	/**
	 * Method sets modelShowing attribute, to indicate if a Model Navigation is current visible.
	 * If True, will also set _navShowing to true and will set _categoryShowing to false, since only a
	 * model or category can be shown at any point.
	 * @param boolean - state True/False 
	 * @member VehicleNavigationState
	 */
	this.setModelShowing = function (state) {
		this._modelShowing = state;
		
		// update dependencies if true
		if(state) {
			this.setNavShowing(true);
			this.setCategoryShowing(false);
		}
	}
  /**
	 * Method sets the current object that is active on the vehicle navigation
	 * @param object - Category or Model Object
	 * @member VehicleNavigationState
	 */
	this.setCurrentActive = function(object) {
		this._currentActive = object;
		
		if(!object)
		  return;
	  if(object.type == VehicleCategory.type) {
	  	this.setCategoryShowing(true);	  	
	  }
	  else {
	  	this.setModelShowing(true);	  	
	  }
	}
  /**
	 * Method gets the current object that is active on the vehicle navigation
	 * @type object - Category or Model Object
	 * @member VehicleNavigationState
	 */
	this.getCurrentActive = function() {
		return this._currentActive;		
	}
	/**
	 * Method returns true/false depending on if a vehicle navigation is current showing
	 * @type boolean
	 * @member VehicleNavigationState
	 */
	this.isNavShowing = function() {
		return this._navShowing;
	}
	/**
	 * Method returns true/false depending on if a vehicle Category navigation is current showing
	 * @type boolean
	 * @member VehicleNavigationState
	 */
	this.isCategoryShowing = function() {
		return this._categoryShowing;
	}
	/**
	 * Method returns true/false depending on if a vehicle model navigation is current showing
	 * @type boolean
	 * @member VehicleNavigationState
	 */
	this.isModelShowing = function() {
		return this._modelShowing;
	}
}
/*******************************************************************************/
/**
 * Class acts as the controller to handle all interaction of the navigation bar<br/>
 * @constructor
 */
function VehicleNavigationManager() {
	this.categories = $A();
	this.navState = new VehicleNavigationState();
    this.navView = new VehicleNavigationView();
	this.timeOutId;
	this.timeOutSet = false;
	this.ajaxQueue;
	this.imageCache = new Array();
	
	this.backdrop;	

	/**
	 * Method will be called on instantiation of this class.
	 * Exact features are TBD
	 * @member VehicleNavigationManager
	 */
	this.init = function() {
	this._setOnState();	
      
	 // Add onload event
	 onPageLoadEvents.addAction(this.init_onload.bindAsEventListener(this));
	 Event.observe(window, 'unload', Event.unloadCache);
	}
	this.init_onload = function() {
	  this._setupNavigation();
	  this._cacheMenuImages();
      this._preLoadMenus();  
	}
	/**
   * Method adds a Category Object to an array.   
   * @param model - Category Category Object representing a Lexus Category
   * @type void
   * @member VehicleNavigationManager
   */
  this.addCategory = function(category) {
    this.categories.push(category);
  }
  /**
   * Method returns a Category Object from the current array.
   * @param model - Category Category Object representing a Lexus Category
   * @type void
   * @member VehicleNavigationManager
   */
  this.getCategory = function(key) {
  	return this.categories.find(function(category){
  		if(category.id.indexOf(key.toUpperCase()) >= 0) {
  		  return category;
  		}
  	})
  }
  /**
   * Function will control the action of showing a Model or Category Vehicle Navigation Item
   * @param domObject Dom Element
   * @param categoryId String 
   * @param modelId String
   * @type void
   * @member VehicleNavigationManager
   */
  this.showNavigation = function (domObject, categoryId, modelId) {
  	var dataObject = this._getDataObject(categoryId, modelId);

  	if(dataObject == null)
  	  return;
  	if(this.timeoutSet) {
  		clearTimeout(this.timeoutId);
  		this.timeoutSet = false;
  	}
	this.closeDisclaimer();
	
  	// attach Dom Hot Spot if not already done.
  	if(!dataObject.domHotSpot)
  	  dataObject.domHotSpot = domObject;
  	
  	if(this.navState.isNavShowing()) {
  	  if(this.navState.getCurrentActive() == dataObject)
  	    return;
  	  else
  		this.hideNavigation();
  	}
  	// Hide all flash objects in safari
  	hideElementsForOverlays();
  	if(dataObject.type == VehicleCategory.type) {
  		this._showCategoryNavigation(dataObject);
  	}
  	else {
  		/*
  		 * IE needs to have an expliced hide on the body to make sure
  		 * the navigation actually hides when you roll off the menu
  		 */
        if(document.all)
  		  Event.observe(document.body, 'mouseout', ieBodyhideNavigation, true);
  		  
  		this._showModelNavigation(dataObject);
  	}

  }
  /**
   * Method will control the action to hide a Model or Category Vehicle Navigation Item.
   * @param eventObject Event
   * @type void
   * @member VehicleNavigationManager
   */
  this.hideNavigation = function (eventObject) {
  	var currentActive = this.navState.getCurrentActive();

  	// Only Hide if its ok
  	if(!this._shouldWeHideNavigation(eventObject))
  	  return;
    
    var wrapper = $('wrapper');
    
    // Hide Navigation
    currentActive.domNavigation.style.display = 'none';
    currentActive.domOverlay.style.display = 'none';
    
    /* 
     * Removed from the actual DOM because IE has issues displaying if we dont remove,
     * since these elements could be cloned.
     */
    wrapper.removeChild(currentActive.domNavigation);
    wrapper.removeChild(currentActive.domOverlay);    
    /*
     * Removed IE specific body event
  	 * 
  	 */
    if(document.all)
      Event.stopObserving(document.body, 'mouseout', ieBodyhideNavigation, true);
      
    this.navState.setNavShowing(false);
    
    // Show all flash objects in safari
  	showElementsForOverlays();
  }
  /**
   * Method will activate a timer and execute hideNavigation().
   * @member VehicleNavigationManager
   */
  this.hideNavigationWithTimeOut = function(eventObject) {
    if(this.timeoutSet)
      return;
    // Only Hide if its ok
  	if(!this._shouldWeHideNavigation(eventObject))
  	  return;

  	this.timeoutId = setTimeout("navigationManager.hideNavigation()",menuTimeout);
  	this.timeoutSet = true;
  }
   /**
   * Method will figure out wether or not to hide the current openned navigation
   * @member VehicleNavigationManager
   */
  this._shouldWeHideNavigation = function (eventObject) {
  	var currentActive = this.navState.getCurrentActive();
  	
  	// Nothing to do if we dont have a nav showing
  	if(!currentActive || !currentActive.domNavigation || !currentActive.domOverlay)
  	  return false; 	
  	// If in bounds, do nothing
  	if(this.isEventInBounds(currentActive.domOverlay, eventObject) || this.isEventInBounds(currentActive.domNavigation, eventObject))
  	  return false;
  	return true;
  }
  /**
   * Method clears the current hideNavigation timeout setting if there is one.
   * @member VehicleNavigationManager
   */
  this.clearTimeOut = function() {
  	if(this.timeoutSet) {
  	  clearTimeout(this.timeoutId);
  	  this.timeoutSet = false;
  	}
  }
  /**
   * Method will handle the specific task to show a Category Navigation Item
   * @param category VehicleCategory
   * @type void 
   * @member VehicleNavigationManager
   */
  this._showCategoryNavigation = function(category) {
  	var status = this.navView.showCategoryNavigation(category);
  	this.navState.setCurrentActive(category);
  }
  /**
   * Method will handle the specific task to show a Model Navigation Item
   * @param category VehicleCategory
   * @type void 
   * @member VehicleNavigationManager
   */
  this._showModelNavigation = function(model) {
  	var status = this.navView.showModelNavigation(model);
  	this.navState.setCurrentActive(model);
  }
  /**
   * Method figures out if the cursor of the given Event is within the given DOM Element
   * @param domObject DOMElement 
   * @param eventObject Event
   * @type void 
   * @member VehicleNavigationManager
   */
  this.isEventInBounds = function(domObject, eventObject) {	
  	if(!eventObject)
  	  return false;
	return Dom.isInBounds(domObject,Event.pointerX(eventObject), Event.pointerY(eventObject));
  }
  /**
   * Method pre caches all menu images
   * @type void 
   * @member VehicleNavigationManager
   */  
  this._cacheMenuImages = function() {
		
	for(var x=0; x<this.categories.length; x++) {
		var category = this.categories[x];
	
	    // Cache Model Navigation Images
	    for(var i=0; i<category.models.length; i++) {
	    	var model = category.models[i];
	    	this._cacheModelNavigationImages(model.name);	  
	    }
	}
  }
  /**
   * Method returns either a Category or a Model object based on if a model is passed in.
   * @param category String
   * @param model String (optional)
   * @type VehicleCategory/VehicleModel
   * @member VehicleNavigationManager
   */
  this._getDataObject = function(category, model) {
  	var dataObject;
  	if(!model)
  	  dataObject = this._getCategoryObject(category);
  	else
  	  dataObject = this._getModelObject(category, model);
  	return dataObject;
  }
  /**
   * Method returns either a Category object based on the id passed in
   * @param categoryId String
   * @type VehicleCategory
   * @member VehicleNavigationManager
   */
  this._getCategoryObject = function(categoryId) { 
  	return this.getCategory(categoryId);
  }
  /**
   * Method returns either a Model object based on the id passed in
   * @param modelId String
   * @type Model
   * @member VehicleNavigationManager
   */
  this._getModelObject = function(categoryId, modelId) {
  	var category = this.getCategory(categoryId);
  	return category.getModel(modelId);
  }
  this._setOnState = function() {
  	if(typeof( window[ 'MODEL_ID' ] ) != "undefined") {      
      var onStateImg;
      // Check if the current page we are on is a model
      for(var i=0; i<this.categories.length; i++) {
      	var category = this.categories[i];
      	for(var x=0; x<category.models.length; x++) {
      		var model = category.models[x];
      		// Determine if we are on this current Model, change image to 'On' state, and cache image
  	 	  	if(MODEL_ID.toLowerCase() == model.id.toLowerCase()) {
  	 	    	onStateImg = $( [model.categoryId.toLowerCase(), '_' , model.id.toLowerCase()].join('') );
  	      		break;
  	      	}
      	}
      }

  	  // If we are not on a Model, look if we are on a misc Link
  	  if(!onStateImg) {
  		onStateImg = $( ['mv', MODEL_ID].join('') );
  	  }
  	
  	  if(onStateImg) {
  		onStateImg.src = onStateImg.src.replace('.gif', 'On.gif');
  		this._cacheImage(onStateImg.src);
  	  }
    }
  }
  /**
   * Method executes the preliminary setup of the navigation bar. 
   * Including: caching of all images and rollovers, and all needed
   * events.
   * @member VehicleNavigationManager
   */
  this._setupNavigation = function() {  
  	 var mvCategoryContainers = document.getElementsByClassName('mvCategoryContainer');
  	 var mvMiscLinkContainers = document.getElementsByClassName('mvMiscLinkContainer');
  	 
  	 // Category and Model: Add Events and cache all images
  	 for(var i=0; i<mvCategoryContainers.length; i++) {
  	 	var mvCategoryContainer = mvCategoryContainers[i];
  	 	var mvCategory = $A(document.getElementsByClassName('mvCategory',mvCategoryContainer));
  	 	var mvModels = $A(document.getElementsByClassName('mvModels',mvCategoryContainer));
  	 	
  	 	if(mvCategory != '') {
  	 	  this._setupCategory(mvCategory[0]);
  	 	  this._setupModels(mvModels[0]);
  	 	}
  	 }
  	 
  	 // Misc Links: Add Events and cache all images
	for(var i=0; i<mvMiscLinkContainers.length; i++) {
  	 	var miscDivs = ($NL(mvMiscLinkContainers[i].childNodes)).elements();
		
		for(var x=0; x<miscDivs.length; x++) {
			var miscDiv = miscDivs[x];
			var href = ($NL(miscDiv.childNodes)).firstElement();
  	 		var img = ($NL(href.childNodes)).firstElement();
  	 		
  	 		this._cacheOnOverImages(img.src);
  	 		// Cache Images
  	        //this._cacheImage(img.src);
  	        
  	        // Cache Over State
  	        //var overImgSrc = img.src.replace('On.gif', '.gif');
  	        //this._cacheImage(overImgSrc.replace('.gif', 'Over.gif'));
  	 		// Events
  	 		if(img.src.indexOf('On.gif') == -1) {
  	 			Event.observe(img, 'mouseout', function() {swapOver(this);}.bind(img), false);
  	 			Event.observe(img, 'mouseover', function() {swapOver(this);}.bind(img), false);
  	 		}
		}
	}
  }
  /**
   * Method prebuild category overlays.
   * @member VehicleNavigationManager
   */
  this._preLoadMenus = function() {  	
  	this.categories.each(function(category){ 
  	   this.navView.buildCategoryOverlay(category); 	  
  	}.bind(this));
  }
  /**
   * Method managers the caching of all navigation category images and
   * adds swapOver and showNavigation events to the category position of the 
   * Navigtaion bar.
   * @member VehicleNavigationManager
   */
  this._setupCategory = function(mvCategory) { 
    // Find Category Image and Cache
    var categoryImg = ($NL(mvCategory.childNodes)).firstElement();
    
    this._cacheOverImage(categoryImg.src);
    
    // Add Events to Category
    Event.observe(categoryImg, 'mouseover', function() {swapOver(categoryImg);this.hideNavigation()}.bindAsEventListener(this), false);
    Event.observe(categoryImg, 'mouseout', function() {swapOut(categoryImg);}, false);
    Event.observe(categoryImg, 'click', function() {swapOut(categoryImg);this.showNavigation(categoryImg, categoryImg.id)}.bindAsEventListener(this), false);   
  }
  this._cacheOverImage = function(src) {
    var overImgSrc = src.replace('On.gif', '.gif');
  	this._cacheImage(overImgSrc.replace('.gif', 'Over.gif'));
  }
  this._cacheOnOverImages = function(src) {
  	this._cacheImage(src);
  	this._cacheOverImage(src)        
  }
  /**
   * Method caches image in browser.
   * @member VehicleNavigationManager
   */
  this._cacheImage = function(src) {
  	// Check if we are a third party navigation and we dont have a full url
  	if(window.LEXUS_ROOT_ASSET && src.indexOf('http://') == -1) {
  		src = window.LEXUS_ROOT_ASSET + src;
  	} 

    var newImage = new Image();
  	newImage.src = src;
  	this.imageCache.push(newImage);
  }
  /**
   * Method handels the setup of all Navigation model images and
   * addes showNavigation to a mouseover event on each model.
   * @member VehicleNavigationManager
   */
  this._setupModels = function(mvModel) {
  	 var modelLinks = ($NL(mvModel.childNodes)).elements();

  	 // Loop through each Model, cache and apply needed events
  	 modelLinks.each(function(modelLink) {
  	 	var modelImg = modelLink.firstChild;
  	 	var ids = modelImg.id.split('_');
  	 	var catId = ids[0];
  	 	var modId = ids[1];

  	 	// Cache Model Image and Overlay
  	 	this._cacheOverImage(modelImg.src);

  	 	// Add Events to Model
  	 	Event.observe(modelImg, 'mouseover', function() {this.showNavigation(modelImg, catId, modId)}.bindAsEventListener(this), false);
  	 }.bind(this)); 	 
  }
  /**
   * Method controls the caching of all Navigation Menu Model images.
   * @member VehicleNavigationManager
   */
  this._cacheModelNavigationImages = function(modelName) {
  	this._cacheImage(this.navView._replaceModel(this.navView.IMG_HEAD,modelName));
    this._cacheImage(this.navView._replaceModel(this.navView.IMG_PHOTO,modelName));
    this._cacheImage(this.navView._replaceModel(this.navView.IMG_OVERVIEW,modelName));
    this._cacheImage(this.navView._replaceModel(this.navView.IMG_BUILD,modelName));
  }
  this.launchDisclaimer = function(modelName) {
  	this.hideNavigation();
  	this.closeDisclaimer();
  	
  	hideElementsForOverlays();
  	this.showDisclaimerWrap();
  	
  	this.ajaxQueue = new Ajax.Queue(Ajax.Queue.FIFO, true);
  	this.ajaxQueue.addAction(
  		new Ajax.Updater(
			    document.body,
			    GalleryUtils.buildAjaxUrl(['/lexus-share/includes/models/legal_disclaimers_template.incl']),
			    {
			 	    method: 'get',
		 	        insertion: Insertion.Bottom,
		 	        onComplete: function() {this.prepareContent()}.bind(this),
				    wait: true
			    }
			  )
	)
	this.ajaxQueue.addAction(
  		new Ajax.Updater(
			    'legalDisclaimerHolder',
			    GalleryUtils.buildAjaxUrl(['/lexus-share/includes/models/legal_disclaimers_' + modelName + '.incl']),
			    {
			 	    method: 'get',
		 	        insertion: Insertion.Bottom,
		 	        onComplete: this.setupLegalDisclaimerScroll,
				    wait: true
			    }
			  )
	)
	this.ajaxQueue.start();
  }
  this.launchDisclaimerPopup = function(modelName) {
  	this.hideNavigation();
  	
  	var windowWidth = (document.all) ? document.body.offsetWidth : window.innerWidth;
	var windowHeight = (document.all) ? document.body.offsetHeight : window.innerHeight;
	
	var left = Math.round( (windowWidth - 804) / 2 );
	var top =  Math.round( (windowHeight - 620) / 2 );
	
	this.closeDisclaimer();
	
	legalDisclaimerWindow  = window.open(LEXUS_ROOT_URL + '/lexus-share/includes/models/legal_disclaimer_vendor.html?model='+modelName,'legalDisclaimerWindow','width=' 
																	+ 774 + ',height=' + 425
																	+ ',menubar=no,location=no,resizable=no,scrollbars=no,status=no,left=' + left + 'px,top=' + top + 'px');
	legalDisclaimerWindow.focus();	
	
	// We have to add these events without prototype, since prototype might not
	// be loaded at this point
	if (window.addEventListener) {
      window.addEventListener('unload', this.closeDisclaimer.bind(this), null);
    } else if (window.attachEvent) {
      window.attachEvent('on' + 'unload', this.closeDisclaimer.bind(this));
    }
  }
  this.prepareContent = function() {
  	$('legalClose').onclick = function() {this.closeDisclaimer()}.bind(this);
  	
  }
  this.closeDisclaimer = function() {
  	if($('legalDisclaimerContainer')) {
  		$('legalDisclaimerContainer').parentNode.removeChild($('legalDisclaimerContainer'));
  		this.hideDisclaimerWrap();
  		showElementsForOverlays();
  	}
  	else if(window.legalDisclaimerWindow && !window.legalDisclaimerWindow.closed) {
		legalDisclaimerWindow.close();
		legalDisclaimerWindow = null;
	}
  }
  this.setupLegalDisclaimerScroll = function() {
  		var scrollObj = new dw_scrollObj('legalClippingLayer', 'legalDisclaimerHolder', null);
	
		// arguments: dragBar id, track id, axis ("v" or "h"), x offset, y offset
		// (x/y offsets of dragBar in track)
		scrollObj.setUpScrollbar("legalDragBar", "legalTrack", "v", 0, 0);
  }
  this.showDisclaimerWrap = function() {
	if(!this.backdrop) {
		this.backdrop = new Backdrop('disclaimerWrap','galleryWrap');
		this.backdrop.observe('click', this.closeDisclaimer.bind(this), false);
	}
	this.backdrop.enable();
  }
  this.hideDisclaimerWrap = function() {
		  if(this.backdrop) {
			this.backdrop.disable();
		}
		
	}
}
/**
 * Class provides static methods to build and display the navigation onto the browser
 * @constructor
 */
function VehicleNavigationView() {
	this.ROOT_IMG = '/lexus-share/images/nav/vehicleNav/';
	this.MODEL_REPLACE = 'model';
	this.MODEL_CODE_REPLACE = 'model-code';
	this.CATEGORY_REPLACE = 'category';
	this.IMG_OVERVIEW = this.ROOT_IMG + 'vn_svBtn~' + this.MODEL_REPLACE + '~Ov.gif';
	this.IMG_GALLERY = this.ROOT_IMG + 'vn_svBtn~' + this.MODEL_REPLACE + '~Pg.gif';
	this.IMG_BUILD = this.ROOT_IMG + 'vn_svBtn~' + this.MODEL_REPLACE + '~Bld.gif';
	this.IMG_HEAD = this.ROOT_IMG + 'vn_sv~'  + this.MODEL_REPLACE + '~Head.gif';
	this.IMG_PHOTO = this.ROOT_IMG + 'vn_sv~'  + this.MODEL_REPLACE + '~Photo.gif';
	this.CAT_OVERLAY = this.ROOT_IMG + 'vn_~' + this.CATEGORY_REPLACE + '~On.gif'
	                                                                         
	/**
	 * Method will control the operatations to build and show a Cateogry Navigation.
	 * Will return true if the Model navigation is displayed
	 * @param category VehicleCategory
	 * @type boolean
	 * @member VehicleNavigationView
	 */
	this.showCategoryNavigation = function(category) {
	    var wrapper = $('wrapper');
		this.buildCategoryOverlay(category);
		this.buildCategoryNavigation(category);
	
		// If we could not build, return, nothing else to do
		if(!category.domOverlay)
		  return;
	
		// Make sure we have the Model class NOT category
	    wrapper.appendChild(category.domOverlay);
	    category.domOverlay.style.top = Dom.getTopYAsPx(category.domHotSpot,wrapper);
	    category.domOverlay.style.left = Dom.getLeftXAsPx(category.domHotSpot,wrapper);
	    category.domOverlay.style.display = 'block';
			
		if(!category.domNavigation)
		  return
		category.domNavigation.style.top = Dom.getBottomYAsPx('mvContainer',wrapper);
	
		/*
		 * Need to calculate the position of category div
		 * This will take into consideration the total size of the
		 * category menu and compare with the total size of the navigation bar.
		 * This is to make sure we do NOT position past the right most point of
		 * the navigation bar.
		 */
		var catTotalSize = 1; // we start with one because the category div has to make up one extra right px
		var navTotalSizeRight = 0;
		var catTotalSizeRight = 0;
	
	    /* 
	     * Calculate the total width based on how many models we are showing
	     * also adds the left position of the dom hot spot (category image)
	     */
		for(var i=0; i<category.models.length; i++) {
			catTotalSize += 234;
			if(i>0) {
				catTotalSize += 1;
			}
		}
		catTotalRight = catTotalSize + Dom.getLeftX(category.domHotSpot,wrapper) - 5;
	
	    // calculate the total size and left position of Navigation bar.
	    var mvBoundry = Dom.getBoundries('mvContainer',wrapper);
	    navTotalSize = mvBoundry.width + mvBoundry.leftX
	    
	    /* 
	     * If are category div is larger than the navigation bar then we will 
	     * line it up on the right corner
	     */
		if(catTotalRight  >  navTotalSize) {
		  category.domNavigation.style.left = (mvBoundry.rightX - catTotalSize) + 'px';
		}
		/*
		 * Else position the menu at the left edge of the triggering category image
		 */
		else {
		  category.domNavigation.style.left = (Dom.getLeftX(category.domHotSpot,wrapper) - 5) + 'px';
		}
		wrapper.appendChild(category.domNavigation);
		category.domNavigation.style.display = 'block';
	    
	}
	/**
	 * Method will control the operatations to build and show a Model Navigation.
	 * Will return true if the Model navigation is displayed
	 * @param model VehicleModel
	 * @type boolean
	 * @member VehicleNavigationView
	 */
	this.showModelNavigation = function(model) {
		var wrapper = $('wrapper');
		this.buildModelNavigation(model);
	
		// if we could not build, return, nothing else to do
		if(!model.domNavigation)
		  return

        // show and position navigation menu	
		wrapper.appendChild(model.domNavigation);	
		model.domNavigation.style.top = Dom.getBottomYAsPx('mvContainer',wrapper);
		model.domNavigation.style.left = (Dom.getLeftX(model.domHotSpot,wrapper) - 8) + 'px';
	    model.domNavigation.style.display = 'block';
	    
	    
		this.buildModelOverlay(model);
		
		// if we could not build, return, nothing else to do
		if(!model.domOverlay)
		  return
		
		wrapper.appendChild(model.domOverlay);
		model.domOverlay.style.top = Dom.getTopYAsPx(model.domHotSpot,wrapper);
		// We move the image 4 px left because the image has 3px on each side more of space
		model.domOverlay.style.left = (Dom.getLeftX(model.domHotSpot,wrapper) - 4) + 'px';
		
		model.domOverlay.style.display = 'block';
	    
		return true;
	}
	/**
	 * Method will build the DIV Object Navigation representing a specific Model.
	 * @param model VehicleModel
	 * @type void
	 * @member VehicleNavigationView
	 */
	this.buildModelNavigation = function(model) {
	    if(model.domNavigation)
		  return
		
		var nav = $('mvNavigationModel_Template').cloneNode(true);
	    var links = nav.getElementsByTagName('a');
	    var imgs = nav.getElementsByTagName('IMG');
	
	//Set all Links
	   for(var i=0; i<links.length; i++) {
	   	 var link = links[i];
	   	 var linkImg = link.firstChild;
	   	 link.href = this._replaceModelLink(link.href, model.name, model.code);	   	
	   
		 if(link.parentNode.className == 'mvNavigationLink') {

 		 	Event.observe(linkImg, 'mouseover', function() {swapOver(this)}.bind(linkImg) );   	
 		 	Event.observe(linkImg, 'mouseout', function() {swapOut(this)}.bind(linkImg) );
		 }
	   }
	   
	// Set all images
		for(var i=0; i<imgs.length; i++) {
			var img = imgs[i];
			var pieces = img.src.split('#');
			img.src = this._replaceModel(pieces[pieces.length - 1], model.name);	   	
	   		img.alt = this._replaceModel(img.alt, model.name.replace(new RegExp("h$"),' Hybrid'));		   	
		}

		nav.id = 'mvNav_' + model.categoryId + "_" + model.name;
    
	//Build Features
	  var containerDivs = nav.getElementsByTagName('DIV');
		var topChildrenDivs = containerDivs[0].getElementsByTagName('DIV');
		var featuresDiv = topChildrenDivs[topChildrenDivs.length - 1];
		var startingPrice = topChildrenDivs[topChildrenDivs.length - 2];
		
		for(var i=0; i<model.features.length; i++) {
			var featureDiv = document.createElement('DIV');
			featureDiv.className = 'mvNavigationFeature';
			featureDiv.innerHTML = model.features[i];
			
			/*
			var disclaimers = featureDiv.getElementsByTagName('A');
			
			for(var x=0; x<disclaimers.length; x++) {
				var disclaimer = disclaimers[x];
				
				disclaimer.href = 'javascript:void(0);'
				
				disclaimer.onclick = function() {navigationManager.launchDisclaimer(this);}.bind(model.name);
			}
			*/
			featuresDiv.appendChild(featureDiv);		
		}
		
		
	//Build Staring Price
		startingPrice.innerHTML = model.getPriceAsString();
		
		
		
    //Add Events
		if(document.all)
		  Event.observe(nav, 'mouseout', function() {event.cancelBubble = true;navigationManager.hideNavigationWithTimeOut(event)})
		else
		  Event.observe(nav, 'mouseout', function(event) {event.cancelBubble = true;navigationManager.hideNavigationWithTimeOut(event)})
		
		Event.observe(nav, 'mouseover', function() {navigationManager.clearTimeOut()})

		model.domNavigation = nav;
		
		this._addLegalDisclaimerEvents(model.name,model.domNavigation);
		$('mvContainer').appendChild(model.domNavigation);
	}
	/**
	 * Method will build the DIV Object for the Model Overlay representing a specific Model.
	 * @param model VehicleModel
	 * @type void
	 * @member VehicleNavigationView
	 */
	this.buildModelOverlay = function(model) {
		if(model.domOverlay)
		  return

		var overlayDiv = document.createElement('DIV');
		var overlayHref = document.createElement('A');
		var overlayImg = document.createElement('IMG');
	
		overlayDiv.className = 'mvOverLay';
	
		// browser conflict
		if(document.all)	
		  overlayDiv.onmouseout = function() { event.cancelBubble = true;navigationManager.hideNavigationWithTimeOut(event)};
		else
		  overlayDiv.onmouseout = function(event) {event.cancelBubble = true;navigationManager.hideNavigationWithTimeOut(event)};
	
		overlayDiv.onmouseover = function() {navigationManager.clearTimeOut()};

		overlayHref.href = model.domHotSpot.parentNode.href;
	    overlayHref.target = model.domHotSpot.parentNode.getAttribute('TARGET');

	    var imagepath = model.domHotSpot.src.split('vehicleNav');
		overlayImg.src =  imagepath[0]  + 'vehicleNav/vn_svBtn' + model.name + "Over.gif";
		overlayImg.alt = model.name.replace(new RegExp("h$"),' Hybrid');

		overlayHref.appendChild(overlayImg);
		overlayDiv.appendChild(overlayHref);
	
		model.domOverlay = overlayDiv;
		$('mvContainer').appendChild(model.domOverlay);  
	}
	/**
	 * Method will build the DIV Object Navigation representing a specific Model.
	 * @param model VehicleModel
	 * @type void
	 * @member VehicleNavigationView
	 */
	this.buildCategoryNavigation = function(category) {
		if(category.domNavigation)
		  return
	   
		var categoryDiv = document.createElement('DIV');
		categoryDiv.id = 'mvCat_' + category.name;
		categoryDiv.className = 'mvNavigationCategory';
	    
	    for(var i=0; i<category.models.length; i++) {    	
	  	// Build Model Navigation if needed
		  	if(!category.models[i].domNavigation) {
		  	  this.buildModelNavigation(category.models[i]);
		  	  
		  	}
		
		  	var cloneDiv = category.models[i].domNavigation.cloneNode(true);
		  	
		  	cloneDiv.id = category.name + '_' + cloneDiv.id;
		  	cloneDiv.className = 'mvNavigationModelForCategory';
		  	cloneDiv.style.display = 'block';
		
			this._addLegalDisclaimerEvents(category.models[i].name,cloneDiv);

		  	if(i>0) {
		        var catDivider = document.createElement('DIV');
		        var catDividerImg = document.createElement('IMG');
		        
		      catDivider.className = 'mvNavigationCategoryDivider';	        
		      catDividerImg.src = IMG_ROOT + 'spacer.gif'
		        
		  	  catDivider.appendChild(catDividerImg);
		  	  categoryDiv.appendChild(catDivider)
		  	}
		  	categoryDiv.appendChild(cloneDiv);
	  }
	  category.domNavigation = categoryDiv;
	  $('mvContainer').appendChild(categoryDiv);
	}
	/**
	 * Method will build the DIV Object for the Model Overlay representing a specific Model.
	 * @param model VehicleModel
	 * @type void
	 * @member VehicleNavigationView
	 */
	this.buildCategoryOverlay = function(category) {
	  if(category.domOverlay)
	    return

	  var overlayDiv = $('mvCategoryOverLay_Template').cloneNode(true);
	  var divs = overlayDiv.getElementsByTagName('DIV');
	  var topDiv = divs[0];
	
	  overlayDiv.id = 'overlayDiv' + category.id;
	
	  // Create Category Overlay Image Example: 'vn_ESOn.gif'
	  var imgTopDiv = ($NL(topDiv.childNodes)).firstElement();
	  var pieces = imgTopDiv.src.split('#');
	  imgTopDiv.src = this._replaceCategory(pieces[pieces.length - 1], category.id);
      imgTopDiv.alt = category.name;
	  //Need to calc cached images width;
	  var imgWidth = new Image();
	  imgWidth.src = imgTopDiv.src;
	  // Have to set a width in IE
	  if(document.all)
	    overlayDiv.style.width = imgWidth.width;

	  category.domOverlay = overlayDiv;
	  $('mvContainer').appendChild(category.domOverlay);
	}
	this._addLegalDisclaimerEvents = function(modelId, div) {
		var featureDivs = document.getElementsByClassName('mvNavigationFeatures', div, 'DIV');
		var priceDiv = document.getElementsByClassName('mvNavigationPrice', div, 'DIV')[0];
		
		for(var x=0; x<featureDivs.length; x++) {
			var featureDiv  = featureDivs[x];
			
			var disclaimers = featureDiv.getElementsByTagName('A');
			
			for(var x=0; x<disclaimers.length; x++) {
				var disclaimer = disclaimers[x];
				
				disclaimer.href = 'javascript:void(0);'
				
				// If we are on a vendor site
				if(window.LEXUS_ROOT_URL) {
					disclaimer.onclick = function() {navigationManager.launchDisclaimerPopup(this);}.bind(modelId);
				}
				// else we must be on www.lexus.com
				else {
					disclaimer.onclick = function() {navigationManager.launchDisclaimer(this);}.bind(modelId);
				}
			}
		}
		
		var hrefs = priceDiv.getElementsByTagName('A'); 
		var disclaimer;
		if(hrefs.length > 0) {
			disclaimer = hrefs[0];
		}
		else {
			disclaimer = document.createElement('A');
			disclaimer.href = '#_1';
			disclaimer.className = 'link_disclaim';
			disclaimer.innerHTML = '[1]';
			priceDiv.appendChild(disclaimer);
		}		
		// Add diclaimer about price 
		// If we are on a vendor site
		if(window.LEXUS_ROOT_URL) {
			disclaimer.onclick = function() {navigationManager.launchDisclaimerPopup(this);}.bind(modelId);
		}
		// else we must be on www.lexus.com
		else {
			disclaimer.onclick = function() {navigationManager.launchDisclaimer(this);}.bind(modelId);
		} 		
		
	}
	/**
	 * Method replaces all ~model~ wildcards with actual model name
	 */
	this._replaceModel = function(str, name) {
	  if(str.indexOf('lexusConfigApp') > -1 && name.match(new RegExp("h$"))) {
	  	name = name.replace(new RegExp("h$"),'_HYBRID');
	  }
	  return str.templateReplace(this.MODEL_REPLACE, name);	
	}
	this._replaceModelCode = function(str, name) {
		return str.templateReplace(this.MODEL_CODE_REPLACE, name);	
	}
	this._replaceModelLink = function(str, name, code) {
	  str = str.replace('about:blank','');
	  str = str.replace('javascript:void(0);', '');
	  str = this._replaceModel(str, name);
	  str = this._replaceModelCode(str, code);
	  return str;
	}
	/**
	 * Method replaces all ~category~ wildcards with actual category name
	 */
	this._replaceCategory = function(str, cat) {
	  return str.templateReplace(this.CATEGORY_REPLACE, cat);	
	}
}
function ieBodyhideNavigation() {	
	navigationManager.hideNavigationWithTimeOut();
}
var navigationManager = new VehicleNavigationManager();

	


	
	var category = new VehicleCategory('LS', 'Luxury Sedans');
	 
	 	
	 	var model = new VehicleModel('LS', 'LS','$61,000','$71,000','91');
	 	
	 		//'[<a href="#LS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// LS Disclaimer
	 		model.addFeature('4.6-Liter V8');
	 	
	 		//'[<a href="#LS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// LS Disclaimer
	 		model.addFeature('380 hp [<a href="#LS_Disclaimer_2" class="link_disclaim">2</a>]');
	 	
	 		//'[<a href="#LS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// LS Disclaimer
	 		model.addFeature('Eight-Speed Sequential-Shift Automatic ');
	 	
	 		//'[<a href="#LS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// LS Disclaimer
	 		model.addFeature('0 - 60 mph in 5.4 sec [<a href="#LS_Disclaimer_2" class="link_disclaim">2</a>][<a href="#LS_Disclaimer_3" class="link_disclaim">3</a>]');
	 	
	 		//'[<a href="#LS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// LS Disclaimer
	 		model.addFeature('Rear-Wheel Drive');
	 	
	 	category.addModel(model);
	 
	 	
	 	var model = new VehicleModel('GS', 'GS','$44,150','$52,375','9399');
	 	
	 		//'[<a href="#GS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GS Disclaimer
	 		model.addFeature('4.3-Liter V8 or 3.5-Liter V6');
	 	
	 		//'[<a href="#GS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GS Disclaimer
	 		model.addFeature('290-303 hp [<a href="#GS_Disclaimer_2" class="link_disclaim">2</a>]');
	 	
	 		//'[<a href="#GS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GS Disclaimer
	 		model.addFeature('Six-Speed Sequential-Shift Automatic');
	 	
	 		//'[<a href="#GS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GS Disclaimer
	 		model.addFeature('0 - 60 mph in 5.7 or 5.8 sec [<a href="#GS_Disclaimer_2" class="link_disclaim">2</a>][<a href="#GS_Disclaimer_3" class="link_disclaim">3</a>]');
	 	
	 		//'[<a href="#GS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GS Disclaimer
	 		model.addFeature('Rear- or All-Wheel Drive');
	 	
	 	category.addModel(model);
	 
	 	
	 	var model = new VehicleModel('ES', 'ES','$33,170','','9000');
	 	
	 		//'[<a href="#ES_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// ES Disclaimer
	 		model.addFeature('3.5-Liter V6');
	 	
	 		//'[<a href="#ES_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// ES Disclaimer
	 		model.addFeature('272 hp [<a href="#ES_Disclaimer_2" class="link_disclaim">2</a>]');
	 	
	 		//'[<a href="#ES_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// ES Disclaimer
	 		model.addFeature('Six-Speed Sequential-Shift Automatic');
	 	
	 		//'[<a href="#ES_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// ES Disclaimer
	 		model.addFeature('0 - 60 mph in 6.8 sec [<a href="#ES_Disclaimer_2" class="link_disclaim">2</a>][<a href="#ES_Disclaimer_3" class="link_disclaim">3</a>]');
	 	
	 		//'[<a href="#ES_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// ES Disclaimer
	 		model.addFeature('Front-Wheel Drive');
	 	
	 	category.addModel(model);
	 
	 	
	 	var model = new VehicleModel('IS', 'IS','$30,255','$35,705','95');
	 	
	 		//'[<a href="#IS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// IS Disclaimer
	 		model.addFeature('3.5- or 2.5-Liter V6');
	 	
	 		//'[<a href="#IS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// IS Disclaimer
	 		model.addFeature('306 or 204 hp [<a href="#IS_Disclaimer_2" class="link_disclaim">2</a>]');
	 	
	 		//'[<a href="#IS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// IS Disclaimer
	 		model.addFeature('Six-Speed Manual or Paddle-Shift Sequential Automatic');
	 	
	 		//'[<a href="#IS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// IS Disclaimer
	 		model.addFeature('0 - 60 mph in 5.3 [<a href="#IS_Disclaimer_3" class="link_disclaim">3</a>] to 8.3 sec [<a href="#IS_Disclaimer_2" class="link_disclaim">2</a>][<a href="#IS_Disclaimer_4" class="link_disclaim">4</a>]');
	 	
	 		//'[<a href="#IS_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// IS Disclaimer
	 		model.addFeature('Rear- or All-Wheel Drive');
	 	
	 	category.addModel(model);
	 
	navigationManager.addCategory(category);

	
	var category = new VehicleCategory('LC', 'Luxury Coupe');
	 
	 	
	 	var model = new VehicleModel('SC', 'SC','$65,455','','9270');
	 	
	 		//'[<a href="#SC_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// SC Disclaimer
	 		model.addFeature('4.3-Liter V8');
	 	
	 		//'[<a href="#SC_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// SC Disclaimer
	 		model.addFeature('288 hp [<a href="#SC_Disclaimer_2" class="link_disclaim">2</a>]');
	 	
	 		//'[<a href="#SC_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// SC Disclaimer
	 		model.addFeature('Six-Speed Sequential-Shift Automatic ');
	 	
	 		//'[<a href="#SC_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// SC Disclaimer
	 		model.addFeature('0 - 60 mph in 5.8 sec [<a href="#SC_Disclaimer_2" class="link_disclaim">2</a>][<a href="#SC_Disclaimer_3" class="link_disclaim">3</a>]');
	 	
	 		//'[<a href="#SC_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// SC Disclaimer
	 		model.addFeature('Rear-Wheel Drive ');
	 	
	 	category.addModel(model);
	 
	navigationManager.addCategory(category);

	
	var category = new VehicleCategory('LUV', 'Luxury Utility Vehicles');
	 
	 	
	 	var model = new VehicleModel('LX', 'LX','$67,395','','9620');
	 	
	 		//'[<a href="#LX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// LX Disclaimer
	 		model.addFeature('4.7-Liter V8');
	 	
	 		//'[<a href="#LX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// LX Disclaimer
	 		model.addFeature('268 hp [<a href="#LX_Disclaimer_2" class="link_disclaim">2</a>][<a href="#LX_Disclaimer_3" class="link_disclaim">3</a>]');
	 	
	 		//'[<a href="#LX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// LX Disclaimer
	 		model.addFeature('Five-Speed Automatic');
	 	
	 		//'[<a href="#LX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// LX Disclaimer
	 		model.addFeature('Seats Eight Passengers');
	 	
	 		//'[<a href="#LX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// LX Disclaimer
	 		model.addFeature('Full-time Four-Wheel Drive');
	 	
	 	category.addModel(model);
	 
	 	
	 	var model = new VehicleModel('GX', 'GX','$46,635','','9700');
	 	
	 		//'[<a href="#GX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GX Disclaimer
	 		model.addFeature('4.7-Liter V8');
	 	
	 		//'[<a href="#GX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GX Disclaimer
	 		model.addFeature('263 hp [<a href="#GX_Disclaimer_2" class="link_disclaim">2</a>][<a href="#GX_Disclaimer_3" class="link_disclaim">3</a>]');
	 	
	 		//'[<a href="#GX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GX Disclaimer
	 		model.addFeature('Five-Speed Automatic');
	 	
	 		//'[<a href="#GX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GX Disclaimer
	 		model.addFeature('Seats Five to Eight Passengers [<a href="#GX_Disclaimer_4" class="link_disclaim">4</a>]');
	 	
	 		//'[<a href="#GX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GX Disclaimer
	 		model.addFeature('Full-Time Four-Wheel Drive');
	 	
	 	category.addModel(model);
	 
	 	
	 	var model = new VehicleModel('RX', 'RX','$37,400','$38,800','9499');
	 	
	 		//'[<a href="#RX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// RX Disclaimer
	 		model.addFeature('3.5-Liter V6');
	 	
	 		//'[<a href="#RX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// RX Disclaimer
	 		model.addFeature('270 hp [<a href="#RX_Disclaimer_2" class="link_disclaim">2</a>][<a href="#RX_Disclaimer_3" class="link_disclaim">3</a>]');
	 	
	 		//'[<a href="#RX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// RX Disclaimer
	 		model.addFeature('Five-Speed Automatic');
	 	
	 		//'[<a href="#RX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// RX Disclaimer
	 		model.addFeature('Seats Five Passengers');
	 	
	 		//'[<a href="#RX_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// RX Disclaimer
	 		model.addFeature('Front- or All-Wheel Drive');
	 	
	 	category.addModel(model);
	 
	navigationManager.addCategory(category);

	
	var category = new VehicleCategory('LH', 'Luxury Hybrid');
	 
	 	
	 	var model = new VehicleModel('GSh', 'GSh','$54,900','','9344');
	 	
	 		//'[<a href="#GSh_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GSh Disclaimer
	 		model.addFeature('3.5-Liter V6, 340 hp (Total Output) [<a href="#GSh_Disclaimer_2" class="link_disclaim">2</a>]');
	 	
	 		//'[<a href="#GSh_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GSh Disclaimer
	 		model.addFeature('ECVT');
	 	
	 		//'[<a href="#GSh_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GSh Disclaimer
	 		model.addFeature('MPG (city/highway): 25/28 [<a href="#GSh_Disclaimer_3" class="link_disclaim">3</a>]');
	 	
	 		//'[<a href="#GSh_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GSh Disclaimer
	 		model.addFeature('0 - 60 mph in 5.2 sec [<a href="#GSh_Disclaimer_2" class="link_disclaim">2</a>][<a href="#GSh_Disclaimer_4" class="link_disclaim">4</a>]');
	 	
	 		//'[<a href="#GSh_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// GSh Disclaimer
	 		model.addFeature('Rear-Wheel Drive');
	 	
	 	category.addModel(model);
	 
	 	
	 	var model = new VehicleModel('RXh', 'RXh','$41,180','$42,580','9444');
	 	
	 		//'[<a href="#RXh_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// RXh Disclaimer
	 		model.addFeature('3.3-Liter V6, 268 hp (Total<br />Output) [<a href="#RXh_Disclaimer_2" class="link_disclaim">2</a>]');
	 	
	 		//'[<a href="#RXh_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// RXh Disclaimer
	 		model.addFeature('ECVT');
	 	
	 		//'[<a href="#RXh_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// RXh Disclaimer
	 		model.addFeature('MPG (city/highway):<br/>32/27 (FWD) [<a href="#RXh_Disclaimer_3" class="link_disclaim">3</a>], 31/27 (AWD) [<a href="#RXh_Disclaimer_3" class="link_disclaim">3</a>]');
	 	
	 		//'[<a href="#RXh_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// RXh Disclaimer
	 		model.addFeature('0 - 60 mph in 6.9 [<a href="#RXh_Disclaimer_4" class="link_disclaim">4</a>] or 7.5 sec [<a href="#RXh_Disclaimer_2" class="link_disclaim">2</a>][<a href="#RXh_Disclaimer_5" class="link_disclaim">5</a>]');
	 	
	 		//'[<a href="#RXh_Disclaimer_1" class="link_disclaim">1</a>]'
	 		// RXh Disclaimer
	 		model.addFeature('Front- or Part-Time AWD [<a href="#RXh_Disclaimer_6" class="link_disclaim">6</a>]');
	 	
	 	category.addModel(model);
	 
	navigationManager.addCategory(category);



	/*************************************************************************
  This code is from Dynamic Web Coding at www.dyn-web.com
  Copyright 2001-4 by Sharon Paine 
  See Terms of Use at www.dyn-web.com/bus/terms.html
  regarding conditions under which you may use this code.
  This notice must be retained in the code as is!
	This file contains 5 sections
*************************************************************************/
function initScrollLayers(wn,lyr,dragBar,track) {
	if (!PAGE_LOAD){
		return;
	}
  // arguments: id of layer containing scrolling layers (clipped layer), id of layer to scroll, 
  // if horizontal scrolling, id of element containing scrolling content (table?)
  var wndo1 = new dw_scrollObj(wn, lyr, null);
  // arguments: dragBar id, track id, axis ("v" or "h"), x offset, y offset
  // (x/y offsets of dragBar in track)
  wndo1.setUpScrollbar(dragBar, track, "v", 0, 0);
}
function dw_showLayers() {
  if ( document.getElementById ) {
    var lyr, i;
    for (i=0; arguments[i]; i++) {
      lyr = document.getElementById( arguments[i] );
      lyr.style.visibility = "visible";
    }
  }
}
function dw_hideLayers() {
  if ( document.getElementById ) {
    var lyr, i;
    for (i=0; arguments[i]; i++) {
      lyr = document.getElementById( arguments[i] );
      lyr.style.visibility = "hidden";
    }
  }
}
/* ********************************************************************************************************
    dw_scrollObj.js  version date: June 2004 
    contains constructor and basic methods for scrolling layers.
    Use with dw_hoverscroll.js and/or dw_glidescroll.js,
    and for scrollbars: dw_scroll-aux.js and dw_slidebar.js
*/

dw_scrollObjs = {};
dw_scrollObj.speed = 100; // default speed for mouseover scrolling
//  constructor arguments: id of layer containing scrolling layers (clipped layer), id of layer to scroll, 
//	id of table or other element that scrolling content is nested in. 
//	ns6+/moz need that extra container to get width for horizontal scrolling.
//	(not needed for vertical scrolling)
function dw_scrollObj(wnId, lyrId, cntId) {
  this.id = wnId; dw_scrollObjs[this.id] = this;
  this.lyrId = lyrId;
  this.animString = "dw_scrollObjs." + this.id;
  this.load(lyrId, cntId);
}

dw_scrollObj.loadLayer = function(wnId, id, cntId) {
  if ( dw_scrollObjs[wnId] ) dw_scrollObjs[wnId].load(id, cntId);
}

dw_scrollObj.prototype.load = function(lyrId, cntId) {
  if (!document.getElementById) return;
  var wndo, lyr;
  if (this.lyrId) {
    lyr = document.getElementById(this.lyrId);
    lyr.style.visibility = "hidden";
  }
  lyr = document.getElementById(lyrId);
  wndo = document.getElementById(this.id);
  lyr.style.top = this.y = 0; lyr.style.left = this.x = 0;
  this.maxY = (lyr.offsetHeight - wndo.offsetHeight > 0)? lyr.offsetHeight - wndo.offsetHeight: 0;
  this.wd = cntId? document.getElementById(cntId).offsetWidth: lyr.offsetWidth;
  this.maxX = (this.wd - wndo.offsetWidth > 0)? this.wd - wndo.offsetWidth: 0;
  this.lyrId = lyrId; // hold id of currently visible layer
  lyr.style.visibility = "visible";
  this.cleanAnchors();
  this.on_load(); this.ready = true;
}

dw_scrollObj.prototype.on_load = function() {}  

dw_scrollObj.prototype.shiftTo = function(lyr, x, y) {
  lyr.style.left = (this.x = x) + "px"; 
  lyr.style.top = (this.y = y) + "px";
}

// remove layers from table for ns6+/mozilla (needed for scrolling inside tables)
dw_scrollObj.GeckoTableBugFix = function() {
  var i, wndo, holderId, holder, x, y;
	if ( navigator.userAgent.indexOf("Gecko") > -1 && navigator.userAgent.indexOf("Firefox") == -1 ) {
    dw_scrollObj.hold = []; // holds id's of wndo and its container
    for (i=0; arguments[i]; i++) {
      if ( dw_scrollObjs[ arguments[i] ] ) {
        wndo = document.getElementById( arguments[i] );
        holderId = wndo.parentNode.id;
        holder = document.getElementById(holderId);
        document.body.appendChild( holder.removeChild(wndo) );
        wndo.style.zIndex = 1000;
        x = holder.offsetLeft; y = holder.offsetTop;
        wndo.style.left = x + "px"; wndo.style.top = y + "px";
        dw_scrollObj.hold[i] = [ arguments[i], holderId ];
      }
    }
   window.addEventListener("resize", dw_scrollObj.rePositionGecko, true);
  }
}

// ns6+/mozilla need to reposition layers onresize when scrolling inside tables.
dw_scrollObj.rePositionGecko = function() {
  var i, wndo, holder, x, y;
  if (dw_scrollObj.hold) {
    for (i=0; dw_scrollObj.hold[i]; i++) {
      wndo = document.getElementById( dw_scrollObj.hold[i][0] );
      holder = document.getElementById( dw_scrollObj.hold[i][1] );
      x = holder.offsetLeft; y = holder.offsetTop;
      wndo.style.left = x + "px"; wndo.style.top = y + "px";
    }
  }
}
/*********************************************************************************************************************************/
/* dw_hoverscroll.js  version date: June 2004 
   mouseover scrolling for dw_scrollObj (in dw_scrollObj.js)  */

dw_scrollObj.stopScroll = function(wnId) {
  if ( dw_scrollObjs[wnId] ) dw_scrollObjs[wnId].endScroll();
}

// increase speed onmousedown of scroll links
dw_scrollObj.doubleSpeed = function(wnId) {
  if ( dw_scrollObjs[wnId] ) dw_scrollObjs[wnId].speed *= 2;
}

dw_scrollObj.resetSpeed = function(wnId) {
  if ( dw_scrollObjs[wnId] ) dw_scrollObjs[wnId].speed /= 2;
}

// algorithms for time-based scrolling and scrolling onmouseover at any angle adapted from youngpup.net
dw_scrollObj.initScroll = function(wnId, deg, sp) {
  if ( dw_scrollObjs[wnId] ) {
    var cosine, sine;
    if (typeof deg == "string") {
			re = new RegExp("[0-9]", "g");
			deg = deg.replace(re, "");
			//Debug.debug(deg);
      switch (deg) {
        case "up"    : deg = 90;  break;
        case "down"  : deg = 270; break;
        case "left"  : deg = 180; break;
        case "right" : deg = 0;   break;
        default: 
          alert("Direction of scroll in mouseover scroll links should be 'up', 'down', 'left', 'right' or number: 0 to 360.");
       }
    } 
    deg = deg % 360;
    if (deg % 90 == 0) {
      cosine = (deg == 0)? -1: (deg == 180)? 1: 0;
      sine = (deg == 90)? 1: (deg == 270)? -1: 0;
    } else {
      var angle = deg * Math.PI/180;
      cosine = -Math.cos(angle); sine = Math.sin(angle);
    }
    dw_scrollObjs[wnId].fx = cosine / ( Math.abs(cosine) + Math.abs(sine) );
    dw_scrollObjs[wnId].fy = sine / ( Math.abs(cosine) + Math.abs(sine) );
    dw_scrollObjs[wnId].endX = (deg == 90 || deg == 270)? dw_scrollObjs[wnId].x:
      (deg < 90 || deg > 270)? -dw_scrollObjs[wnId].maxX: 0; 
    dw_scrollObjs[wnId].endY = (deg == 0 || deg == 180)? dw_scrollObjs[wnId].y: 
      (deg < 180)? 0: -dw_scrollObjs[wnId].maxY;
    dw_scrollObjs[wnId].startScroll(sp);
  }
}

// speed (optional) to override default speed (set in dw_scrollObj.speed)
dw_scrollObj.prototype.startScroll = function(speed) {
  if (!this.ready) return; if (this.timerId) clearInterval(this.timerId);
  this.speed = speed || dw_scrollObj.speed;
  this.lyr = document.getElementById(this.lyrId);
  this.lastTime = ( new Date() ).getTime();
  this.on_scroll_start();  
  this.timerId = setInterval(this.animString + ".scroll()", 10); 
}

dw_scrollObj.prototype.scroll = function() {
  var now = ( new Date() ).getTime();
  var d = (now - this.lastTime)/1000 * this.speed;
  if (d > 0) {
    var x = this.x + this.fx * d; var y = this.y + this.fy * d;
    if (this.fx == 0 || this.fy == 0) { // for horizontal or vertical scrolling
      if ( ( this.fx == -1 && x > -this.maxX ) || ( this.fx == 1 && x < 0 ) || 
        ( this.fy == -1 && y > -this.maxY ) || ( this.fy == 1 && y < 0 ) ) {
        this.lastTime = now;
        this.shiftTo(this.lyr, x, y);
        this.on_scroll(x, y);
      } else {
        clearInterval(this.timerId); this.timerId = 0;
        this.shiftTo(this.lyr, this.endX, this.endY);
        this.on_scroll_end(this.endX, this.endY);
      }
    } else { // for scrolling at an angle (stop when reach end on one axis)
      if ( ( this.fx < 0 && x >= -this.maxX && this.fy < 0 && y >= -this.maxY ) ||
        ( this.fx > 0 && x <= 0 && this.fy > 0 && y <= 0 ) ||
        ( this.fx < 0 && x >= -this.maxX && this.fy > 0 && y <= 0 ) ||
        ( this.fx > 0 && x <= 0 && this.fy < 0 && y >= -this.maxY ) ) {
        this.lastTime = now;
        this.shiftTo(this.lyr, x, y);
        this.on_scroll(x, y);
      } else {
        clearInterval(this.timerId); this.timerId = 0;
        this.on_scroll_end(this.x, this.y);
      }
    }
  }
}

dw_scrollObj.prototype.endScroll = function() {
  if (!this.ready) return;
  if (this.timerId) clearInterval(this.timerId);
  this.timerId = 0;  this.lyr = null;
}

dw_scrollObj.prototype.on_scroll = function() {}
dw_scrollObj.prototype.on_scroll_start = function() {}
dw_scrollObj.prototype.on_scroll_end = function() {}

/*************************************************************************dw_event.js (version date Feb 2004)****************/

var dw_event = {
  
  add: function(obj, etype, fp, cap) {
    cap = cap || false;
    if (obj.addEventListener) obj.addEventListener(etype, fp, cap);
    else if (obj.attachEvent) obj.attachEvent("on" + etype, fp);
  }, 

  remove: function(obj, etype, fp, cap) {
    cap = cap || false;
    if (obj.removeEventListener) obj.removeEventListener(etype, fp, cap);
    else if (obj.detachEvent) obj.detachEvent("on" + etype, fp);
  }, 

  DOMit: function(e) { 
    e = e? e: window.event;
    e.tgt = e.srcElement? e.srcElement: e.target;
    
    if (!e.preventDefault) e.preventDefault = function () { return false; }
    if (!e.stopPropagation) e.stopPropagation = function () { if (window.event) window.event.cancelBubble = true; }
        
    return e;
  }
  
}
/*******************************   dw_slidebar.js   version date: Feb 2004   requires dw_event.js   *******************************************/

// model: Aaron Boodman's dom drag at www.youngpup.net
var dw_slidebar = {
  obj: null,
  slideDur: 500,  // duration of glide onclick of track  
  init: function (bar, track, axis, x, y) {
    x = x || 0; y = y || 0;
    bar.style.left = x + "px"; bar.style.top = y + "px";
    bar.axis = axis; track.bar = bar;
    if (axis == "h") {
      bar.trkWd = track.offsetWidth; // hold for setBarSize
      bar.maxX = bar.trkWd - bar.offsetWidth - x; 
      bar.minX = x; bar.maxY = y; bar.minY = y;
    } else {
      bar.trkHt = track.offsetHeight;
      bar.maxY = bar.trkHt - bar.offsetHeight - y; 
      bar.maxX = x; bar.minX = x; bar.minY = y;
    }
    bar.on_drag_start =  bar.on_drag =   bar.on_drag_end = 
    bar.on_slide_start = bar.on_slide =  bar.on_slide_end = function() {}
    bar.onmousedown = this.startDrag; track.onmousedown = this.startSlide;
  },
  
  startSlide: function(e) { // called onmousedown of track 
    if ( dw_slidebar.aniTimer ) clearInterval(dw_slidebar.aniTimer);
    e = e? e: window.event;
    var bar = dw_slidebar.obj = this.bar; // i.e., track's bar
    e.offX = (typeof e.layerX != "undefined")? e.layerX: e.offsetX;
    e.offY = (typeof e.layerY != "undefined")? e.layerY: e.offsetY;
    bar.startX = parseInt(bar.style.left); bar.startY = parseInt(bar.style.top);
    if (bar.axis == "v") {
      bar.destX = bar.startX;
      bar.destY = (e.offY < bar.startY)? e.offY: e.offY - bar.offsetHeight;
      bar.destY = Math.min( Math.max(bar.destY, bar.minY), bar.maxY );
    } else {
      bar.destX = (e.offX < bar.startX)? e.offX: e.offX - bar.offsetWidth;
      bar.destX = Math.min( Math.max(bar.destX, bar.minX), bar.maxX );
      bar.destY = bar.startY;
    }
    bar.distX = bar.destX - bar.startX; bar.distY = bar.destY - bar.startY;
    dw_slidebar.per = Math.PI/(2 * dw_slidebar.slideDur);
  	dw_slidebar.slideStart = (new Date()).getTime();
    bar.on_slide_start(bar.startX, bar.startY);
  	dw_slidebar.aniTimer = setInterval("dw_slidebar.doSlide()",10);
  },
  
  doSlide: function() {
    if ( !dw_slidebar.obj ) { clearInterval(dw_slidebar.aniTimer); return; }    
    var bar = dw_slidebar.obj;     
    var elapsed = (new Date()).getTime() - this.slideStart;
  	if (elapsed < this.slideDur) {
  		var x = bar.startX + bar.distX * Math.sin(this.per*elapsed);
  		var y = bar.startY + bar.distY * Math.sin(this.per*elapsed);
      bar.style.left = x + "px"; bar.style.top = y + "px";
      bar.on_slide(x, y);
  	} else {	// if time's up
      clearInterval(this.aniTimer);
      bar.style.left = bar.destX + "px"; bar.style.top = bar.destY + "px";
      bar.on_slide_end(bar.destX, bar.destY);
      this.obj = null;
  	}
  },
  
  startDrag: function (e) { // called onmousedown of bar 
    e = dw_event.DOMit(e);
    if ( dw_slidebar.aniTimer ) clearInterval(dw_slidebar.aniTimer);
    var bar = dw_slidebar.obj = this;
    bar.downX = e.clientX; bar.downY = e.clientY;
    bar.startX = parseInt(bar.style.left);
    bar.startY = parseInt(bar.style.top);
    bar.on_drag_start(bar.startX, bar.startY);
    dw_event.add( document, "mousemove", dw_slidebar.doDrag, true );
    dw_event.add( document, "mouseup",   dw_slidebar.endDrag,  true );
    e.stopPropagation();
  },

  doDrag: function (e) {
    e = e? e: window.event;
    if (!dw_slidebar.obj) return;
    var bar = dw_slidebar.obj; 
    var nx = bar.startX + e.clientX - bar.downX;
    var ny = bar.startY + e.clientY - bar.downY;
    nx = Math.min( Math.max( bar.minX, nx ), bar.maxX);
    ny = Math.min( Math.max( bar.minY, ny ), bar.maxY);
    bar.style.left = nx + "px"; bar.style.top  = ny + "px";
    bar.on_drag(nx,ny);
    return false;  
  },
  
  endDrag: function () {
    dw_event.remove( document, "mousemove", dw_slidebar.doDrag, true );
    dw_event.remove( document, "mouseup",   dw_slidebar.endDrag,  true );
    if ( !dw_slidebar.obj ) return; // avoid errors in ie if inappropriate selections
    dw_slidebar.obj.on_drag_end( parseInt(dw_slidebar.obj.style.left), parseInt(dw_slidebar.obj.style.top) );
    dw_slidebar.obj = null;  
  }
  
}
/************************************** dw_scroll_aux.js    version date: May 2004  *******************************************************
  integrates scrolling layers code with scrollbar code (dw_scrollbar.js)
*********************************************************************************************************************************************/

// Size dragBar according to layer size?  
dw_scrollObj.prototype.bSizeDragBar = true;

dw_scrollObj.prototype.setUpScrollbar = function(id, trkId, axis, offx, offy) {
  if (!document.getElementById) return;
  var bar = document.getElementById(id);
  var trk = document.getElementById(trkId);
  dw_slidebar.init(bar, trk, axis, offx, offy);
  // connect dw_slidebar with dw_scrollObj
  bar.wn = dw_scrollObjs[this.id]; // scroll area object this bar connected to
  if (axis == "v") this.vBarId = id; else this.hBarId = id;
  // also called on_load (i.e., when layer loaded), but in case h and v scrollbars, need to call here too
  if (this.bSizeDragBar) this.setBarSize();
  bar.on_drag_start = bar.on_slide_start = dw_scrollObj.getWndoLyrRef;
  bar.on_drag_end =   bar.on_slide_end =   dw_scrollObj.tossWndoLyrRef;
  bar.on_drag =       bar.on_slide =       dw_scrollObj.UpdateWndoLyrPos;
}

// for these 3 functions (assigned to bar.on_drag/slide...) "this" refers to bar
// get/discard ref to layer visible in scroll area
dw_scrollObj.getWndoLyrRef = function()  { this.wnLyr = document.getElementById(this.wn.lyrId); }
dw_scrollObj.tossWndoLyrRef = function() { this.wnLyr = null; }
// keep position of scrolling layer in synch with slide/drag of bar
dw_scrollObj.UpdateWndoLyrPos = function(x, y) {
  var nx, ny;
  if (this.axis == "v") {
    nx = this.wn.x; // floating point values for loaded layer's position held in shiftTo method
    ny = -(y - this.minY) * ( this.wn.maxY / (this.maxY - this.minY) ) || 0;
  } else {
    ny = this.wn.y;
    nx = -(x - this.minX) * ( this.wn.maxX / (this.maxX - this.minX) ) || 0;
  }
  this.wn.shiftTo(this.wnLyr, nx, ny);
}

// Keep position of dragBar in sync with position of layer onscroll
dw_scrollObj.prototype.updateScrollbar = function(x, y) {
  var nx, ny;
  if ( this.vBarId ) {
    if (!this.maxY) return;
    if(!this.vbar) this.vbar = $(this.vBarId);
	ny = -( y * ( (this.vbar.maxY - this.vbar.minY) / this.maxY ) - this.vbar.minY );
    ny = Math.min( Math.max(ny, this.vbar.minY), this.vbar.maxY);  
    nx = parseInt(this.vbar.style.left);
    this.vbar.style.left = nx + "px"; this.vbar.style.top = ny + "px";
  } if ( this.hBarId ) {
    if (!this.maxX) return;
    if(!this.hbar) this.hbar = $(this.hBarId);
    nx = -( x * ( (this.hbar.maxX - this.hbar.minX) / this.maxX ) - this.hbar.minX );
    nx = Math.min( Math.max(nx, this.hbar.minX), this.hbar.maxX);
    ny = parseInt(this.hbar.style.top);
    this.hbar.style.left = nx + "px"; this.hbar.style.top = ny + "px";
  } 
  
}

// Restore dragBar to start position when loading new layer
dw_scrollObj.prototype.restoreScrollbars = function() {
  var bar;
  if (this.vBarId) {
    bar = document.getElementById(this.vBarId);
    bar.style.left = bar.minX + "px"; bar.style.top = bar.minY + "px";
  }
  if (this.hBarId) {
    bar = document.getElementById(this.hBarId);
    bar.style.left = bar.minX + "px"; bar.style.top = bar.minY + "px";
  }
}
  
// Size dragBar in proportion to size of content in layer
// called on_load of layer if bSizeDragBar prop true
dw_scrollObj.prototype.setBarSize = function() {
  var bar;
  var lyr = document.getElementById(this.lyrId);
  var wn = document.getElementById(this.id);
  if (this.vBarId) {
    bar = document.getElementById(this.vBarId);
    bar.style.height = (lyr.offsetHeight > wn.offsetHeight)? bar.trkHt / ( lyr.offsetHeight / wn.offsetHeight ) + "px": bar.trkHt - 2*bar.minY + "px";
    bar.maxY = bar.trkHt - bar.offsetHeight - bar.minY; 
  }
  if (this.hBarId) {
    bar = document.getElementById(this.hBarId);
    bar.style.width = (this.wd > wn.offsetWidth)? bar.trkWd / ( this.wd / wn.offsetWidth ) + "px": bar.trkWd - 2*bar.minX + "px";
    bar.maxX = bar.trkWd - bar.offsetWidth - bar.minX; 
  }
}

// called from load method
dw_scrollObj.prototype.on_load = function() { 
  this.restoreScrollbars();
  if (this.bSizeDragBar) this.setBarSize();
}

dw_scrollObj.prototype.on_scroll = dw_scrollObj.prototype.on_slide = function(x,y) { this.updateScrollbar(x,y); }

// obtain and discard references to relevant dragBar
dw_scrollObj.prototype.on_scroll_start = dw_scrollObj.prototype.on_slide_start = function() {
  if ( this.vBarId ) this.vbar = document.getElementById(this.vBarId);
  if ( this.hBarId ) this.hbar = document.getElementById(this.hBarId);
}

dw_scrollObj.prototype.on_scroll_end = dw_scrollObj.prototype.on_slide_end = function(x, y) { 
  this.updateScrollbar(x,y);
  this.lyr = null; this.bar = null; 
}

//Added by Dave Grijalva
//Fix for anchor links within scroll box
dw_scrollObj.prototype.cleanAnchors = function(){
	var links = {};
	//collect all links with #anchors
	$NL($(this.id).getElementsByTagName('a')).each(function(link){
		var href = link.getAttribute('href');
		var name = link.getAttribute('name');

		if(name){
			if(!links[name]) links[name] = {};
			links[name]['target'] = link;
		}
		
		if(href){
			var hash = href.replace(/.*#(.*)/i, '$1');
			if(hash.length){
				if(!links[hash]) {
					links[hash] = {};
					links[hash].elements = new Array()
				}
				links[hash].elements.push(link);
			}
		}
	});
	
	for(key in links){
		if(links[key].elements && links[key]['target']){
			var link = links[key];
			//kill link to #anchor
			for(var i=0; i<link.elements.length; i++) {
				var element = link.elements[i];	
				element.href = 'javascript:;';
				element.setAttribute('anchor_key', key);
				//attach event for custom scroll
				var t = link['target'];
				Event.observe(element, 'click', this.scrollToAnchor.bindAsEventListener(this));
			}
		}
	}
}

dw_scrollObj.prototype.scrollToAnchor = function(event){
	var element = Event.element(event);
	var anchor_key = element.getAttribute('anchor_key');
	var anchor = $NL($(this.id).getElementsByTagName('a')).find(function(e){return e.name == anchor_key});
	var anchor_offset = Dom.getTopY(anchor, $(this.id));
	anchor_offset = (anchor_offset < this.maxY ? anchor_offset : this.maxY) * -1;
	this.shiftTo($(this.lyrId), 0, anchor_offset);
	this.on_scroll(0, anchor_offset);
}
	/**********************************************************************************************/
/* Function footer(ftContainerArray,spacingW3C,spacingIE)            													*/
/*                                                                            								*/
/* Takes 3 parameters (prototype required):                                    								*/
/* ftContainerArray: Array of container ids (Required)  																			*/
/* Spacing: (optional) - Used to fix spacing																								  */
/* spacingW3C: spacing Between lowest container and the footer for W3C compliant-browsers     */
/* spacingIE: spacing Between lowest container and the footer for Internet Explorer           */
/*          Defaults to 20px. It can be set to a positive or a negative value                 */
/*																																														*/
/* Site-wide CSS File: Set #ftArea{display:none;position:absolute;} 													*/
/*																																														*/
/*	For a page that contains 2 container divs, call the function as follow in the page:       */
/*        // Pushes The footer below content   																								*/
/*        var ftContainerArray = new Array('mainContent','rightContent');                     */
/*				vent.observe(window, 'load', function(){footer(ftContainerArray);}, false);        */
/*																																														*/
/* Last Modified: August 28, 2006                                             								*/
/* Author: Christian Dumais                                                   								*/
/**********************************************************************************************/
function footer(ftContainerArray,spacingW3C,spacingIE){
	var ft = null;
	var sp_w3c = (spacingW3C==null)?20:spacingW3C;
	var sp_ie = (spacingIE==null)?20:spacingIE;
	if ($('ftArea')!=null){
		ft = $('ftArea');
		/* Finding if one of the container is lower than the Side Nav and by how much */
		isContainerLower = getLower(ftContainerArray);
		/* Side Nav exist and is lower */
		if (!isContainerLower){
			ft.style.top = Dom.getBottomY($('sn_wrapper')) + "px";
		}
		/* Side Nav is NOT Lower or may not exist */
		else{
			/* Set the footer below the lowest container */
			ft.style.top = isContainerLower + ((document.all)?sp_ie:sp_w3c) + "px";
		}
		ft.style.display = "block";
	}
}
/* This function will find if the Side Nav exist and if it is the lowest container */
function getLower(arr){
	//if($(arr[0])) {
		var biggest = Dom.getBottomY($(arr[0]));
	//}
	
	for (var i=0;i<arr.length;i++){
		if($(arr[i]) && Dom.getBottomY($(arr[i]))>biggest){
				biggest = Dom.getBottomY($(arr[i]));
		}
	}
	sny = ($('sn_wrapper'))?Dom.getBottomY($('sn_wrapper')):null;
	if (sny!=null && sny>biggest){
		/* Side Nav exist and is lower */
		return false;
	}
	else{
		/* Side Nav is NOT lower or may not exist, return biggest Y value */
		return biggest;
	}
}
	
/**
 * PLUGIN FRAMEWORK, Version 0.5
 * For details, see the Knallgrau web site: http://www.knallgrau.code/prototype/plugins_js
 * Copyright (c) 2006 Matthias Platzer <matthias@knallgrau.at>
 * This code is freely distributable under the terms of an MIT-style license.
 * 
 ***********************************************************************************
 *  Copyright (c) 2006 Matthias Platzer <matthias@knallgrau.at>
 *  
 *  Permission is hereby granted, free of charge, to any person obtaining a copy 
 *  of this software and associated documentation files (the "Software"), to deal 
 *  in the Software without restriction, including without limitation the rights 
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 *  copies of the Software, and to permit persons to whom the Software is 
 *  furnished to do so, subject to the following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included in 
 *  all copies or substantial portions of the Software.
 *  
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 *
 ***********************************************************************************
 *
 *  inspired by Prototype JavaScript framework
 *
 *  Provides the following functions
 *    // name accepts: 
 *    // Acrobat, QuickTime, DivX, Director, 
 *    // 'Windows Media', Flash, Java, RealPlayer, VLC
 *    Plugin.isInstalled(String name) 
 *    Plugin.getVersion(String name)
 *    Plugin.getPluginsForMimeType(String mimeType)  // returns Array of Plugin Names
 *    Plugin.getPluginsForFileSuffix(String suffix)  // returns Array of Plugin Names
 *    Plugin.embed(pluginName, options, target)
 *    Plugin.getInfo(String name) 
 *      // Result Object contains informations about the plugin
 *      Boolean isInstalled
 *      String  version
 *      String  description
 *      Array   progID        to be used with new ActiveXObject()
 *      String  classID       for ActiveX
 *      String  pluginsPage   URL to download the plugin
 *      Array   acceptedMimeTypes  provides MimeType info for IE
 *
 * CHANGELOG:
 * 17.12.2005: Version 0.1
 *   initial version
 * 18.12.2005: Version 0.2
 *   added mimetypes for divx & co.
 *   added VLC support (detection for IE is missing)
 *   renamed getPluginsForMimeType, getPluginsForFileSuffix -> returns Array, instead of String
 *   dropped support vor Adobe SVG (IE)
 *   tested and debugged RealPlayer -> still reports a strange version number
 *   fixed bugs where script did break on unknown name attribute
 *   added experimental Plugin.embed
 * 20.12.2005: Version 0.3
 *   added docs
 *   added license
 *   rewrote Plugin.embed -> now it's easier to add new formats
 *   downloadURL became pluginsPage
 *   added mimeType, activeXType and codeBase to Plugin.PLUGINS
 *   Plugin.embed accepts strings as target (id)
 *   Added Plugin.embed support for Flash, RealPlayer and VLC
 * 23.03.2006: Version 0.4
 *   Fixed a few warnings reported by firefox in javascript strict mode (reported by Olav Roth)
 * 13.04.2006: Version 0.5
 *   Improved support for Windows Media Plugin
 *   - use WM6.4 ClassID instead of WM7 (this fixes a lot of bad behaviour, like missing controls)
 *   - detect installed ActiveX support for Mozilla (Firefox)
 *   - added support for forceObjectTag as a sideeffect
 *   Fixed a bug with embeding VLC (src needs to be present in the embed tag)
 *   Updated DivX support to final Version 1.0
 * 
 * you may remove the comments section, but please leave the copyright
/*--------------------------------------------------------------------------*/

var PluginFactory = function() {

  // Returns if plugin with identifier name is installed
  // @see Plugin.getInfo
  this.isInstalled = function(name) {
    return Plugin.getInfo(name).isInstalled;
  }

  // Returns version number of plugin if available
  // @see Plugin.getInfo
  this.getVersion = function(name) {
    return Plugin.getInfo(name).version;
  }
	
  this.getVersionAsFloat = function(name) {
    if(!Plugin.getInfo(name).version && Plugin.getInfo(name).version == "")
    	return 0;
    else
    	return parseFloat(Plugin.getInfo(name).version);
  }	
  // Returns an Array of plugin identifier names, 
  // that can handle this mimeType.
  this.getPluginsForMimeType = function(mimeType) {
    var result = [];
    if (supportsNavigatorPlugins()) {
      // navigator.mimeTypes
      for (var i=0; i<navigator.mimeTypes.length; i++) {
        if (navigator.mimeTypes[i].type.indexOf(mimeType) == 0 && navigator.mimeTypes[i].enabledPlugin) {
          var pluginName = (findPluginName(navigator.mimeTypes[i].enabledPlugin.name) || navigator.mimeTypes[i].enabledPlugin.name);
          if (!Array.contains(result, pluginName)) result.push(pluginName);
        }
      }
    } else {
      // Code for IE using ActiveX
      for (var pluginName in Plugin.PLUGINS) {
        var mimeTypes = Plugin.PLUGINS[pluginName].acceptedMimeTypes;
        if (!mimeTypes) continue;
        for (var j=0; j<mimeTypes.length; j++) {
          if (mimeTypes[j].type.indexOf(mimeType) == 0 && Plugin.isInstalled(pluginName)) {
            if (!Array.contains(result, pluginName)) result.push(pluginName);
          }
        }
      }    
    }
    return result;
  }

  // Returns an Array of plugin identifier names, 
  // that can handle a file with this suffix.
  this.getPluginsForFileSuffix = function(suffix) {
    var result = [];
    if (supportsNavigatorPlugins()) {
      // navigator.mimeTypes
      for (var i=0; i<navigator.mimeTypes.length; i++) {
        if ((","+navigator.mimeTypes[i].suffixes+",").indexOf(","+suffix+",") != -1 && navigator.mimeTypes[i].enabledPlugin) {
          var pluginName = (findPluginName(navigator.mimeTypes[i].enabledPlugin.name) || navigator.mimeTypes[i].enabledPlugin.name);
          if (!Array.contains(result, pluginName)) result.push(pluginName);
        }
      }
    } else {
      // Code for IE using ActiveX
      for (var pluginName in Plugin.PLUGINS) {
        var mimeTypes = Plugin.PLUGINS[pluginName].acceptedMimeTypes;
        if (!mimeTypes) continue;
        for (var j=0; j<mimeTypes.length; j++) {
          if ((","+mimeTypes[j].suffixes+",").indexOf(","+suffix+",") != -1 && Plugin.isInstalled(pluginName)) {
            if (!Array.contains(result, pluginName)) result.push(pluginName);
          }
        }
      }    
    }
    return result;
  }

  // Returns general information about a plugin.
  // accepts: Acrobat, QuickTime, DivX, Director, 'Windows Media', 
  //          Flash, Java, RealPlayer, VLC
  this.getInfo = function(name) {

    var info = Plugin.PLUGINS[name];
    var isInstalled = false;
    var version = null;

    if (supportsNavigatorPlugins()) {
      // navigator.plugins
      var plugin = findNavigatorPluginByName((name == "RealPlayer") ? "RealPlayer Version Plugin" : name);
      if (plugin) {
        isInstalled = true;
        version = getVersionFromPlugin(plugin);
      }

    } else {
      // Code for IE using ActiveX
      isInstalled = hasActiveXObject(Plugin.PLUGINS[name] && Plugin.PLUGINS[name].progID);
      if (isInstalled) {
        if (Plugin.PLUGINS[name].getActiveXVersionInfo) {
          version = Plugin.PLUGINS[name].getActiveXVersionInfo();
        } else {
          // assume that the progID contains the version number
          // this is not always correct
          var progID = getProgIdForActiveXObject(Plugin.PLUGINS[name].progID);
          version = getVersionFromPlugin(progID);
        }
      } else {
        version = getActiveXPluginByClassId(Plugin.PLUGINS[name] && Plugin.PLUGINS[name].classID);
        if (version) version = version.replace(/,/g, ".");
        isInstalled = (version!=undefined);
      }

    }

    var result = {};
    for (var i in info) {
      result[i] = info[i];
    }
    result["isInstalled"] = isInstalled;
    result["version"] = version;
    result["name"] = name;

    return result;
  }

/**
 * writes an embed or object tag to document.write or target.
 * @param plugin   name of the plugin to be used
 * @param options  options for embed respectivly object tag.
 *   .src,.width,.height,.type,.activeXType will get a special treatment
 *   all other properties of options will be added to the 
 *   embed tag as attributes resp. to the object tag as param(eters).
 *   option names should be lower case!
 * @param target   optional (id of) container element for the embed/object tag
 */
  this.embed = function(plugin, options, target) {
    options = options || {};

    var embedOptions = Object.extend({}, options);
    var src = embedOptions.src;
    delete embedOptions.src;
    var id = embedOptions.id;
    delete embedOptions.id;
    var name = embedOptions.name || id;
    delete embedOptions.name;
    var width = embedOptions.width;
    delete embedOptions.width;
    var height = embedOptions.height;
    delete embedOptions.height;
    var type = embedOptions.type || (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].mimeType) || "";
    delete embedOptions.type;
    var activeXType = embedOptions.activeXType || (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].activeXType) || type;
    delete embedOptions.activeXType;
    var forceEmbedTag = (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].forceEmbedTag === true) ? true : false;
    var forceObjectTag = (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].forceObjectdTag === true) ? true : false;

    var embedOptions = Object.extend(((Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].standardEmbedAttributes) || {}), embedOptions);

    switch (plugin) {
      case "QuickTime":
        // get space for controlls
        if (embedOptions.controller == "true" && (height+"").indexOf("%") == -1) {
          height += 16;
        }
        if (!options.activeXType) {
          activeXType = null;
        }
        break;

      case "DivX":
        // get space for controlls
        if ((height+"").indexOf("%") == -1) {
          if (embedOptions.mode == "mini") height += 20;
          else if (embedOptions.mode == "large") height += 65;
          else if (embedOptions.mode == "full") height += 90;
        }
        break;

      case "Windows Media":
        // check if ActiveX for Firefox is installed
        // http://help.yahoo.com/help/us/launch/videos/videos-07.html
        if (!supportsNavigatorPlugins() || window.GeckoActiveXObject) {
           forceObjectTag = true;
        }
        // get space for controlls
        if ((window.ActiveXObject || window.GeckoActiveXObject || window.opera) &&
            (height+"").indexOf("%") == -1) {
          height += 45;
        }
        break;

      case "Flash":
        // flash wants the src to be named "movie" if passed as object param
        if (!supportsNavigatorPlugins()) {
          embedOptions.movie = src;
          src = null;
        }
        break;

      case "VLC":
        // VLC wants the src to be named "target"
        // update: that's actualy wrong, even it's documented like that!
        if (supportsNavigatorPlugins()) {
          embedOptions.target = src;
        }
        break;

      case "RealPlayer":
        break;        

      default: 
        // do nothing
        break;
    }

    // prepare html code
    var html = "";
    if ((supportsNavigatorPlugins() && ! forceObjectTag) || forceEmbedTag) {
      // Netscape Plugin embed Tag
      html += '<embed' + getAttributeHtml("src", src)  + getAttributeHtml("id", id) + getAttributeHtml("name", name) + getAttributeHtml("width", width) + getAttributeHtml("height", height) + getAttributeHtml("pluginspage", Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].pluginsPage) + getAttributeHtml("type", type);
      for (var i in embedOptions) {
        html += ' '+i+'="'+embedOptions[i]+'"';
      }
      html += '></embed>\n';
    } else {
      // ActiveX object tag
      html += '<object classid="clsid:'+(Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].classID)+'"';
      html += getAttributeHtml("id", id) + getAttributeHtml("name", name) + getAttributeHtml("width", width) + getAttributeHtml("height", height) + getAttributeHtml("codebase", (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].codeBase)) + getAttributeHtml("type", activeXType) + '>\n';
      html += (src) ? '  <param name="src" value="'+src+'">\n' : '';
      for (var i in embedOptions) {
        html += '  <param name="'+i+'" value="'+embedOptions[i]+'" />';
      }
      html += '</object>\n';
    }

    if (target) {
      if (typeof target == "string") target = document.getElementById(target);
      target.innerHTML = html;
    } else {
      document.write(html);
    }
  }

  var getAttributeHtml = function(name, value) {
    return (value) ? (" " + name + "=\"" + value + "\"") : "";
  }

  // Info about known plugins
  this.PLUGINS = {
    "Acrobat": {
      description: "Adobe Acrobat Plugin",
      progID: ["PDF.PdfCtrl.7", "PDF.PdfCtrl.6", "PDF.PdfCtrl.5", "PDF.PdfCtrl.4", "PDF.PdfCtrl.3", "AcroPDF.PDF.1"],
      classID: "CA8A9780-280D-11CF-A24D-444553540000",
      pluginsPage: "http://www.adobe.com/products/acrobat/readstep2.html",
      acceptedMimeTypes: [
        { type: "application/pdf", suffixes: "pdf" },
        { type: "application/vnd.fdf", suffixes: "fdf" },
        { type: "application/vnd.adobe.xfdf", suffixes: "xfdf" },
        { type: "application/vnd.adobe.xdp+xml", suffixes: "xdp" },
        { type: "application/vnd.adobe.xfd+xml", suffixes: "xfd" }
      ]
    },
    "QuickTime": {
      description: "QuickTime Plug-in",
      progID: ["QuickTimeCheckObject.QuickTimeCheck.1", "QuickTime.QuickTime"],
      classID: "02BF25D5-8C17-4B23-BC80-D3488ABDDC6B",
      pluginsPage: "http://www.apple.com/quicktime/download/",
      codeBase: "http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0",
      mimeType: "video/quicktime",
      standardEmbedAttributes: {
        autoplay: "false"
      },
      // embedInfo: http://www.apple.com/quicktime/tutorials/embed.html 
      //            http://developer.apple.com/quicktime/compatibility.html
      getActiveXVersionInfo: function() { 
        var progID = getProgIdForActiveXObject(Plugin.PLUGINS["QuickTime"].progID); 
        var obj = new ActiveXObject(progID);
        var version = (obj && obj.QuickTimeVersion) ? obj.QuickTimeVersion.toString(16) : "";
        return version.substring(0,1) + '.' + version.substring(1,2) + '.' + version.substring(2,3);
      },
      acceptedMimeTypes: [
        { type: "image/tiff", suffixes: "tif,tiff" },
        { type: "image/x-tiff", suffixes: "tif,tiff" },
        { type: "video/x-m4v", suffixes: "m4v" },
        { type: "image/x-macpaint", suffixes: "pntg,pnt,mac" },
        { type: "image/pict", suffixes: "pict,pic,pct" },
        { type: "image/x-pict", suffixes: "pict,pic,pct" },
        { type: "image/x-quicktime", suffixes: "qtif,qti" },
        { type: "image/x-sgi", suffixes: "sgi,rgb" },
        { type: "image/x-targa", suffixes: "targa,tga" },
        { type: "audio/3gpp", suffixes: "3gp,3gpp" },
        { type: "video/3gpp2", suffixes: "3g2,3gp2" },
        { type: "audio/3gpp2", suffixes: "3g2,3gp2" },
        { type: "video/sd-video", suffixes: "sdv" },
        { type: "application/x-mpeg", suffixes: "amc" },
        { type: "video/mp4", suffixes: "mp4" },
        { type: "audio/mp4", suffixes: "mp4" },
        { type: "audio/x-m4a", suffixes: "m4a" },
        { type: "audio/x-m4p", suffixes: "m4p" },
        { type: "audio/x-m4b", suffixes: "m4b" },
        { type: "video/mpeg", suffixes: "mpeg,mpg,m1s,m1v,m1a,m75,m15,mp2,mpm,mpv,mpa" },
        { type: "audio/mpeg", suffixes: "mpeg,mpg,m1s,m1a,mp2,mpm,mpa,m2a" },
        { type: "audio/x-mpeg", suffixes: "mpeg,mpg,m1s,m1a,mp2,mpm,mpa,m2a" },
        { type: "video/3gpp", suffixes: "3gp,3gpp" },
        { type: "audio/x-gsm", suffixes: "gsm" },
        { type: "audio/AMR", suffixes: "AMR" },
        { type: "audio/aac", suffixes: "aac,adts" },
        { type: "audio/x-aac", suffixes: "aac,adts" },
        { type: "audio/x-caf", suffixes: "caf" },
        { type: "video/x-mpeg", suffixes: "mpeg,mpg,m1s,m1v,m1a,m75,m15,mp2,mpm,mpv,mpa" },
        { type: "audio/aiff", suffixes: "aiff,aif,aifc,cdda" },
        { type: "audio/x-aiff", suffixes: "aiff,aif,aifc,cdda" },
        { type: "audio/basic", suffixes: "au,snd,ulw" },
        { type: "audio/mid", suffixes: "mid,midi,smf,kar" },
        { type: "audio/x-midi", suffixes: "mid,midi,smf,kar" },
        { type: "audio/midi", suffixes: "mid,midi,smf,kar" },
        { type: "audio/vnd.qcelp", suffixes: "qcp" },
        { type: "application/sdp", suffixes: "sdp" },
        { type: "application/x-sdp", suffixes: "sdp" },
        { type: "application/x-rtsp", suffixes: "rtsp,rts" },
        { type: "video/quicktime", suffixes: "mov,qt,mqv" },
        { type: "video/flc", suffixes: "flc,fli,cel" },
        { type: "audio/x-wav", suffixes: "wav,bwf" },
        { type: "audio/wav", suffixes: "wav,bwf" }
      ]
    },
    "DivX": {
      description: "DivX Browser Plugin",
      progID: ["npdivx.DivXBrowserPlugin.1", "npdivx.DivXBrowserPlugin"],
      classID: "67DABFBF-D0AB-41fa-9C46-CC0F21721616",
      codeBase: "http://go.divx.com/plugin/DivXBrowserPlugin.cab",
      pluginsPage: "http://go.divx.com/plugin/download/",
      mimeType: "video/divx",
      standardEmbedAttributes: {
        mode: "mini",
        minversion: "1.0.0"
      },
      // embedInfo: Beta1: http://labs.divx.com/archives/000072.html
      //            SDK&Doc: http://download.divx.com/labs/Webmaster_SDK.zip
      getActiveXVersionInfo2: function() {
        var progID = getProgIdForActiveXObject(Plugin.PLUGINS["DivX"].progID); 
        return "1.0.0"; // that's the only currently available
      },
      acceptedMimeTypes: [
        { type: "video/divx", suffixes: "dvx,divx" }
      ]
    },
    "Director": {
      description: "Macromedia Director",
      progID: ["SWCtl.SWCtl.11","SWCtl.SWCtl.10","SWCtl.SWCtl.9","SWCtl.SWCtl.8","SWCtl.SWCtl.7","SWCtl.SWCtl.6","SWCtl.SWCtl.5","SWCtl.SWCtl.4"],
      classID: "166B1BCA-3F9C-11CF-8075-444553540000",
      pluginsPage: "http://www.macromedia.com/shockwave/download/",
      codeBase: "http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0",
      mimeType: "application/x-director"
    },         
    "Flash": {
      description: "Macromedia Shockwave Flash",
      progID: ["ShockwaveFlash.ShockwaveFlash.9", "ShockwaveFlash.ShockwaveFlash.8.5", "ShockwaveFlash.ShockwaveFlash.8", "ShockwaveFlash.ShockwaveFlash.7", "ShockwaveFlash.ShockwaveFlash.6", "ShockwaveFlash.ShockwaveFlash.5", "ShockwaveFlash.ShockwaveFlash.4"],
      classID: "D27CDB6E-AE6D-11CF-96B8-444553540000",
      pluginsPage: "http://www.macromedia.com/go/getflashplayer",
      codeBase: "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0",
      mimeType: "application/x-shockwave-flash",
      standardEmbedAttributes: {
        quality: "high"
      },
      // embedInfo: http://www.macromedia.com/cfusion/knowledgebase/index.cfm?id=tn_4150
      //            http://www.macromedia.com/cfusion/knowledgebase/index.cfm?id=tn_12701
      acceptedMimeTypes: [
        { type: "application/x-shockwave-flash", suffixes: "swf" },
        { type: "application/futuresplash", suffixes: "spl" }
      ]
    }, 
    "VLC": {
      description: "VLC multimedia plugin",
      progID: [],
      classID: "",
      pluginsPage: "http://www.videolan.org/doc/play-howto/en/ch02.html#id287569",
      codeBase: "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0",
      mimeType: "application/x-vlc-plugin",
      standardEmbedAttributes: {
        quality: "high",
        autoplay: "no"
      },
      // embedInfo: http://www.videolan.org/doc/vlc-user-guide/en/ch07.html
      //            http://www.videolan.org/doc/play-howto/en/ch04.html#id293251
      acceptedMimeTypes: [
        { type: "audio/mpeg", suffixes: "mp2,mp3,mpga,mpega" },
        { type: "audio/x-mpeg", suffixes: "mp2,mp3,mpga,mpega" },
        { type: "video/mpeg", suffixes: "mpg,mpeg,mpe" },
        { type: "video/x-mpeg", suffixes: "mpg,mpeg,mpe" },
        { type: "video/mpeg-system", suffixes: "mpg,mpeg,vob" },
        { type: "video/x-mpeg-system", suffixes: "mpg,mpeg,vob" },
        { type: "video/mpeg4", suffixes: "mp4,mpg4" },
        { type: "audio/mpeg4", suffixes: "mp4,mpg4" },
        { type: "application/mpeg4-iod", suffixes: "mp4,mpg4" },
        { type: "application/mpeg4-muxcodetable", suffixes: "mp4,mpg4" },
        { type: "video/x-msvideo", suffixes: "avi" },
        { type: "video/quicktime", suffixes: "mov,qt" },
        { type: "application/x-ogg", suffixes: "ogg" },
        { type: "application/x-vlc-plugin", suffixes: "*" },
        { type: "video/x-ms-asf-plugin", suffixes: "asf,asx,*" },
        { type: "video/x-ms-asf", suffixes: "asf,asx,*" },
        { type: "application/x-mplayer2", suffixes: "dvx,divx,ivx,xvid,ivf,*" },
        { type: "video/x-ms-wmv", suffixes: "wmv,*" },
        { type: "application/x-google-vlc-plugin", suffixes: "*" }      
      ]
    },
    "Windows Media": {
      description: "Windows Media Player Plug-in Dynamic Link Library",
      progID: ["WMPlayer.OCX", "MediaPlayer.MediaPlayer.1"],
      classID: "22D6f312-B0F6-11D0-94AB-0080C74C7E95", // WMP6 -> semms to work a lot better, don't know why
      // classID: "6BF52A52-394A-11D3-B153-00C04F79FAA6", // WMP7+ -> doesn't work for me
      pluginsPage: "http://www.microsoft.com/windows/windowsmedia/",
      codeBase: "http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,0,02,902",
      mimeType: "application/x-mplayer2",
      activeXType: "application/x-oleobject",
      standardEmbedAttributes: {
        autoplay: "false"
      },
      // embedInfo: http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/samples/internet/imedia/netshow/crossbrowserembed/default.asp
      getActiveXVersionInfo: function() { 
        var progID = getProgIdForActiveXObject(Plugin.PLUGINS["Windows Media"].progID); 
        var obj = new ActiveXObject(progID);
        return (obj && obj.versionInfo) ? obj.versionInfo : "";
      },
      acceptedMimeTypes: [
        { type: "application/asx", suffixes: "*" },
        { type: "video/x-msvideo", suffixes: "avi" },
        { type: "video/x-ms-asf-plugin", suffixes: "*" },
        { type: "application/x-mplayer2", suffixes: "dvx,divx,ivx,xvid,ivf,*" },
        { type: "video/x-ms-asf", suffixes: "asf,asx,*" },
        { type: "video/x-ms-wm", suffixes: "wm,*" },
        { type: "audio/x-ms-wma", suffixes: "wma,*" },
        { type: "audio/x-ms-wax", suffixes: "wax,*" },
        { type: "video/x-ms-wmv", suffixes: "wmv,*" },
        { type: "video/x-ms-wvx", suffixes: "wvx,*" }
      ]
    },
    "Java": {
      description: "Java Virtual Machine",
      progID: [],
      classID: "08B0E5C0-4FCB-11CF-AAA5-00401C608500",
      pluginsPage: "http://www.java.com/de/download/manual.jsp",
      acceptedMimeTypes: [
        { type: "application/x-java-applet", suffixes: "" },
        { type: "application/x-java-bean", suffixes: "" },
        { type: "application/x-java-vm", suffixes: " " }
      ]
    },          
    "RealPlayer": {
      description: "RealPlayer Version Plugin",
      progID: ["RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)", "RealVideo.RealVideo(tm) ActiveX Control (32-bit)", "rmocx.RealPlayer G2 Control"],
      classID: "CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA",
      mimeType: "audio/x-pn-realaudio-plugin",
      pluginsPage: "http://www.real.com/freeplayer/?rppr=rnwk",
      forceEmbedTag: true,
      standardEmbedAttributes: {
        controls: "ControlPanel",
        nojava: "true",
        autostart: "false"
      },
      // embedInfo: http://service.real.com/help/library/guides/realone/ProductionGuide/HTML/realpgd.htm?page=htmfiles/embed.htm
      // couldn't find any info about the object tag!
      getActiveXVersionInfo: function() { 
        var progID = getProgIdForActiveXObject(Plugin.PLUGINS["RealPlayer"].progID); 
        var obj = new ActiveXObject(progID);
        var version = (obj) ? obj.GetVersionInfo() : "";
        return version;
      },
      acceptedMimeTypes: [
        { type: "audio/x-pn-realaudio-plugin", suffixes: "rpm" },
        { type: "application/vnd.rn-realplayer-javascript", suffixes: "rpj" }
      ]
    },
	"MetaStream": {
		description: "MetaStream 3 Plugin",
		progID: ["AxMetaStream.MetaStreamCtl", "AxMetaStream.MetaStreamCtlSecondary"],
		classID: "03F998B2-0E00-11D3-A498-00104B6EB52E",
		mimeType: "application/x-mtx",
		pluginsPage: "http://www.viewpoint.com",
		standardEmbedAttributes: {},
		getActiveXVersionInfo: function() { 
//		  var progID = getProgIdForActiveXObject(Plugin.PLUGINS["MetaStream"].progID); 
//		  var obj = new ActiveXObject(progID);
//		  var version = (obj) ? obj.GetVersion() : "";
//		  return version;
			return 3;
		},
		acceptedMimeTypes: [
			{type: "application/x-mtx", suffixes: "mtx"}
		]
	}
  }

  var supportsNavigatorPlugins = function() {
    return (navigator.plugins && (navigator.plugins.length > 0));
  }

  var supportsActiveX = function() {
    return ((typeof 'ActiveXObject' != 'undefined') && (navigator.userAgent.indexOf('Win') != -1));
  }

  var findNavigatorPluginByName = function(name) {
    if (supportsNavigatorPlugins()) {
      for(var i=0;i<navigator.plugins.length;++i) {
        var plugin = navigator.plugins[i];
        if (plugin.name.indexOf(name) != -1) {
          return plugin;
        }
      }
    }
    return null;
  }

  var findPluginName = function(str) {
    for (var pluginName in Plugin.PLUGINS) {
      if (str.indexOf(pluginName) != -1) {
        return pluginName;
      }
    }
    return null;
  }

  var getIEClientCaps = function() {
    var clientcaps = document.getElementById("__Plugin_ClientCaps");
    if (!clientcaps) {
      var clientcaps = document.createElement("DIV");
      clientcaps.id = "__Plugin_ClientCaps";
      if (clientcaps.addBehavior) {
        clientcaps.addBehavior("#default#clientCaps");
        document.body.appendChild(clientcaps);
      }
      clientcaps = document.getElementById("__Plugin_ClientCaps");
    }
    return clientcaps;    
  }

  var getActiveXPluginByClassId = function(classID) {
    if (!classID) return null;
    if (!classID.match(/{[^}]+}/)) classID = "{" + classID + "}";
    var clientcaps = getIEClientCaps();
    try {
      var result = clientcaps.getComponentVersion(classID, "ComponentID")
      return result || null;
    } catch (err) { }
    return null;
  }

  var hasActiveXObject = function(progID) {
    progID = getProgIdForActiveXObject(progID);
    return (progID != null);
  }

  var getProgIdForActiveXObject = function(progID) {
    if (!progID) return null;
    for (var i=0; i<progID.length; i++) {
      try {
        var obj = new ActiveXObject(progID[i]);
        return progID[i] || null;
      }
      catch(e) { }
    }
    return null;
  }

  // accepts plugin or string
  var getVersionFromPlugin = function(plugin) {
    if (!plugin.name) plugin = { name: plugin, description: name };
    var matches = /[\d][\d\.]*/.exec(plugin.name);
    if (matches && plugin.name.indexOf("Java") == -1) return matches[0];
    matches = /[\d\.]+/.exec(plugin.description);
    return matches ? matches[0] : "";
  }
  
};

// helper functions
// for usage without prototype.js
if (!Object.extend) {
  Object.extend = function(destination, source) {
    for (property in source) {
      destination[property] = source[property];
    }
    return destination;
  }
}

// Array functions
Array.contains = function(arr, el) {
  return Array.indexOf(arr, el) != -1;
}

Array.indexOf = function(arr, el) {
  for (var i=0; i<arr.length; i++) {
    if (arr[i] == el) return i;
  }
  return -1;
}

String.encode =
String.prototype.encode = function() {
  var str = this;
  str = str.replace("&", "&amp;");
  str = str.replace("<", "&lt;");
  str = str.replace(">", "&gt;");
  str = str.replace("\"", "&quot;");
  str = str.replace("\n", "");
  return str;
}

if (!window.Plugin) {
  var Plugin = new Object();
}
Object.extend(Plugin, (new PluginFactory()));

		
	/**
 * Modal Backdrop: This is the semi-transparent white backdrop that goes between
 * 		a popup panel and the main page.
 */
var Backdrop = Class.create();
Object.extend(Backdrop.prototype, {
	initialize: function(id, classname){
		//Prepare Backdrop Div
		this.element = document.createElement('div');
		this.element.id = id;
		if(document.all)
			this.element.className = classname + 'IE';
		else
			this.element.className = classname;
		
		this.element.style.display = 'none';
		//If the user resizes the window, make sure the modal backdrop still covers the whole page
		Event.observe(window, 'resize', function(){this.resize()}.bind(this));
		document.body.appendChild(this.element);		
		
	},
	resize: function() {
		//have to shrink the backdrop so we can get the new scrollHeight
//		this.element.style.height = document.body.offsetHeight + 'px';
//		this.element.style.width = document.body.offsetWidth + 'px';
		
		//make sure the backdrop covers the whole page
		var sizes = this.getPageSize();
		
		this.element.style.height = sizes[1] + 'px';
		this.element.style.width = sizes[0] + 'px';
	
		
	},
	// getPageScroll()
// Returns array with x,y page scroll values.
// Core code from - quirksmode.org
//
	getPageSize: function(){
		
		var xScroll, yScroll;
		
		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll =  document.body.offsetHeight;
		}
		
		var windowWidth, windowHeight;
		if (self.innerHeight) {	// all except Explorer
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	
		
		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}
	
		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){	
			pageWidth = windowWidth;
		} else {
			pageWidth = xScroll;
		}
	
	
		arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight) 
		return arrayPageSize;
	},
	enable: function(){
		this.element.style.height = document.body.scrollHeight + 'px';
		this.element.style.width = document.body.scrollWidth + 'px';
		this.element.style.display = 'block';
		this.resize();
	},
	disable: function(){
		this.element.style.display = 'none';
	},
	observe: function(action, func, bubble) {
		Event.observe(this.element, action, func, bubble);
	}
});
	var galleryManager;
/**
 * Class is the main process point for all gallery
 * tranactions.  It will be responsible for brokering all
 * tab interactions to the appropriate TabController. 
 * Also will handle all ajax requests based on the AjaxUpdater 
 * passed back from the TabController.
 * @constructor
 */
function GalleryManager(modelId, tab, subNav, galleryType, baseGalleryContentUrl) {
	
	
	this.modelId;
	this.tab;
	this.galleryType;
	this.baseGalleryContentUrl = baseGalleryContentUrl || '/lexus-share/gallery/';
	
	this.galleryState;
	this.galleryController;
	this.tabController;
	
	this.ajaxSingleQueue = new Ajax.Queue(Ajax.Queue.Single, false);
	this.loadingImageSmall = new Image();
	this.loadingImageLarge = new Image();
	
	this.backdrop;	
	/**
	 * Method starts the Gallery upon instantiation of this class.
	 * @member GalleryManager
	 */
	this.init = function(modelId, tab, subNav,galleryType) {
    	this._cacheLoadingImage();
    	this.openGallery(modelId, tab, subNav,galleryType);
	}
	
	/**
	 * Method handles the first Ajax calls. This will 
	 * Fetch the modelGallery.html template and the 
	 * default TabController's template. Currently
	 * that is PhotoTabController && photoGallery.html
	 * @member GalleryManager
	 */
	this._initializeGallery = function(modelId, tab, subNav,galleryType) {
		this.galleryState = new GalleryState(modelId, tab, subNav, galleryType);
		
		this.galleryController = new GalleryController(this);
		
		var ajaxQueue = new Ajax.Queue(Ajax.Queue.FIFO, false);
		ajaxQueue.addAction(this.galleryController.buildAjaxUpdater());
		ajaxQueue.addAction(this._getTabController(this.galleryState.tab).buildAjaxUpdater());
		ajaxQueue.start();
	}
	/**
	 * Method will destroy the current gallery if one exists.
	 * @member GalleryManager
	 */
	this._destroyGallery = function() {
		if($('galleryContainer')) {
			if(this.tabController) {
				this.tabController.cleanup();
				this.tabController = null;	
			}
			
			this.galleryController = null;
			
			$('galleryContainer').parentNode.removeChild($('galleryContainer'));
		}
	}
	/**
	 * Method retrieves the loading image used for placeholder
	 * until real images are completly downloaded
	 * @member GalleryManager
	 */
    this._cacheLoadingImage = function() {
    	this.loadingImageSmall.src = '/lexus-share/images/gallery/loading_small.gif';
    	this.loadingImageLarge.src = '/lexus-share/images/gallery/loading_large.gif';
    }	
	/**
	 * Method returns the current TabController. If there is not one
	 * by default the PhotoTabController will be returned.
	 * @member GalleryManager
	 */
	this._getTabController = function(tab) {
		if(!this.tabController)
		  this._toggleTabController(tab);	  
		return this.tabController;
	}
	
	/**
	 * Method will instantiation a new TabController based
	 * on the tabKey provided.
	 * @member GalleryManager
	 */
	this._toggleTabController = function(tabKey) {
		switch (tabKey.toUpperCase()) {
			case PhotoTabController.TAB_KEY:
				this.tabController = new PhotoTabController(this.galleryState, this.baseGalleryContentUrl);
				break;
			case WallpaperTabController.TAB_KEY:
				this.tabController = new WallpaperTabController(this.galleryState, this.baseGalleryContentUrl);
				break;	
			case ScreenSaverTabController.TAB_KEY:
				this.tabController = new ScreenSaverTabController(this.galleryState, this.baseGalleryContentUrl);
				break;
			case VideoTabController.TAB_KEY:
				this.tabController = new VideoTabController(this.galleryState, this.baseGalleryContentUrl);
				break;	
			case Video360TabController.TAB_KEY:
				this.tabController = new Video360TabController(this.galleryState, this.baseGalleryContentUrl);
				break;	
			case ColorTabController.TAB_KEY:
				this.tabController = new ColorTabController(this.galleryState, this.baseGalleryContentUrl);
				break;		
			default:
				this.tabController = new PhotoTabController(this.galleryState, this.baseGalleryContentUrl);
				break;
		}	
	}	
	/**
	 * Method will take desired function (action) and attempt to 
	 * apply it to the current TabController. If no function/method
	 * exists on the TabController, no action will be taken.
	 * @member GalleryManager
	 */
	this.doTabAction = function(ref, func, args,e) {
	  
	  if(this._getTabController()[func]) {
	  	if(!args) 
	  	  args = $A();
	    args.unshift(ref);
	    if(e) {
	    	args.push(e);
	    }

	    arguments = args;
	    return this._getTabController()[func].apply(this._getTabController(), args);
	  }
	}

    /**
     * Method will either show or create the Gallery Wrapper Div.
     * @member GalleryManager
     */
    this._showGalleryWrap = function() {
		if(!this.backdrop) {
			this.backdrop = new Backdrop('galleryWrap','galleryWrap');
			this.backdrop.observe('click', this.closeGallery.bind(this), false);
		}
		this.backdrop.enable();
	}
	
	this._findTabImage = function(key) {
		
		var images = $A( $('pgTabContainer').getElementsByTagName('IMG') ); 
		
		return ( images.find(function(image) {
					var imageKey = image.id.replace('pg_','').toUpperCase();
					return (imageKey == key);
				  }) 
			    );
	}
	
	/**
	 * Method hides the Gallery Wrapper Div
	 * @member GalleryManager
	 */
	this._hideGalleryWrap = function() {
		  if(this.backdrop) {
			this.backdrop.disable();
		}
		
	}
	
	/**
	 * Method will take desired function (action) and attempt to 
	 * apply it to the current GalleryController. If no function/method
	 * exists on the GalleryController, no action will be taken.
	 * @member GalleryManager
	 */
	this.doGalleryAction = function(ref, func, args) {
	  if(this.galleryController[func]) {
	    if(!args) 
	  	  args = $A();
	    args.unshift(ref);
	    return  this.galleryController[func].apply(this.galleryController, args);
	  }
	}

	/**
	 * Method opens the gallery based on the modelId provided
	 * @member GalleryManager
	 */
	this.openGallery = function(modelId, tab, subNav,galleryType) {
		
		// Hide all flash objects in safari
		hideAllFlashInSafari();
		
		this._showGalleryWrap();
		// If no gallery or we have a differnt type, start from scratch
		if(!$('galleryContainer') || galleryType != this.galleryState.galleryType) {
		  this._destroyGallery();
		  this._initializeGallery(modelId, tab,subNav, galleryType);
		}
		// We already have the correct Gallery Template, lets get the model and tab.
		else {
		  this.toggleGallery(modelId,tab);
		  $('galleryContainer').style.display = 'block';
		}
		
		// Make sure we are at the top of the page
		scroll(0,0);
	}
	
	/**
	 * Method handles the work for toggling the gallery between models.
	 * Will removed any old content and preform an AJAX call to get the
	 * new model content based on the current Tab they are on. 
	 * @member GalleryManager
	 */
	this.toggleGallery = function(modelId, tab) {
		this.galleryState.modelId = modelId;
		
		
		this.galleryController.swapModelImage();
		this.galleryController.updateDropDown(modelId);
		
		if(tab) {
			this.galleryState.setTab(tab);
			this._toggleTabController(tab);
		}
		// Clean up the current Controller
		this._getTabController().cleanup();
		
		// Get a new Controller
		this._toggleTabController(this.galleryState.tab);
		
		
		// Preform ajax call for template
		this._makeTabAjaxCall();
	}
	this.toggleGalleryFromDropDown = function(modelId) {
		if(this.galleryState.modelId != modelId) {
			this.toggleGallery(modelId);
		}
	}
	/**
	 * Method makes an ajax call based on the current Tab Controller
	 * @member GalleryManager
	 */
	this._makeTabAjaxCall = function() {
		this.ajaxSingleQueue.addAction(this._getTabController().buildAjaxUpdater());
		
	}
	/**
	 * Method switches to a new Tab Controller and exectutes the ajax call 
	 * to get the correct template.
	 * @memeber GalleryManager
	 */
	this.toggleTab = function(clickedImg) {
		
	   // Switch Tab Control
       var key = clickedImg.id.replace('pg_','').toUpperCase();
       
       // Return false if we are already on this tab
       if(key == this.tabController.TAB_KEY)
         return false;
       
       this.galleryState.tab = key;
       
	   // Removed the current Tab Controller's content
	   this._getTabController().cleanup();
	          
       this._toggleTabController(key);
       
       //Make Ajax call for new Tab Template
       this._makeTabAjaxCall();
       
       return true;
	}
	/**
	 * Method will close hte gallery by hidding it in the DOM.
	 * @member GalleryManager
	 */
	this.closeGallery = function() {
		
		// close entire window if we are a popup that was generated from another lexus page.
		if(window.isPopup) {
			window.close();
		}
		// only hide the gallery for possible later use
		else {
      		this._hideGalleryWrap();
  	  		this._destroyGallery() 
			hidePW();
  	  		showAllFlashInSafari();
		}
  }	
  
  //Perform the Init function on instantiation
  this.init(modelId, tab, subNav,galleryType);
}
GalleryManager.LARGE = 'LARGE';
/**
 * Static Method that will launch the gallery based on if 
 * it has already been openned on the current page.
 * @member GalleryManager
 */
GalleryManager.launchGallery = function() {

	
	if($('popupOverlay')) {
		hidePW();	// hide popup windows from glossary terms.
	}
	 
	 if(!PAGE_LOAD) {
	 	return;
	 }
	 
	 if(window.navigationManager) {
	 	navigationManager.hideNavigation();
	 }
	 
	 if(!galleryManager)
	 	// GalleryManager(model id, tab, subNav, type);
	    galleryManager = new GalleryManager(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]);
	  else
	    galleryManager.openGallery(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]);
}
GalleryManager.launchGalleryOnload = function() {
	var params = Address.getParameters();

	if(params['launchGallery'] && params['launchGallery'] == 'true') {
		var model = (params['model'] && params['model'] != '') ? params['model'] : MODEL_ID; // TODO - this is going to blow up on hotels pages or anything that is not a model page
		
		GalleryManager.launchGallery(model, params['tab'], params['subNav'], params['type']);
	}
}

/**
 * Class handles the controls for all Global Gallery specefic tasks like:
 * gallery setup, caching all global images, swaping the model header image,
 * and actions like switching tabs and toggling the model drop down.
 * @constructor
 */
function GalleryController(manager) {
	this.manager = manager;
	
	/**
	 * Method returns an Ajax.Updater object to be used to 
	 * gather the correct template "modelGallery.html" and onComplete
	 * will call _prepareContent, which will prep the content.
	 * @member GalleryController
	 */ 
	this.buildAjaxUpdater = function() {
		return new Ajax.Updater(
			    {success: document.body, failure: null }, 
			    GalleryUtils.buildAjaxUrl([this.manager.baseGalleryContentUrl,this.manager.galleryState.galleryType,'/gallery.html']),
			    {
				    method: 'GET',
				    wait: true,
				    insertion: Insertion.Bottom,	
				    onComplete: function(){this._prepareContent()}.bind(this)
			    }
		)
	}
	/**
	 * Method is called by onComplete of the Ajax.Updater proved by 
	 * buildAjaxUpdater().  Method will swap the Model Header image, 
	 * prep the tab area, and prepare the model dropdown.
	 * @member GalleryController
	 */
	this._prepareContent = function() {
		if($('galleryContainer')) {
			this.switchTabPresentation(this.manager._findTabImage(this.manager.galleryState.tab));
			this.swapModelImage();
			this.updateDropDown(this.manager.galleryState.modelId);
			this._prepareTabImages();
			this._prepareDropDown();
			//this._prepareDisclaimerArea();
						 
		  $('galleryContainer').style.display = 'block'; 
		}		
	}

    /**
     * Method will swap the Model Header image to the current Model
     * @member GalleryController
     */
	this.swapModelImage = function() {		  
		var modelImage = document.getElementsByClassName('pgModelLogo',$('galleryContainer'), 'IMG');
      	modelImage[0].src = '/lexus-share/images/gallery/' + manager.galleryState.galleryType + '/' + manager.galleryState.modelId + '/vc_GalHead.gif'
	}
	/**
	 * Method will update the state of all elements in the drop down
	 */
	 this.updateDropDown = function(modelId) {
	 	//sometimes we wont have a drop down
	 	if(!$('g_drDnList')) {
	 		return;
	 	}
	 	var elements = $('g_drDnList').getElementsByTagName('A');
	 	
	 	for(var i=0; i<elements.length; i++) {
	 		var element = elements[i];
	 		
	 		if(element.parentNode.getAttribute('name') == modelId) {
	 			element.className = 'galleryGalBodyOn';
	 		}
	 		else {
	 			element.className = 'galBody';
	 		}
	 	}
	 }
    /**
     * Method handels teh prep of the Tab component. All tab images for off and on 
     * states will be cached. Events will be added to each tab.
     * @member GalleryController
     */
    this._prepareTabImages = function() {
  	  var domTabs = $NL($('pgTabContainer').getElementsByTagName('IMG'));
  	  domTabs.each(function(domTab){
        var cacheImage = new Image();
        var cacheImageOn = new Image();
       
        cacheImage.src = domTab.src;   
        cacheImageOn.src = (domTab.src.indexOf('On.gif') > -1) ? 
                            domTab.src.replace('On.gif', '.gif') : domTab.src.replace('.gif', 'On.gif');

        // Add onclick event
        Event.observe(domTab, 'click',function(){galleryManager.doGalleryAction(this,'switchTab');return false;}.bind(domTab))       

  	  })	
    }
    /**
     * Method adds events to the model dropdown.
     * @member GalleryController
     */
    this._prepareDropDown = function() {
  	  //sometimes we wont have a drop down
  	  if(!$('g_drDnList')) {
  	  	return;
  	  }
  	  
  	  var hrefs = $('g_drDnList').getElementsByTagName('A');
  	
  	  for(var i=0; i<hrefs.length; i++) {
  	  	var a = hrefs[i];
  		Event.observe(a.parentNode, 'click',function(){
  											 galleryManager.doGalleryAction(this.controller,'toggleDropDownAction', [this.obj]);
  											 galleryManager.toggleGalleryFromDropDown(this.obj.getAttribute('name'));
  											 return false;
  											}.bind( {controller: this, obj: a.parentNode} )
  					  );
  		a.href = "javascript:void(0);";  
  	  }
  	
    }
    this._prepareDisclaimerArea = function() {
		var boundry = Dom.getBoundries('pgDisclaimerArea');
		
		// We only show the scroll bar if we need it.
		if(boundry.height > 63) { 
			$('pgScrollbar').style.display = 'block';
			var scrollObj = new dw_scrollObj('pgFooterContentContainer', 'pgDisclaimerArea', null);
		
			// arguments: dragBar id, track id, axis ("v" or "h"), x offset, y offset
			// (x/y offsets of dragBar in track)
			scrollObj.setUpScrollbar("pgDragBar", "pgTrack", "v", 0, 0);
		}
		else {
			$('pgScrollbar').style.display = 'none';
		}
    }

	
	this.findDisclaimers = function() {
		var disclaimers = new Object();
		var disclaimerViews = document.getElementsByClassName('disclaimerView', 'pgTabDisclaimers', 'DIV');	

		for(var i=0; i<disclaimerViews.length; i++) {
			var view = disclaimerViews[i];
			var viewId = view.id.replace('disclaimer', '');
			
			disclaimers[viewId] = new Array();
			
			var disclaimerElements = view.getElementsByTagName('DIV');
			
			for(var x=0; x<disclaimerElements.length; x++) {
				var disclaimer = disclaimerElements[x].innerHTML;
				disclaimers[viewId].push(disclaimer);
			}
		}
		return disclaimers;		
	}
	this.updateDisclaimers = function(ref, disclaimers) {
		var content = '';
		
		this.removeDisclaimers();
		
		for(var i=0; i<disclaimers.length; i++) {
			content += disclaimers[i];
		}
		$('pgDisclaimerArea').innerHTML = content;
		this._prepareDisclaimerArea();
	}
	this.removeDisclaimers = function() {
		$('pgDisclaimerArea').innerHTML = '';
	}
	/**
	 * Method handels the action to switch to a different Model
	 * @member GalleryController
	 */
	this.toggleDropDownAction = function(ref , obj) {
		this.toggleDropDown(obj);
	}
	this.toggleDropDown = function(obj) {
	  //sometimes we wont have a drop down
  	  if(!$('g_drDnList')) {
  	  	return;
  	  }
  	  var dropDown = $('g_drDnList');
  	  if(dropDown.style.display != 'block') {
	    dropDown.style.display = 'block'
	    dropDown.style.left = Dom.getLeftXAsPx(obj,'galleryContainer');
	    dropDown.style.top = Dom.getBottomYAsPx(obj,'galleryContainer');
  	  }
  	  else {
  	  	if(obj.getAttribute('name') != this.manager.galleryState.modelId) {
  			dropDown.style.display = 'none'; 		
  	  	}
  	  }
	}
	/* Sets a delay for the drop-down to close */
    this.closeDropDown = function(){
      //sometimes we wont have a drop down
      if(!$('g_drDnList')) {
  	  	return;
  	  }
	   delayToClose = setTimeout("$('g_drDnList').style.display = 'none'",250);
    }
    /* Clears the delay above a force drop-down to close */
    this.clearDropDown = function (){ 
	  if (typeof delayToClose!="undefined"){clearTimeout(delayToClose);}
    }
	/**
	 * Method switchs to a different tab.
	 * @member GalleryController
	 */
	this.switchTab = function(clickedImg) {
  	
  	// Tell our manager to toggle the Tab Controller
  	// If the response is false, then we arent switching the tab
  	if(!this.manager.toggleTab(clickedImg))
  	   return;
  	
  	this.removeDisclaimers();
  	return this.switchTabPresentation(clickedImg);
  		
  }
  
  this.switchTabPresentation = function(clickedImg) {
  	var li = clickedImg.parentNode;
  	var ul = li.parentNode;
  	var lis = $NL(ul.childNodes).elements();
  	
  	// Turn off any element that is currently on
  	lis.each(function(element) {
  		var img = element.firstChild
  		if(img.src.indexOf('On') > -1) {
  		  img.src = img.src.replace('On.gif', '.gif');		
  		  img.className =  'pgTabs';
  		}  		
  	})
  	clickedImg.src = clickedImg.src.replace('.gif', 'On.gif');
  	clickedImg.className =  'pgTabsOn';
  	return false; 
  	
  }
}
function GalleryState(modelId, tab, subNav, galleryType) {
	this.modelId = modelId;
	this.subNav = subNav;
	this.galleryType = (galleryType) ? galleryType : 'models';
	
	this.getSubNavKey = function() {
		return this.subNav.replace('subNav', '');
	}
	this.setTab = function(tab) {
		this.tab = (tab) ? tab.toUpperCase() : PhotoTabController.TAB_KEY;
	}
	this.setTab(tab);
}

/**
 * Class is responsible for all work regarding the Photo Tab and its content.
 * @constructor
 */
function PhotoTabController(galleryState, baseGalleryContentUrl) {
	
  	this.baseGalleryContentUrl = baseGalleryContentUrl;
  	
  	this.galleryState = galleryState;
  	this.photoGalleryImages = new Object();
  	this.photoGalleryState = new PhotoGalleryState();
  	this.photoSlideShowState;
    this.disclaimers = new Object();
  
	/**
	 * Method handles all Initialization tasks including:
	 * @member PhotoTabController
	 */
	this.init = function() {
	  // Nothing to do  	
	}
	/**
	 * Method preforms necessary cleanup logic before a it can 
	 * be destroyed
	 * @member PhotoTabController
	 */
    this.cleanup = function() {
    	this.removeContent();
    	this.removeMouseOverEventCorrection();
    	
    	for(id in this.photoGalleryImages) {
	   	 var photoGalleryImage = this.photoGalleryImages[id]
	   	 
	   	 for(var i=0; i<photoGalleryImage.length; i++) {
	   	 	var galleryImage = photoGalleryImage[i]
	   	 	galleryImage.clearOnload();	
	   	 	galleryImage = null;
	   	 }
	   }
	   this.photoGalleryImages = null
	   this.photoGalleryState = null;
    	
    	
    }
	/**
	 * Method returns an Ajax.Updater object to be used to 
	 * gather the correct template "photoGallery.html" and onComplete
	 * will call _prepareContent, which will prep the content.
	 * @member GalleryController
	 */
	this.buildAjaxUpdater = function() {
		return new Ajax.Updater(
			    'pgMainBodyContainer',
			    GalleryUtils.buildAjaxUrl([this.baseGalleryContentUrl + this.galleryState.galleryType + '/' + this.galleryState.modelId + '/photos.html']),
			    {
			 	    method: 'GET',
				    wait: true,
				    onComplete: this._prepareContent.bind(this)
			    }
			  )
	}
	
	/**
	 * Method is called by onComplete of the Ajax.Updater proved by 
	 * buildAjaxUpdater().  Method will prep all images that need caching and
	 * will add Events where needed. And will switch the current view of the 
	 * Photo Gallery content, such as the SlideShow, or the Grid
	 * @member GalleryController
	 */
	this._prepareContent = function() {
		var pgMainPhotosGrid = $('pgMainPhotosGrid');
		
		if(pgMainPhotosGrid) {
		  this._cacheTemplateImages();
		  this._prepareThumbNails();
		  this.disclaimers = galleryManager.doGalleryAction(null, 'findDisclaimers');

		  var subNavImg = this._getCorrectSubNav();
		
		  if(this.photoGalleryState.slideShow) {
		  	this.switchSlideShow(subNavImg);
		  	this._showSlideShow();
		  }
		  else {
		  	this.switchToGrid();
		  	this.switchSubNavGrid(subNavImg)
		  }	  
		}	
	}
	
	this._getCorrectSubNav = function() {
		if($(this.galleryState.subNav))  {
			return $(this.galleryState.subNav).firstChild
		}
		else if($(this.photoGalleryState.blankSubNav)) {
			return $(this.photoGalleryState.blankSubNav).firstChild;
		}
		else {
			var subNav = document.getElementsByClassName('pgSubNav','pgMainPhotosGrid','DIV')[0];
			
			return subNav.getElementsByTagName('LI')[0].firstChild;
		}
		
	}
	/**
	 * Method removes the PhotoGallery Tab content
	 * @member PhotoTabController
	 */
	this.removeContent = function() {		
		if($('pgMainPhotosGrid'))
		  $('pgMainPhotosGrid').parentNode.removeChild($('pgMainPhotosGrid'));
	}
	
	/**
	 * Method will cache all Grid images for both Interior and Exterior
	 * TODO this could be moved into an abstract Class called TabController
	 * @member PhotoTabController
	 */
	this._cacheTemplateImages = function() {
		var tempObject = new Object();
		var domImages = $NL($('pgMainPhotosGrid').getElementsByTagName('IMG'));		
		
		domImages.each(function(domImage){
          var cacheImage = new Image();
          cacheImage.src = domImage.src;
          tempObject[cacheImage.src] = cacheImage;
		})
	}
	
	/**
	 * Method will add events to all thumbnails images and create a PhotoGalleryImage object
	 * for each thumbnail image found. this will include the off, on, and a placeholder for the large
	 * slideshow image
	 * @member PhotoTabController
	 */

      this._prepareThumbNails = function() {
		var gridDivs = document.getElementsByClassName('pgBodyGrid',  $('pgMainPhotosGrid'), 'DIV');
		
		// Loop through each Grid Div and setup all thumbnail images
       for(var x=0; x<gridDivs.length; x++) {
       	var gridDiv = gridDivs[x];
      
        var domListItems = gridDiv.getElementsByTagName('LI');
        var images;
      
        // Add one Array for each Grid Div availible
        this.photoGalleryImages[gridDiv.id] = new $A();
      
		// Loop through each Grid Div's Images, cache both off and roll over states.
		for(var i=0; i<domListItems.length; i++) {
		  var domListItem = domListItems[i];
		  var photoGalleryImage = new PhotoGalleryImage();
      	  domListItem.id = i;
      	  domListItem.name = gridDiv.id;


          // Set Alt Text for slideshow description. and removed from ThumbNail Image
          var photoDescription = domListItem.getElementsByTagName('SPAN')[0];
            photoGalleryImage.slideShowText = photoDescription.innerHTML;
            photoDescription.parentNode.removeChild(photoDescription);
//          photoGalleryImage.slideShowText = domListItem.firstChild.alt;

          // Split the Loading image and the real image
          images = domListItem.firstChild.src.split('#');

          //Add Loading Div to the current List Item
          var width;
          var height;
          
          // For ie we need to subtract two since the loading Div has a border of 1px
          if(document.all) {
            width  = 184
            height = 94;
          }             
          else {
            width  = 186;
            height = 96;
          }          
          GalleryUtils.buildLoadingElement(domListItem,width,height);        
          
          // Add to the current grid Div object that keeps all images in this Div (Sub Menu)
          this.photoGalleryImages[gridDiv.id].push(photoGalleryImage);

          // Add an onload event to the thumbPhoto image to replace the Loading Div once it has completly downloaded
          photoGalleryImage.thumbPhoto.setOnload(function() {
          	GalleryUtils.replaceImage(this.thumbPhoto.image,this.domListItem.firstChild);
          }.bind({thumbPhoto:photoGalleryImage.thumbPhoto, domListItem: domListItem }));

          // Set the source of the thumbPhoto image
          photoGalleryImage.thumbPhoto.image.src = images[1];  

          // Add an onload event to the thumbPhotoOn image to add mouseover, mouseout, and onclick events to the list item (domListItem)
          photoGalleryImage.thumbPhotoOn.setOnload(function() {
                   // Add Events to all ThumbNail images in the Grids
                   Event.observe(this,'mouseover',function() {galleryManager.doTabAction(this,'swapImage',['On','On'],arguments[0])}.bind(this));
                   Event.observe(this,'mouseout',function() {galleryManager.doTabAction(this,'swapImage',['On','Out'],arguments[0])}.bind(this));
                   Event.observe(this,'click',function() {galleryManager.doTabAction(this,'launchSlideShow',['On','Out'],arguments[0])}.bind(this));	
               }.bind(domListItem));

          // Set the source of the thumbPhotoOn image
          photoGalleryImage.thumbPhotoOn.image.src = images[1].replace('.jpg','On.jpg');
        }
      }
	}
	/*
	 * View Event Methods
	 */
	 
	/**
	 * Method will swap the thumbnail image from on to off or off to on.
	 * @member PhotoTabController
	 */
	this.swapImage  = function(listItem, state, action,e) {
        var img = listItem.firstChild;
       /**
        * Stop event bubble propagation
        */
	    if (!e) e = window.event;
	      Event.stop(e); 
       /**
        * Turn off the current Img if one exists
        */
        if(this.photoGalleryState.currentThumb && this.photoGalleryState.currentThumb != img ) {
          swapOut(this.photoGalleryState.currentThumb, state);
          this.photoGalleryState.currentThumb = null;
          this.removeMouseOverEventCorrection();
        }
        
        /**
         * Process Swap depending on action requested
         */
        var photoGalleryImage = this.photoGalleryImages[listItem.parentNode.parentNode.id];                
		if(photoGalleryImage) {
		  if(photoGalleryImage[listItem.id].thumbPhoto.image.complete && 
		     photoGalleryImage[listItem.id].thumbPhotoOn.image.complete) {
		  	img.className = 'pgBodyGridImage';
		  	switch (action) {
		  		case 'Over':
		  			swapOver(img, state);
		  			this.photoGalleryState.currentThumb = img;
		  			this.addMouseOverEventCorrection();
		  			break;
		  		case 'On':
		  			swapOn(img, state);
		  			this.photoGalleryState.currentThumb = img;
		  			this.addMouseOverEventCorrection();
		  			break;
                case 'Out':
		  			swapOut(img, state);
		  			this.photoGalleryState.currentThumb = null;
		  			this.removeMouseOverEventCorrection();
		  			break;
		  	}
		  }
		}
	}
	/**
	 * Method adds an event to both 'galleryContainer' && 'galleryWrap' to 
	 * turn off the currently on thumbnail image in the gallery grid.
	 * @member PhotoTabController
	 */
	this.addMouseOverEventCorrection = function() {
	  $('galleryContainer').onmouseover = PhotoTabController.turnOffThumbNail;
	  $('galleryWrap').onmouseover = PhotoTabController.turnOffThumbNail;
	}
	/**
	 * Method removes the turnOffThumbNail event function from both 'galleryContainer' && 'galleryWrap'
	 * @member PhotoTabController
	 */
	this.removeMouseOverEventCorrection = function() {
	  $('galleryContainer').onmouseover = null;
	  $('galleryWrap').onmouseover = null;
	}
	/**
	 * Method will handle any action that clicks on the Sub Nav (Exterior, Interior)
	 * @member PhotoTabController
	 */
	this.switchSubNavGrid = function(clickedImg) {  	
      this._updateSubNav(clickedImg);    
      this._toggleGrid(clickedImg);
    }
    
    /**
     * Method will toggle between Exterior and Interior for the Grid View
     * @member PhotoTabController
     */
    this._toggleGrid = function(clickedImg) {
  	  
  	  var bodyGrids = document.getElementsByClassName('pgBodyGrid', $('pgMainPhotosGrid'), 'DIV');
  	  
  	  var gridId = 'pgBodyGrid' + clickedImg.parentNode.id.replace('subNav','')
  	  for(var i=0; i<bodyGrids.length; i++) {
  	  	var bodyGrid = bodyGrids[i];
  	  
  		if(gridId == bodyGrid.id) {
  			bodyGrid.style.display = "block";
  		}
  		else {
  			bodyGrid.style.display = "none";
  		}
  	
  	  }
  	  /*
  	  if($('pgBodyGridExt')) {
  	  	$('pgBodyGridExt').style.display = (clickedImg.id != 'subNavExt') ? 'none' : 'block';
  	  }
  	  if($('pgBodyGridInt')) {
	  	$('pgBodyGridInt').style.display = (clickedImg.id != 'subNavInt') ? 'none' : 'block';  		  	
  	  }
  	  */
  	  
    }
  
    /**
     * Method will update the SubNav view for all views: Grid and SlideShow
     * @member PhotoTabController
     */
    this._updateSubNav = function(subNavImage) {
  	  var subDivs = document.getElementsByClassName('pgSubNav', $('pgMainBodyContainer'),'DIV')
  	  var currentClass = subNavImage.parentNode.className;
  	  this.galleryState.subNav = subNavImage.parentNode.id;
  	  
  	  subDivs.each(function(subDiv) {
  	 	var lis = subDiv.getElementsByTagName('LI');
  	 	
	  	// Turn off any element that is currently on
	  	for(var i=0; i<lis.length; i++) {
	  		var img = lis[i].firstChild;
	  		if(img.src.indexOf('On.gif') > -1) {
	  			img.src = img.src.replace('On.gif', '.gif');		
	  		}
	  		// Turn on the element that is current
	  		if(currentClass == lis[i].className) {
	  			img.src = img.src.replace('.gif', 'On.gif');		  			
	  		}
	  	 }
  	   })
  	   this._updateDisclaimers();
     }
     this._updateDisclaimers = function() {
     	var viewId = this.galleryState.subNav.replace('subNav','');
     	var disclaimers = this.disclaimers[viewId];
     	galleryManager.doGalleryAction(null, 'updateDisclaimers',[disclaimers]);
     }
     /**
      * Method will launch the slideshow. Start the slideshow based on what image is 
      * clicked on from the Grid.
      * @member PhotoTabController
      */
     this.launchSlideShow = function(thumbNail, state, action,e) {
  	   this._startSlideShow(thumbNail);
  	   this.photoGalleryState.grid = false;
  	   this.photoGalleryState.slideShow = true;
  	
  	   // Toggle templates from ThumbNail to SlideShow
  	   this.swapImage(thumbNail, state, action,e);
       this._showSlideShow();
  	   this._moveSlideShow();
  	   return true;
  	   
     }
     /**
      * Method hides the Grid wiew and shows the Slideshow view
      */
     this._showSlideShow = function() {
  	   $('pgMainPhotosGrid').style.display = 'none';
  	   $('pgMainPhotosSlSh').style.display = 'block';  	
     }
     /*
      * Method will create a new PhotoSlideShowState object and set it to the 
      * current state based on either Exterior/Interior and the image clicked on from
      * the Grid
      * @memeber PhotoTabController
      */
     this._startSlideShow = function(thumbNail) { 	
  	   // Set the current Slide Show State
  	   var gridDiv = this.photoGalleryImages[thumbNail.name];
  	   this.photoSlideShowState = new PhotoSlideShowState((thumbNail.id*1), gridDiv);	
     }

     /**
      * Method will move the SlideShow back one Image
      * @member PhotoTabController
      */
     this.slideShowPrevious = function() {
  	   if((this.photoSlideShowState.index+1) > 1) {
  	     this.photoSlideShowState.index--;
  	     this._moveSlideShow();
  	   }
     }

     /**
      * Method will move the SlideShow forward one Image
      * @member PhotoTabController
      */
     this.slideShowNext = function() {
  	   if((this.photoSlideShowState.index+1)< this.photoSlideShowState.grid.length) {
  	     this.photoSlideShowState.index++;
  	     this._moveSlideShow();
  	   }
     }
     
     /**
      * Method will switch the SlideShow Image to the current view, update the SubNav's SlideShow controls,
      * and will make a call to cache the next and previous image in the chain.
      * @member PhotoTabController
      */
     this._moveSlideShow = function() { 	
       
       GalleryUtils.buildLoadingElement($('pgSlShPhoto'),774,400,GalleryManager.LARGE);
  	   
  	   var currentImage = this._cacheSlideShowImage(this.photoSlideShowState.index);
  	   
  	   if(currentImage.image.complete)
  	     GalleryUtils.replaceImage(currentImage.image,$('pgSlShPhoto').firstChild);
  	   else {
  	     currentImage.setOnload(function() {
          	GalleryUtils.replaceImage(this,$('pgSlShPhoto').firstChild);
          }.bind(currentImage.image));
  	   }
  	
       // Add Alt Text as description of large image
  	   var description = this.photoSlideShowState.grid[this.photoSlideShowState.index].slideShowText;
  	   $('pgSlShPhotoDesc').innerHTML = description;
  	
  	   this._updateSlideShowProgress();
  	   this._cacheBeforeAndAfter();
     }
  
     /**
      * Method will create the SlideShow image based on teh index given and will set the 
      * new image inside of the currrent PhotoSlideShowState.
      * @member PhotoTabController
      */
     this._cacheSlideShowImage = function(index) {
  	   var slideShowPhoto = this.photoSlideShowState.grid[index].slideShowPhoto;
  	   if(slideShowPhoto.image.src.indexOf('g_') < 0) {
  	     slideShowPhoto.image.src  = this.photoSlideShowState.grid[index].thumbPhoto.image.src.replace('gth_', 'g_'); 	    
  	   }
  	   return slideShowPhoto;
      }
  
      /**
       * Method updates the slideshow progress in the SubNav view.
       * If we are on the first Image of the slideshow, the
       * Previous link will be disabled. If we are on the last image the 
       * Next link will be disabled.
       * @member PhotoTabController
       */
      this._updateSlideShowProgress = function() {
  	    var index = this.photoSlideShowState.index+1;
  	    var gridLength = this.photoSlideShowState.grid.length;
  	    var previous = $('pgSlShPrevious');
  	    var next = $('pgSlShNext');
  	
  	    // Update Numbers
  	    $('pgSlShStateIndex').innerHTML = index;
  	    $('pgSlShStateTotal').innerHTML = gridLength;
  	
  	    // Add default events
  	    previous.onclick = function(){galleryManager.doTabAction(previous,'slideShowPrevious')};
  	    next.onclick = function(){galleryManager.doTabAction(next,'slideShowNext')};	
  	
  	    // Update Previous
  	    if(index == 1) {
          if(previous.firstChild.src.indexOf('Disable.gif') < 0) {
  	        previous.firstChild.src = previous.firstChild.src.replace('.gif','Disable.gif');
  	      }
  	      previous.className = 'pgSlShPreviousDisable';
  	      previous.onclick = '';
  	    }
  	    else {
  	      previous.firstChild.src =previous.firstChild.src.replace('Disable.gif','.gif');
   	      previous.className = 'pgSlShPreviousOn';  
  	    }
  	    // Update Forward
  	    if(index == gridLength) {
  	      if(next.firstChild.src.indexOf('Disable.gif') < 0) {
  	        next.firstChild.src = next.firstChild.src.replace('.gif','Disable.gif');
  	      }
  	      next.className = 'pgSlShNextDisable';
  	      next.onclick = '';
  	    }
  	    else {
  	      next.firstChild.src = next.firstChild.src.replace('Disable.gif','.gif');  		
   	      next.className = 'pgSlShNextOn';  
  	    }
      }
      /**
       * Method will switch the slideshow from Interior to Exterior and
       * vice versa.
       * @member PhotoTabController
       */
      this.switchSlideShow = function(clickedImg) {
  	    this._updateSubNav(clickedImg);
  	    this._resetSlideShow(clickedImg);
  	    this._toggleGrid(clickedImg);
      }
      /**
       * Method will reset the current Slideshow back to the fisrt image.
       * @member PhotoTabControlle
       */
      this._resetSlideShow = function(clickedImg) {
        var root = clickedImg.parentNode.id.replace('subNav', '');
        var clickedGrid = 'pgBodyGrid' + root;
    
        if(clickedGrid != this.photoSlideShowState.grid) {
          this.photoSlideShowState = new PhotoSlideShowState(0, this.photoGalleryImages[clickedGrid])	    	
        }
        this._moveSlideShow();
      }
      
      /**
       * Method will attempt to cache the previous and the next image
       * of the current image shown.
       * @member PhotoTabController
       */
      this._cacheBeforeAndAfter = function() {
        var previousImage;
        var forwardImage;
    
        if(this.photoSlideShowState.index>0) {  	
  	      this._cacheSlideShowImage(this.photoSlideShowState.index-1);
        }
        if( (this.photoSlideShowState.index+1) < this.photoSlideShowState.grid.length) {
  	      this._cacheSlideShowImage(this.photoSlideShowState.index+1);
        }
      }
      
      /**
       * Method will switch the Grid View and display the Sub view based on the current SubNav
       * Exterior or Interior
       * @member PhotoTabController
       */
      this.switchToGrid = function() {
  	    this.photoGalleryState.grid = true;
  	    this.photoGalleryState.slideShow = false;
  	    $('pgMainPhotosGrid').style.display = 'block';
  	    $('pgMainPhotosSlSh').style.display = 'none';   	  	
      }
      
  //Perform the Init function on instantiation
  this.init();
}

PhotoTabController.turnOffThumbNail = function() {
	var e = arguments[0];
    if (!e) e = window.event;
	    Event.stop(e);
	
	if(galleryManager.tabController.photoGalleryState.currentThumb) {
		swapOut(galleryManager.tabController.photoGalleryState.currentThumb, 'On');	
	}		
}
PhotoTabController.TAB_KEY = 'PHOTO';
PhotoTabController.prototype.TAB_KEY = 'PHOTO';

/**
 * Class stores the different Images needed
 * for each picture on the Photo Gallery
 * @constructor
 */
function PhotoGalleryImage() {
  	this.thumbPhoto = new GalleryImage();
  	this.thumbPhotoOn = new GalleryImage();
  	this.slideShowPhoto = new GalleryImage();
  	this.slideShowText;
  	
  	this.clearOnload = function() {
		this.thumbPhoto.clearOnload();	
		this.thumbPhotoOn.clearOnload();
		this.slideShowPhoto.clearOnload();	
	}
}
/**
 * Class stores the current state of the Photo Gallery
 * @constructor
 */
function PhotoGalleryState() {
	this.defaultSubNav = 'subNavExt';
	this.blankSubNav = 'subNavDefault'; // Default when no sub nav is present
	this.slideShow = false;
	this.grid = true;
	this.currentThumb;
}
/**
 * Class stores the current state of the SlideShow
 * @constructor
 */
function PhotoSlideShowState(index, grid) {
	this.index = index;
	this.grid = grid;
	this.observerPrevious;
	this.observerForward;
}
/* Wallpaper Controller */

/**
 * Class is responsible for all work regarding the Wallpaper Tab and its content.
 * @constructor
 */
function WallpaperTabController(galleryState, baseGalleryContentUrl) {
	
  	this.galleryState = galleryState;
  	this.baseGalleryContentUrl = baseGalleryContentUrl;
  	
  	this.wallpaperImages = new Object();
    this.mainDivId = 'pgMainWP';
    this.downloadDivId = 'pgWPDnld';
    this.disclaimers = new Object();
	/**
	 * Method handles all Initialization tasks including:
	 * @member WallpaperTabController
	 */
	this.init = function() {
       // Nothing to do
	}
	
	/**
	 * Method preforms necessary cleanup logic before a it can 
	 * be destroyed
	 * @member WallpaperTabController
	 */
    this.cleanup = function() {
    	this.removeContent();
    	
   		for(id in this.wallpaperImages) {
	   	 	var wallpaperImage = this.wallpaperImages[id]
	   	 	wallpaperImage.clearOnload();
	   	 	wallpaperImage = null;
	   }
	   this.wallpaperImages = null;
    }	
	/**
	 * Method returns an Ajax.Updater object to be used to 
	 * gather the correct template "photoGallery.html" and onComplete
	 * will call _prepareContent, which will prep the content.
	 * @member WallpaperTabController
	 */
	this.buildAjaxUpdater = function() {
		return new Ajax.Updater(
			    'pgMainBodyContainer',
			    GalleryUtils.buildAjaxUrl([this.baseGalleryContentUrl + this.galleryState.galleryType + '/' + this.galleryState.modelId + '/wallpapers.html']),
			    {
			 	    method: 'get',
				    wait: true,
				    onComplete: this._prepareContent.bind(this)
			    }
			  )
	}
	
	/**
	 * Method is called by onComplete of the Ajax.Updater proved by 
	 * buildAjaxUpdater().  Method will prep all images that need caching and
	 * will add Events where needed. And will switch the current view of the 
	 * Photo Gallery content, such as the SlideShow, or the Grid
	 * @member WallpaperTabController
	 */
	this._prepareContent = function() {
		if($(this.mainDivId)) {
		  this._loadImages();
		  this._prepareLinks();
		  this.disclaimers = galleryManager.doGalleryAction(null, 'findDisclaimers');
		  this._updateDisclaimers();
		}	
		
	}
    this._updateDisclaimers = function() {
     	
     	var disclaimers = this.disclaimers['Wallpaper'];
     	galleryManager.doGalleryAction(null, 'updateDisclaimers',[disclaimers]);
     } 
    /**
	 * Method removes the Tab's content
	 * @member WallpaperTabController
	 */
	this.removeContent = function() {		
		if($(this.mainDivId)) {
		  $(this.mainDivId).parentNode.removeChild($(this.mainDivId));
		}
	}
	
	/**
	 * Method loads all wallpaper thumbnail images. First
	 * the images will be swapped with the "loading" placeholder
	 * image. Next each real wallpaper image is found and stored into
	 * a WallpaperImage.thumbPhoto object for later use. An onload event is set to the
	 * thumbPhoto, when fully downloaded the image will replce the "loading" placeholder.
	 * @member WallpaperTabController
	 */
	this._loadImages = function() {
		var divs = document.getElementsByClassName('pgWPThumb','pgBodyGridWP','DIV')
		
		for(var i=0; i<divs.length; i++) {
			var div = divs[i];	
		
            var domImg = div.firstChild;
			var images = domImg.src.split('#');
			
            //Add Loading Images First
            GalleryUtils.buildLoadingElement(div,251,160);
			
			var key = WallpaperImage.getImageKeyStatic(domImg);
			div.name = key;
			this.wallpaperImages[key] = new WallpaperImage();
			
			this.wallpaperImages[key].thumbPhoto.onload =
					function() {
						GalleryUtils.replaceImage(this.thumbPhoto,this.element);
					
					}.bind({thumbPhoto:this.wallpaperImages[key].thumbPhoto, element:div.firstChild});
					
			this.wallpaperImages[key].thumbPhoto.src = images[1];
		}
	}
	
	/**
	 * Method prepares all resolution links with the proper method call.
	 * And also addes the onclick event to the download page's Back Link.
	 * @member WallpaperTabController
	 */
	this._prepareLinks = function() {
		
      // Prepare all Download Size links
      var downloadLinks = document.getElementsByClassName('pgWPDnldLinks','pgMainWP','DIV')
      downloadLinks.each(function(downloadLink) {
      	
      	var sizeDesc = document.getElementsByClassName('pgWPSizeDesc',downloadLink,'DIV')[0];
      	var resolution = sizeDesc.firstChild.firstChild.nodeValue.toLowerCase().split(' x ')[0];
      	var key = $NL(downloadLink.parentNode.childNodes).firstElement().name;
      	
      	// Add events to the Arrow and the Text Only
      	$NL( downloadLink.getElementsByTagName('DIV') ).each(function(div){
      	  Event.observe(div, 'click', function(){galleryManager.doTabAction(downloadLink,'showDownload',[key,resolution])})
      	});
      });

      // Add event to the Back Button
      var backButton = $('pgBack');
      Event.observe($('pgBack'), 'click', function(){galleryManager.doTabAction($('pgBack'),'showMain')})
	}
	
	/**
	 * Methdo handles the hide && show of both the mainDiv and the download Div.
	 * @member WallpaperTabController
	 */
	this._toggleWallpaper = function(view) {	
		$(this.mainDivId).style.display = (view == 'MAIN') ? 'block' : 'none';
		$(this.downloadDivId).style.display = (view == 'MAIN') ? 'none' : 'block';		
	}

	
	/** View Action Methods **/
      
    /**
     * Method will show the Download page showing the 
     * desired image and resolution
     * @member WallpaperTabController
     */
    this.showDownload = function(sizeDom, key, resolution) {
      
      // Set the desired Images (Large and Correct Resolution)
      var wallpaperImage = this.wallpaperImages[key];
      var currentResolutionImg = (resolution == '1024') ? wallpaperImage.res1024Photo : wallpaperImage.res1280Photo;
      
      /*
       * Swaping Large Image
       */
      // Swap to Loading Image before we change to the real image 
      GalleryUtils.buildLoadingElement($('pgWPDnldPlaceHolder'),552,414,GalleryManager.LARGE);

      // Swap the Large Image  
      if(wallpaperImage.largePhoto.src == '' || wallpaperImage.largePhoto.src.indexOf('.html') > -1) {
        
        //Swap the Large Image when the image only when it has completed downloaded and the Resolution Image has been downloaded
        wallpaperImage.largePhoto.onload = 
        			function() {
        							if(currentResolutionImg.complete){
        								GalleryUtils.replaceImage(this,$('pgWPDnldPlaceHolder').firstChild) 
        							}
        						}.bind(wallpaperImage.largePhoto);

        wallpaperImage.largePhoto.src = '/lexus-share/images/gallery/' + this.galleryState.galleryType + '/' + this.galleryState.modelId + '/wallpapers/wall_large/' + wallpaperImage.getImageName();
      }
      else if(currentResolutionImg.complete) {
      	GalleryUtils.replaceImage(wallpaperImage.largePhoto,$('pgWPDnldPlaceHolder').firstChild);
      }

      /*
       * Swaping Real High Resolution Image and add onload to swap the Large Image
       */
      if(currentResolutionImg.src == '' || currentResolutionImg.src.indexOf('.html') > -1) {
      	  // Swap the Large image once the Resolution Image has been completly downloaded
          currentResolutionImg.onload = 
          			function() {
          							GalleryUtils.replaceImage(this.largePhoto,$('pgWPDnldPlaceHolder').firstChild)
          							GalleryUtils.replaceImage(this.currentResolutionImg,$('pgWPDnldRealImage').firstChild)	
          						}.bind({largePhoto:wallpaperImage.largePhoto, currentResolutionImg: currentResolutionImg});

          currentResolutionImg.src = '/lexus-share/images/gallery/' + this.galleryState.galleryType + '/' + this.galleryState.modelId + '/wallpapers/wall' + resolution + '/' + wallpaperImage.getImageName();          
      }
         
      /*
       * Set Header Text for correct Resolution
       */ 
      $('pgWPDnldResolution').firstChild.nodeValue = (resolution == '1024') ? '1024x768' : '1280x1024';
      
      /*
       * Show the download page
       */
      this._toggleWallpaper('DOWNLOAD');
    }
    /**
     * Method will show the Main page
     * @member WallpaperTabController
     */
    this.showMain = function() {
      this._toggleWallpaper('MAIN');      	
    }
    //Perform the Init function on instantiation
    this.init();
}
WallpaperTabController.TAB_KEY = 'WALLPAPER';
WallpaperTabController.prototype.TAB_KEY = 'WALLPAPER';

/**
 * Class stores the different Images needed
 * for each picture on the Photo Gallery
 * @constructor
 */
function WallpaperImage() {
  	this.thumbPhoto = new Image();
  	this.largePhoto = new Image();
  	this.res1024Photo = new Image();
  	this.res1280Photo = new Image();
  	
  	this.getImageName = function() {
  	  if(this.thumbPhoto.src == '')
  	    return;
  	    
      return WallpaperImage.getImageNameStatic(this.thumbPhoto);
  	}
  	this.clearOnload = function() {
		this.thumbPhoto.onload = Prototype.emptyFunction;	
		this.largePhoto.onload = Prototype.emptyFunction;
		this.res1024Photo.onload = Prototype.emptyFunction;
		this.res1280Photo.onload = Prototype.emptyFunction;
	}
  	
}
WallpaperImage.getImageNameStatic = function(img) {
	var pieces = img.src.split('/');
	return pieces[pieces.length-1];
}
WallpaperImage.getImageKeyStatic = function(img) {
	return WallpaperImage.getImageNameStatic(img).replace('.jpg','');
}


/**
 * Class is responsible for all work regarding the Screen Saver Tab and its content.
 * @constructor
 */
function ScreenSaverTabController(galleryState, baseGalleryContentUrl) {
	
  	this.galleryState = galleryState;
  	this.baseGalleryContentUrl = baseGalleryContentUrl;
  	
    this.mainDivId = 'pgSS';
    this.disclaimers = new Object();

	/**
	 * Method handles all Initialization tasks including:
	 * @member ScreenSaverTabController
	 */
	this.init = function() {
       // Nothing to do
	}
	
	/**
	 * Method preforms necessary cleanup logic before a it can 
	 * be destroyed
	 * @member ScreensaverTabController
	 */
    this.cleanup = function() {
    	this.removeContent();
    }	
	/**
	 * Method returns an Ajax.Updater object to be used to 
	 * gather the correct template "photoGallery.html" and onComplete
	 * will call _prepareContent, which will prep the content.
	 * @member ScreenSaverTabController
	 */
	this.buildAjaxUpdater = function() {
		return new Ajax.Updater(
			    'pgMainBodyContainer',
			     GalleryUtils.buildAjaxUrl([this.baseGalleryContentUrl + this.galleryState.galleryType + '/' + this.galleryState.modelId + '/screensavers.html']),
			    {
			 	    method: 'get',
				    wait: true,
				    onComplete: this._prepareContent.bind(this)
			    }
			  )
	}
	
	/**
	 * Method is called by onComplete of the Ajax.Updater proved by 
	 * buildAjaxUpdater().  Method will prep all images that need caching and
	 * will add Events where needed. And will switch the current view of the 
	 * Photo Gallery content, such as the SlideShow, or the Grid
	 * @member ScreenSaverTabController
	 */
	this._prepareContent = function() {
		if($(this.mainDivId)) {
		  this._buildFlashSample();
		  this._prepareLinks();
		  this.disclaimers = galleryManager.doGalleryAction(null, 'findDisclaimers');
		  this._updateDisclaimers();
		}	
	}
    this._updateDisclaimers = function() {
     	
     	var disclaimers = this.disclaimers['Screensaver'];
     	galleryManager.doGalleryAction(null, 'updateDisclaimers',[disclaimers]);
     } 
    /**
	 * Method removes the Tab's content
	 * @member ScreenSaverTabController
	 */
	this.removeContent = function() {		
		if($(this.mainDivId)) {
		  $(this.mainDivId).parentNode.removeChild($(this.mainDivId));
		}
	}

	/**
	 * Method prepares all resolution links with the proper method call.
	 * And also addes the onclick event to the download page's Back Link.
	 * @member ScreenSaverTabController
	 */
	this._prepareLinks = function() {
		var downloadLinks = document.getElementsByClassName('pgSSPCDnld','pgSSMain','DIV');
		
		for(var i=0; i<downloadLinks.length; i++) {
			var href = '/lexus-share/gallery/' + this.galleryState.galleryType + '/' +  this.galleryState.modelId + '/screensavers/' + this.galleryState.modelId + '_screensaver';			
			var downloadLink = downloadLinks[i].firstChild;
			var id = downloadLink.id;
		    
		    // Add the proper extension
			if(id.indexOf('_PC') > -1)
			  href += '.exe';
			else if(id.indexOf('_MAC') > -1)
			  href += '.zip';
			
			downloadLink.href = href;
		}
	}

	this._getFlashParameters = function(movie) {
	  	var params = new Object();
 		var paramDivs = movie.getElementsByTagName('DIV');
 		
 		//Gather all parameters for a movie		
 		params = GalleryUtils.buildParamters(paramDivs)
 		
	  	return params;
	  }	 
	  
	  
	 this._buildFlashSample = function() {
		var params = this._getFlashParameters($('pgSSSample'));
		MovieUtils.buildFlashMovie('pgSSSample',params, true);
	 }	
    //Perform the Init function on instantiation
    this.init();
}
ScreenSaverTabController.TAB_KEY = 'SCREENSAVER';
ScreenSaverTabController.prototype.TAB_KEY = 'SCREENSAVER';

/**
 * Class is responsible for all work regarding the Screen Saver Tab and its content.
 * @constructor
 */
function VideoTabController(galleryState, baseGalleryContentUrl) {
	
  	
  	this.galleryState = galleryState;
  	this.baseGalleryContentUrl = baseGalleryContentUrl;
  	this.tabState = new VideoState();
    this.mainDivId = 'pgVd';
    
    this.movies = new Object();
    this.disclaimers = new Object();

	/**
	 * Method handles all Initialization tasks including:
	 * @member VideoTabController
	 */
	this.init = function() {
       // Nothing to do
	}
	this.cleanup = function() {
       	window.onunload = function(){};
       	this.removeContent();
	}
	/**
	 * Method returns an Ajax.Updater object to be used to 
	 * gather the correct template "photoGallery.html" and onComplete
	 * will call _prepareContent, which will prep the content.
	 * @member VideoTabController
	 */
	this.buildAjaxUpdater = function() {
		return new Ajax.Updater(
			    'pgMainBodyContainer',
			    GalleryUtils.buildAjaxUrl([this.baseGalleryContentUrl + this.galleryState.galleryType + '/' + this.galleryState.modelId + '/videos.html']),
			    {
			 	    method: 'get',
				    wait: true,
				    onComplete: this._prepareContent.bind(this)
			    }
			  )
	}
	
	/**
	 * Method is called by onComplete of the Ajax.Updater proved by 
	 * buildAjaxUpdater().  Method will prep all images that need caching and
	 * will add Events where needed. And will switch the current view of the 
	 * Photo Gallery content, such as the SlideShow, or the Grid
	 * @member VideoTabController
	 */
	this._prepareContent = function() {
		if($(this.mainDivId)) {
		  this._findAllMovies();
		  this.disclaimers = galleryManager.doGalleryAction(null, 'findDisclaimers');
		  this._buildFlashMoviePlayer();
		  
		}	
		
	}
    this.videoPlayerLoaded = function() {
    	this._showSubNav(this._getCorrectSubNav());
    }
    this._getCorrectSubNav = function() {
		if($(this.galleryState.subNav))  {
			return $(this.galleryState.subNav).firstChild
		}
		else {
			var subNav = document.getElementsByClassName('pgSubNav','pgMainPhotosGrid','DIV')[0];
			
			return subNav.getElementsByTagName('LI')[0].firstChild;
		}
		
	}
    /**
	 * Method removes the Tab's content
	 * @member VideoTabController
	 */
	this.removeContent = function() {		
		if(document.lp3_videoplayer) {
			document.lp3_videoplayer.stopVideo();
			$('lp3_videoplayer').parentNode.removeChild($('lp3_videoplayer'));
		}
		if($(this.mainDivId)) {
		  $(this.mainDivId).parentNode.removeChild($(this.mainDivId));
		}
		
	}
	
	/**
	 * Method prepares all video links.
	 * @member VideoTabController
	 */
	this._findAllMovies = function() {
		
		var views = document.getElementsByClassName('pgVdAvlVideosContainer', this.mainDivId, 'DIV')
		
		for(var i=0; i<views.length; i++) {
			var view = views[i];
			var viewId = view.id.replace('pgMain','');
			
			this.movies[viewId] = new Object();
			
			var movies = this.movies[viewId];
			
			var lis = view.getElementsByTagName('LI');
			
			for(var x=0; x<lis.length; x++) {
				var li = lis[x];
				li.id = x;
				
				var movieName = li.getAttribute('video');
				var movieVersion = li.getAttribute('version');
				var movieDesc = li.innerHTML;				
				
				var movie = new VideoMovie(li.id, movieName, movieDesc, movieVersion, viewId) 
			  	
			    Event.observe(li,'mouseover', function() {galleryManager.doTabAction(this,'toggleMouseOver',[this])}.bind(li), false);
				Event.observe(li,'mouseout', function() {galleryManager.doTabAction(this,'toggleMouseOut',[this])}.bind(li), false);
			  	Event.observe(li,'click', function() {galleryManager.doTabAction(this.li,'playMovie',[this.viewId])}.bind({li:li, viewId: viewId}), false);
			  
			  	movies[li.id] = movie;
			}
		}
	}
	this.toggleMouseOver = function(element) {
		element.className = 'pgArrowLeftOver';
	}
	this.toggleMouseOut = function(element) {
		element.className = 'pgArrowLeft';
	}
	  /**
      * Method take the Dom Element passed in and shows this view of the
      * Video Gallery. Example Features or Commercials.
      * @param subNavImage - Dom Element reference of the image in the subNav that was clicked
	  * @member VideoTabController 
      */
     this.showSubNav = function(subNavImage) {
     	var subNavId = (subNavImage.parentNode.id);
     	if(subNavId != this.galleryState.subNav) {
     		this._showSubNav(subNavImage);
     	}
     }
     /**
      * Method take the Dom Element passed in and shows this view of the
      * Video Gallery. Example Features or Commercials.
      * @param subNavImage - Dom Element reference of the image in the subNav that was clicked
	  * @member VideoTabController  
      */
     this._showSubNav = function(subNavImage) {
		
		if(subNavImage) {
			var subNavId = (subNavImage.parentNode.id);
			
			var videoId = 'pgMain' + subNavId.replace('subNav','')
			var views = document.getElementsByClassName('pgVdAvlVideosContainer',this.mainDivId,'DIV');
			
			this._updateSubNav(subNavImage);
			
			for(var i=0; i<views.length; i++) {
				var view = views[i];
					
				if(videoId == view.id) {
					view.style.display = 'block';
					this.tabState.subNav = subNavId;
				}
				else {
					view.style.display = 'none';
				}
			}
		}
		else {
			$('pgMainFeature').style.display = 'block';	
		}
		//$('pgVdVideoContainer').style.display = 'block';
		var movie = this.movies[this.galleryState.getSubNavKey()] [0];
		
		this._playMovie(movie);
		 	
	}
	/**
	 * Method updates the sub navigation based on the subNav image that is passed into
	 * the method.
	 * 
	 * @param subNavImage - Dom Element reference of the image in the subNav that was clicked
	 * @member VideoTabController
	 */
	this._updateSubNav = function(subNavImage) {
  	  var subDivs = document.getElementsByClassName('pgSubNav', 'pgMainBodyContainer','DIV')
  	  var currentClassName = subNavImage.parentNode.className;
  	  
  	  this.galleryState.subNav = subNavImage.parentNode.id;
  	  
  	  subDivs.each(function(subDiv) {
  	 	var lis = subDiv.getElementsByTagName('LI');
  	 	
	  	// Turn off any element that is currently on
	  	for(var i=0; i<lis.length; i++) {
	  		var img = lis[i].firstChild;
	  		if(img.src.indexOf('On.gif') > -1) {
	  			img.src = img.src.replace('On.gif', '.gif');
	  			img.style.cursor = 'pointer';
	  		}
	  		// Turn on the element that is current
	  		if(currentClassName == lis[i].className) {
	  			img.src = img.src.replace('.gif', 'On.gif');		  			
	  			img.style.cursor = 'default';
	  		}
	  	 }
  	   });
  	   this._updateDisclaimers();
     }
     this._updateDisclaimers = function() {
     	var viewId = this.galleryState.getSubNavKey();
     	var disclaimers = this.disclaimers[viewId];
     	galleryManager.doGalleryAction(null, 'updateDisclaimers',[disclaimers]);
     } 
	this._loadMovie = function(movie) {
		if(document.lp3_videoplayer) {
			document.lp3_videoplayer.prepareVideo(this.modelId, movie.name, movie.version, this.getVideoKey());
			$('pgVdVideoName').innerHTML = movie.description;	
			this.tabState.currentMovie = movie;
		}
	}
	 this._buildFlashMoviePlayer = function(element) {

	 	var src = '/lexus-share/gallery/assets/videoplayer/lp3_videoplayer';
	 	
	 	var params = new Object() ;
	 	params['width'] = 640;
		params['height'] = 395;
		params['movie'] = src;
	 	params['codebase'] = 'http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0';
		params['type'] = 'application/x-shockwave-flash';
		params['id'] = 'lp3_videoplayer';
		params['name'] = 'lp3_videoplayer';
		params['allowScriptAccess'] = 'sameDomain';
		params['quality'] = 'high';
		params['bgcolor'] = '#000000';
		//if(!isMacBrowser()) {
			params['wmode'] = 'transparent';
		//}
		
		params['scale'] = 'exactfit';
	 	

	 	MovieUtils.buildFlashMovie('pgVdVideo',params, true);
		
		// Flash is not installed, we need to handle this gracefully.
		// Still act like we loaded the player so we can show the correct subNav.
		if(!Plugin.isInstalled('Flash')) {
			this.videoPlayerLoaded();
		}
	 }
	/**
	 * View Action Methods
	 */
	 this.playMovie = function(element,viewId) {
	 	this.toggleMouseOut(element);
	 	
	 	if(document.lp3_videoplayer) {
	 		var movie = this.movies[viewId] [element.id];
			this._playMovie(movie);
	 	}
	 }
	 this._playMovie = function(movie) {
	 	if(document.lp3_videoplayer) {
			document.lp3_videoplayer.playVideo(this.galleryState.modelId, movie.name, movie.version, this.getVideoKey());
			$('pgVdVideoName').innerHTML = movie.description;	
			this.tabState.currentMovie = movie;
	 	}
	 	
	 }
	 this.adjustDescPlacement = function(format){
	 	
	 	switch (format) {
	 		case VideoTabController.LARGE_FORMAT:
	 			$('pgVdVideoName').style.paddingLeft = '0';
	 			break;

	 		default:
	 			$('pgVdVideoName').style.paddingLeft = '80px';
	 			break;
	 	}

	 }
	 this.getVideoKey = function() {
		if(this.galleryState.subNav.indexOf('Features') > -1) {
			return 'models';
		}
		else {
			return 'commercial';
		}
	}
    //Perform the Init function on instantiation
    this.init();
}
function VideoState() {
	this.defaultSubNav = 'subNavFeatures';
	this.currentMovie = false;
		
}
function VideoMovie(id,name, desc, version, viewId) {
	this.id   = id;
	this.name = name;
	this.description = desc;
	this.version = version;
	this.viewId = viewId;
	
}
VideoTabController.TAB_KEY = 'VIDEO';
VideoTabController.prototype.TAB_KEY = 'VIDEO';
VideoTabController.LARGE_FORMAT = '16:9';

/**************************
 * window scope method used to accept and broker
 * the callback from the Flash Video Player letting
 * the page know video format
 */
function videoGalleryChangeSize(format) {
	galleryManager.doTabAction(this,'adjustDescPlacement',[ format ]);
}
function  videoPlayerLoaded() {
	galleryManager.doTabAction(this,'videoPlayerLoaded',[]);
}


/**
 * Class is responsible for all work regarding the Screen Saver Tab and its content.
 * @constructor
 */
var spinPresetFrames = new Array();
function Video360TabController(galleryState, baseGalleryContentUrl) {
	
  	this.galleryState = galleryState;
  	this.baseGalleryContentUrl = baseGalleryContentUrl;
  	
    this.mainDivId = 'pg360';
	this.video360State = new Video360State();
	this.childIframes = new Object();
	this.presetImages = new Object();
	this.viewPointMethods;
	this.disclaimers = new Object();
	/**
	 * Method handles all Initialization tasks including:
	 * @member Video360TabController
	 */
	this.init = function() {
       // Nothing to do
	}
	this.cleanup = function() {
       // Nothing to do
       
       this.video360State.movies = new Object();
       
       this._cleanupOldMovies();
       this.presetImages = null;
       this.removeContent();
	}
	/**
	 * Method returns an Ajax.Updater object to be used to 
	 * gather the correct template "photoGallery.html" and onComplete
	 * will call _prepareContent, which will prep the content.
	 * @member Video360TabController
	 */
	this.buildAjaxUpdater = function() {
		return new Ajax.Updater(
			    'pgMainBodyContainer',
			    GalleryUtils.buildAjaxUrl([this.baseGalleryContentUrl + this.galleryState.galleryType + '/' + this.galleryState.modelId + '/360.html']),
			    {
			 	    method: 'get',
				    wait: true,
				    evalScripts: true,
				    onComplete: this._prepareContent.bind(this)
			    }
			  )
	}
	
	/**
	 * Method is called by onComplete of the Ajax.Updater proved by 
	 * buildAjaxUpdater().  Method will prep all images that need caching and
	 * will add Events where needed. And will switch the current view of the 
	 * Photo Gallery content, such as the SlideShow, or the Grid
	 * @member Video360TabController
	 */
	this._prepareContent = function() {
		if($(this.mainDivId) || $('pg360ES')) {
		  this._buildMovies();
		  this.disclaimers = galleryManager.doGalleryAction(null, 'findDisclaimers');
		  Debug.debug('_prepareContent');
		  this.showMovie($(this.galleryState.subNav));
		  //this.showMovie($(this.galleryState.subNav));
		  //this.showMovie($(this.galleryState.subNav));
		}	
		
	}
    this._updateDisclaimers = function(viewId) {
     	var disclaimers = this.disclaimers[viewId];
     	galleryManager.doGalleryAction(null, 'updateDisclaimers',[disclaimers]);
     }
    /**
	 * Method removes the Tab's content
	 * @member Video360TabController
	 */
	this.removeContent = function() {		
		if($(this.mainDivId)) {
		  if(this.video360State.currentMovie &&
		  	 this.video360State.currentMovie.typeOfMovie == 'quicktime') 
		  {
		  	this._addMovieToClear();
		  }
		  $(this.mainDivId).parentNode.removeChild($(this.mainDivId));
		}
	}
	this._addMovieToClear = function() {
		params = this.video360State.currentMovie.params;
	  	var movie = new Object();
	  	movie.movie = '/lexus-share/gallery/models/ES/360s/deactivate.swf';
	  	MovieUtils.buildQuickTimeMovie(params['container'], movie,false);
	}
	this.showMovie = function(subNav) {
		var subNavId;
		var movie;
		if(subNav && subNav.firstChild) {
			Debug.debug('subNav && subNav.firstChild')
			var subNavImage = subNav.firstChild;
			subNavId = subNavImage.parentNode.id;
			this._updateSubNav(subNavImage);
			
			if(subNavId == 'subNavExt') {
				Debug.debug('subNavExt TIME');
				
				$('pg360Ext').style.visibility = 'visible'
				$('pg360Ext').style.display = 'block';
								
				$('pg360Int').style.visibility = 'hidden';
				
				$('pg360Ext').style.zIndex = '99';
				$('pg360Int').style.zIndex = '98';
				
				
				
				
				movie = this.video360State.movies['pg360Ext'];				
				this._updateDisclaimers('Ext');
			}
			else {
				$('pg360Int').style.visibility = 'visible'
				$('pg360Int').style.display = 'block';
				
				$('pg360Ext').style.visibility = 'hidden';
				
				$('pg360Int').style.zIndex = '99';
				$('pg360Ext').style.zIndex = '98';
				
				movie = this.video360State.movies['pg360Int'];	
				
				this._updateDisclaimers('Int');			
			}
			
	  		//Take care of large Movies if they exist
	  		if($('pg360ExtLarge')) {
	  			Debug.debug('pg360ExtLarge')
	  			$('pg360ExtLarge').style.visibility = 'hidden';	  
	  			$('pg360ExtLarge').style.zIndex = '98';			
	  		}
	  		if($('pg360IntLarge')) {
	  			Debug.debug('pg360IntLarge')
	  			$('pg360IntLarge').style.visibility = 'hidden';
	  			$('pg360IntLarge').style.zIndex = '98';
	  		}
		}
		else {
			$('pg360Ext').style.visibility = 'visible';	
			$('pg360Ext').style.zIndex = '99';
			movie = this.video360State.movies['pg360Ext'];
			
			this._updateDisclaimers('Ext');		
		}
		if(movie) {
			//Determine which type of movie we are working with
	 		switch ( movie.typeOfMovie) {
	 			case 'viewpoint':
					this._configureForViewPoint(movie,subNavId.replace('subNav', ''));
	 				break;
	 				
	 			case 'flash':
	 				break;
	 				
				case 'quicktime':
					// If we are a MAC browser (safari in paticular), we need to
					// display the quicktime movie one more time, to make sure it appears.
					if(isMacBrowser()) {
						if(subNavId == 'subNavExt')
							$('pg360Ext').style.display = 'block';
						else
							$('pg360Int').style.display = 'block';
					}
	 				break;
	 				
	 			default:
	 				break;
	 		}
	 		this.video360State.currentMovie = movie;
		}
	}
	
	this._turnOffAllMovies = function() {
		var movies = document.getElementsByClassName('pg360MainVP', 'pg360','DIV');
		
		movies.each(function(movie){
			movie.style.visibility = 'hidden';
		})
	}
	 
	 this._configureForViewPoint = function(movie, subNav,ext) {
	 	if(!movie) {
	 		return
	 	} 
	 	ext = (ext) ? ext : '';
	 	this.viewPointMethods = new Object();
	 	this.viewPointMethods.movie = movie;
	 	if(movie.params.transparent) {
	 		movie.Execute('ForceHostLayering(1)');
	 	}
	 	Object.extend(this.viewPointMethods, new ViewPointMethods());
	 	Object.extend(this.viewPointMethods, eval(' new ViewPointMethods' + this.galleryState.modelId + subNav + ext  + '()') );
	 }
	 
	 this.processViewPointAction = function(ref, func, args) {		 
		 if(this.viewPointMethods && this.viewPointMethods[func]) {
		   if(!args) 
		 	args = $A();
		   this.viewPointMethods[func].apply(this.viewPointMethods, args);
		  }
	 }	 

	 this._buildMovies = function() {
	 	var movies = document.getElementsByClassName('pg360MainVP','pg360Movies','DIV');
	 	
	 	this._cleanupOldMovies();
	 	movies.each(function(movie){
	 		
	 		var params = this._getMovieParameters(movie);
	 		var movieObj;
	 		
	 		//Determine which type of movie we are working with
	 		switch (params.type) {
	 			case 'viewpoint':
	 				movieObj = MovieUtils.buildViewPointMovie(params['container'],params, false);
	 				
	 				if(!movieObj) {
	 					this._buildViewPointPreset(movie);
	 				}
	 				break;
	 				
	 			case 'flash':
	 				movieObj = MovieUtils.buildFlashMovie(movie,params);
	 				break;
	 				
				case 'quicktime':
					// If IE we hide, so when the quicktime movie first appears, its not shown on the left
					// side of the browser.
					if(document.all) {
						params['container'].style.display = 'none';
					}
					
	 				movieObj = MovieUtils.buildQuickTimeMovie(params['container'],params, false);
	 				
	 				if(!movieObj) {
	 					this._buildViewPointPreset(movie);
	 				}
	 				// If IE its hidden and we must display it after a slight delay to make sure
	 				// the movie is in the right place.
	 				if(document.all) {
	 					setTimeout(function() {params['container'].style.display = 'block'},500);
	 				}
	 				break;
	 				
	 			default:
	 				break;
	 		}
	 		if(movieObj) {
	 			movieObj.typeOfMovie = params.type;
	 			movieObj.params = params;
	 		}
	 		this.video360State.movies[movie.id] = movieObj;
	 	}.bind(this))
	 }	
	 
	 this._buildViewPointPreset = function(movie) {
	 		this._cleanupOldMovies();
	 		this.video360State.vpPreset = true;
	 		
	 		var subNavId = movie.id.replace('pg360','');
	 		
	 		var movieContainer = document.getElementsByClassName('pg360MovieContainer',movie, 'DIV')[0];
	 		var presetContainer = document.getElementsByClassName('pg360PresetContainer',movie, 'DIV');
	 		
	 		// we need to make sure preset is availible before we do anything
	 		if(presetContainer.length > 0) {
	 			presetContainer = presetContainer[0];
	 		 
	 		
		 		var images = presetContainer.getElementsByTagName('IMG');
		 		var imageArray = new Array();
		 		for(var i=0; i<images.length; i++) {
		 			var imgCache = new Image();
		 			imgCache.src = images[i].src;
		 			imageArray.push(imgCache);
		 		}
		 		this.presetImages[subNavId] = imageArray;
		 		
		 		movieContainer.style.display = 'none';		
		 		presetContainer.style.display = 'block';
	 		}
	 }
	 this._cleanupOldMovies = function() {
	 	this.video360State.movies = new Object();
	 	this.video360State.vpPreset = false;
	 	for(i in this.childIframes) {
       	  var iframe = this.childIframes[i];
       	  if(iframe.tearDown) {
       	  	iframe.tearDown();
       	  }
       }
	 	this.childIframes = new Object();
	 	stopSpin();
	 	
	 }
	 this._getMovieParameters = function(movie) {
	  	var params = new Object();
 		var spinsGalleryViewer = document.getElementsByClassName('spinsGalleryViewer',movie,'DIV')[0];
 		var paramDivs = spinsGalleryViewer.getElementsByTagName('DIV');
 		
 		//Gather all parameters for a movie
 		
 		params = GalleryUtils.buildParamters(paramDivs)
 		
 		params['container'] = spinsGalleryViewer;
	  	return params;
	  }	 
	/**
     * Method will update the SubNav view for all views: Grid and SlideShow
     * @member Video360TabController
     */
    this._updateSubNav = function(subNavImage) {
  	  var subDivs = document.getElementsByClassName('pgSubNav', $('pgMainBodyContainer'),'DIV')
  	  var currentClass = subNavImage.parentNode.className;
  	  
  	   this.galleryState.subNav = subNavImage.parentNode.id;
  	  
  	  subDivs.each(function(subDiv) {
  	 	var lis = subDiv.getElementsByTagName('LI');
  	 	
	  	// Turn off any element that is currently on
	  	for(var i=0; i<lis.length; i++) {
	  		var img = lis[i].firstChild;
	  		if(img.src.indexOf('On.gif') > -1) {
	  			img.src = img.src.replace('On.gif', '.gif');		
	  		}
	  		// Turn on the element that is current
	  		if(currentClass == lis[i].className) {
	  			img.src = img.src.replace('.gif', 'On.gif');		  			
	  		}
	  	 }
  	   })
  	   if($('pg360Back'))
		  $('pg360Back').style.display = 'none';
		  
		// Turn on Viewpoint Preset if needed.
		if(this.video360State.vpPreset) {
			this._startVPPreset(subNavImage.parentNode.id.replace('subNav',''));
		}
     }
	
	/**
	 * Method prepares all video links.
	 * @member Video360TabController
	 */
	this._prepareLinks = function() {
		/*
		var lis = $A($(this.mainDivId).getElementsByTagName('LI'));
		
		lis.each(function(li){
			if(li.getAttribute('video')) {
			  var video = li.getAttribute('video');
			  var desc  = li.getAttribute('desc');
			  li.removeAttribute('video');
			  li.removeAttribute('desc');
			  Debug.debug('Video: ' + video + ' Desc: ' + desc);
			  
			  Event.observe(li,'click', function() {galleryManager.doTabAction(this,'buildFlashMovie',[video,desc])}, false);
			}
		})
		*/
	}

	this.showLargeMovie = function(obj, id) {
	 	
	 	var largeMovie;
	 	this._turnOffAllMovies();

		if(this.galleryState.subNav == 'subNavExt') {
	  		largeMovie = 'pg360ExtLarge';
	  	}
	  	else {
	  		largeMovie = 'pg360IntLarge';
	  	}	
	  	if(id && this.childIframes[largeMovie]) {
	  		this.childIframes[largeMovie].callback(id);
	  		
	  	}
	  	else {
	  		this._configureForViewPoint(this.video360State.movies[largeMovie],this.galleryState.getSubNavKey(),'Large');
	  	}	
  		$(largeMovie).style.display = 'block';
  		$(largeMovie).style.visibility = 'visible';
  		$('pg360Back').style.display = 'block';	  			
		this.video360State.largeMovie = largeMovie;	
		
		
	 }
	 
	 this.hideLargeMovie = function() {
	 	this.showMovie($(this.galleryState.subNav));
	 	
	 	if($(this.video360State.largeMovie))
  			$(this.video360State.largeMovie).style.visibility = 'hidden';	 	
  		if($('pg360Back'))
  			$('pg360Back').style.display = 'none';
	 }
	 
	 this.registerWithParent = function(obj, child, id) {
	 	if(id) {
	 		this.childIframes[id] = child;
	 	}
	 }
	 
	 this._startVPPreset = function(id) {
	 	// Preset global varibles, needed by legacy code
	 	curSpin = '';
	 	whereYouAt = (id + 'erior').toLowerCase();
	 	spinPresetFrames = this.presetImages[id];
	 	
	 	playSpin('preset', id);
	 	
	 }
    //Perform the Init function on instantiation
    this.init();
}
Video360TabController.TAB_KEY = '360';
Video360TabController.prototype.TAB_KEY = '360';

function Video360State() {
	this.defaultSubNav = 'subNavExt';
	this.movies = new Object();
	this.currentMovie;
	this.largeMovie;
	
	this.vpPreset = false;
}
canplay = 1;
bcanplay = 0;
xStable = 240;
xStableSet = 0;
cChanged = "";
hyper = 0;
	
function ViewPointMethods() {
	this.movie;
	
	/**
	 * Functions to start spin rotation
	 */
	this.displayImageSpinRight = function(src) {
		this.displayImageSpin('g_360SpinRight.gif');
		this.vwpt_start('rotate_up', 'rotate_right', 'rotate_down', 'rotate_left');
	}
	this.displayImageSpinLeft = function(src) {
		this.displayImageSpin('g_360SpinLeft.gif');
		this.vwpt_start('rotate_up', 'rotate_down', 'rotate_left', 'rotate_right');
	}
	this.displayImageSpinUp = function(src) {
		this.displayImageSpin('g_360SpinUp.gif');
		this.vwpt_start('rotate_up', 'rotate_right', 'rotate_left', 'rotate_down');
	}
	this.displayImageSpinDown = function(src) {
		this.displayImageSpin('g_360SpinDown.gif');
		this.vwpt_start('rotate_down', 'rotate_right', 'rotate_left', 'rotate_up');
	}
	this.displayImageSpin = function (src) {
		if (this.canPlay()) {
			document['nav_spin_' + this.view].src = "/lexus-share/images/gallery/360s/" + src;
			
		}
	}
	/**
	 * Functions zoom in or out
	 */
	this.displayImageZoomOut = function() {
		this.displayImageZoom('g_360ZoomOut.gif');
		this.vwpt_start(' ', ' ', 'zoom_in', 'zoom_out');
		
	}
	this.displayImageZoomIn = function() {
		this.displayImageZoom('g_360ZoomIn.gif');
		this.vwpt_start(' ', ' ', 'zoom_out', 'zoom_in');
		
	}
	this.displayImageZoom = function(src) {
		if (this.canPlay()) {
			document['nav_zoom_' + this.view].src = "/lexus-share/images/gallery/360s/" + src;
		}
	}
	
	/**
	 * Functions to start move
	 */
	 this.displayImageMoveRight = function() {
	 	this.displayImageMove('g_360MoveLeft.gif');
	 	this.vwpt_start('move_up', 'move_right', 'move_down', 'move_left');
	 }
	 this.displayImageMoveLeft = function() {
	 	this.displayImageMove('g_360MoveRight.gif');
	 	this.vwpt_start('move_up', 'move_down', 'move_left', 'move_right');	
	 }
	 this.displayImageMoveUp = function() {
	 	this.displayImageMove('g_360MoveDown.gif');
	 	this.vwpt_start('move_down', 'move_right', 'move_left', 'move_up');	
	 }
	 this.displayImageMoveDown = function() {
	 	this.displayImageMove('g_360MoveUp.gif');
	 	this.vwpt_start('move_up', 'move_right', 'move_left', 'move_down');	
	 }
	 
	this.displayImageMove = function(src) {
		if (this.canPlay()) {
			document['nav_move_' + this.view].src = "/lexus-share/images/gallery/360s/" + src;
		}
	}
	
	this.displayImageReset = function() {
		if (this.canPlay()) {
			document['nav_reset_' + this.view].src = "/lexus-share/images/gallery/360s/g_360ResetOver.gif"; 	
			
		}
	}
	
	this.hideImageSpin = function() {
		if (this.canPlay()) {
			document['nav_spin_' + this.view].src = "/lexus-share/images/gallery/360s/g_360Spin.gif";
		}
	}
	
	this.hideImageZoom = function() {
		if (this.canPlay()) {
			document['nav_zoom_' + this.view].src = "/lexus-share/images/gallery/360s/g_360Zoom.gif";
		}
	}
	
	this.hideImageMove = function() {
		if (this.canPlay()) {
			document['nav_move_' + this.view].src = "/lexus-share/images/gallery/360s/g_360Move.gif";
		}
	}
	
	this.hideImageReset = function() {
		if (this.canPlay()) {
			document['nav_reset_' + this.view].src = "/lexus-share/images/gallery/360s/g_360Reset.gif";
		}
	}
	this.superview = function() {
		if (this.canPlay()) {
			this.movie.PostEvent("superview_message");
		}
	}
	this.vwpt_trigger = function(anim) {
		if (this.canPlay()) {
			this.movie.PostEvent("stop_anim");
			pos = String(this.movie.GetProperty("MTSCamera", "rot_")).split(" ");
			x = parseFloat(pos[0]);
			y = parseFloat(pos[1]);
			z = parseFloat(pos[2]);
			for (i = 0; i < 4; i++) {
				if (y < 0) { y = y + 360; }
			}
			for (i = 0; i < 4; i++) {
				if (y > 360) { y = y - 360; }
			}
			this.movie.SetProperty("MTSCamera", "rot_", x + " " + y + " " + z, "mts_pnt3d");
			this.movie.TriggerAnim(anim);
			
			//setTimeout(function() {TriggerAnim(anim)}, 200);
		}
	}
	this.align = function(anim) {
		pos = String(this.movie.GetProperty("MTSCamera", "rot_")).split(" ");
		x = parseFloat(pos[0]);
		y = parseFloat(pos[1]);
		z = parseFloat(pos[2]);
		for (i = 0; i < 4; i++) {
			if (y < 0) { y = y + 360; }
		}
		for (i = 0; i < 4; i++) {
			if (y > 360) { y = y - 360; }
		}
		this.movie.SetProperty("MTSCamera", "rot_", x + " " + y + " " + z, "mts_pnt3d");
		setTimeout("render", 200);
		setTimeout(function() {triggerAnim(anim)}, 400);
	}
	
	this.vwpt_start = function (stop1, stop2, stop3, ani) {
		if (this.canPlay()) {
			this.movie.PostEvent("stop_anim");
			this.movie.SetProperty("MTSTimeElem."+stop1, "runs", 0, "mts_int");
			this.movie.SetProperty("MTSTimeElem."+stop2, "runs", 0, "mts_int");
			this.movie.SetProperty("MTSTimeElem."+stop3, "runs", 0, "mts_int");
			this.movie.TriggerAnim(ani);
		}
	}
	this.vwpt_stop = function(ani) {
		if (this.canPlay()) {
			this.movie.SetProperty("MTSTimeElem."+ani, "runs", 0, "mts_int");
		}
	}
	this.check_sv = function() {
		
		if (screen.height >= 768) { 
		/*
			top.window.scroll(0,0);
			if (document.all) {
				top.window.resizeTo(screen.availWidth,screen.availHeight);
			}
			else if (document.layers||document.getElementById) {
				if (top.window.outerHeight<screen.availHeight||top.window.outerWidth<screen.availWidth){
					top.window.outerHeight = screen.availHeight;
					top.window.outerWidth = screen.availWidth;
				}
			}
			top.window.scroll(0,200);
			
			*/
			this.movie.TriggerAnim("superview"); 
		}
		else { this.movie.TriggerAnim("nonsuperview"); }
	}
	this.render = function() {
		this.movie.Render();
	}
	this.triggerAnim = function(anim) {
		this.movie.TriggerAnim("MTSTimeElem." + anim)
	}
	this.set_resolution = function() {
		if (screen.height < 650) { 
			this.movie.PostEvent("800by600");
		}
		else {
			this.movie.PostEvent("over800by600");
		}
	}
	this.scroll_to_top = function() {
		if (screen.height < 650) { 
			top.window.scroll(0,0);
			if (document.all) {
				top.window.resizeTo(screen.availWidth,screen.availHeight);
				top.window.moveTo(0,0);
			}
			else if (document.layers||document.getElementById) {
				if (top.window.outerHeight<screen.availHeight||top.window.outerWidth<screen.availWidth){
					top.window.outerHeight = screen.availHeight;
					top.window.outerWidth = screen.availWidth;
				}
			}
			top.window.scroll(0,0);
		}
		else {
			top.window.scroll(0,0);
		}
	}
	
	// Function called when going into detailed view - grey out and disable button clicks here
	this.disable_buttons = function() {
		this.setCanPlay(false);
		
		if($('nav_spin_' + this.view)) {
			$('nav_spin_' + this.view).src = '/lexus-share/images/gallery/360s/g_360SpinOff.gif';
			$('nav_spin_' + this.view).useMap = '';
		}
		if($('nav_zoom_' + this.view)) {
			$('nav_zoom_' + this.view).src = '/lexus-share/images/gallery/360s/g_360ZoomOff.gif';
			$('nav_zoom_' + this.view).useMap = '';
		}
		
		if($('nav_move_' + this.view)) {
			$('nav_move_' + this.view ).src = '/lexus-share/images/gallery/360s/g_360MoveOff.gif';
			$('nav_move_' + this.view).useMap	= '';
		}
		
		if($('nav_reset_' + this.view)) {
			$('nav_reset_' + this.view).src = '/lexus-share/images/gallery/360s/g_360ResetOff.gif';
			$('nav_reset_' + this.view).useMap	= '';
		}
		
		if($('nav_super_' + this.view)) {
			$('nav_super_' + this.view).src = '/lexus-share/images/gallery/360s/g_360SuperZoomOff.gif';
		}
		if($('nav_instr_' + this.view)) {
			$('nav_instr_' + this.view).src = '/lexus-share/images/gallery/360s/gs_360_instructionsOff.gif';
		}
	}
	
	// Function called when leaving detailed view -- ungrey and enable button clicks here
	this.enable_buttons = function() {
		this.setCanPlay(true);
		
		if($('nav_spin_' + this.view)) {
			$('nav_spin_' + this.view).src = '/lexus-share/images/gallery/360s/g_360Spin.gif';
			$('nav_spin_' + this.view).useMap = '#spinMap';
		}
		if($('nav_zoom_' + this.view)) {
			$('nav_zoom_' + this.view).src = '/lexus-share/images/gallery/360s/g_360Zoom.gif';
			$('nav_zoom_' + this.view).useMap = '#zoomMap';
		}
		
		if($('nav_move_' + this.view)) {
			$('nav_move_' + this.view ).src = '/lexus-share/images/gallery/360s/g_360Move.gif';
			$('nav_move_' + this.view).useMap	= '#moveMap';
		}
		
		if($('nav_reset_' + this.view)) {
			$('nav_reset_' + this.view).src = '/lexus-share/images/gallery/360s/g_360Reset.gif';
			$('nav_reset_' + this.view).useMap	= '#resetMap';
		}
		
		if($('nav_super_' + this.view)) {
			$('nav_super_' + this.view).src = '/lexus-share/images/gallery/360s/g_360SuperZoom.gif';
		}
		
		if($('nav_instr_' + this.view)) {
			$('nav_instr_' + this.view).src = '/lexus-share/images/gallery/360s/gs_360_instructions.gif';
		}
	}
}

/***************************************************************
 * Viewpoint Methods that have to be under window.xxxxxx
 ***************************************************************/

function check_sv() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'check_sv' ]);
}
function align(anim) {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'align',[anim] ]);
}
function align2(anim) {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'align',[anim] ]);
}
function render() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'render' ]);
}
function triggerAnim(anim) {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'triggerAnim', [anim] ]);
}
function enlarge_image(letter) {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'enlarge_image', [letter] ]);
}
function enable_buttons() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'enable_buttons']);
}
function disable_buttons() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'disable_buttons']);
}
/*
function superview() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'superview']);	
}
*/
function dragger(x) {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'dragger',[x]]);	
}
function set_resolution() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'set_resolution']);	
}
function set_position() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'set_position']);	
}
function to_hyper() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'to_hyper']);	
}
function to_normal() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'to_normal']);	
}
function scroll_to_top() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'scroll_to_top']);	
}
function show_hotspot() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'show_hotspot']);		
}

function targets_on() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'targets_on']);	
}

function targets_off() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'targets_off']);	
}

function headlight_zoom() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'headlight_zoom']);	
}

function wheel_zoom() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'wheel_zoom']);	
}

function taillight_zoom() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'taillight_zoom']);	
}

function end_superzoom() {
	galleryManager.doTabAction(this,'processViewPointAction',[ 'end_superzoom']);	
}


function ViewPointMethodsISExt() {
	this.view = 'Ext';
	xStable = 240;
	xStableSet = 0;
	cChanged = "";
	hyper = 0;
	
	this.canPlay = function() {
		return (canplay == 1) ? true : false;
	}
	this.setCanPlay = function(onOrOff) {
		canplay = (onOrOff) ? 1 : 0;
	}
	this.dragger = function(x) {
		xStable = xStable - Number(x);
		if (hyper == 0) {
			if (xStable < 85) { xStable = 85; }
			if (xStable > 355) { xStable = 355; }
		}
		else {
			if (xStable < -124) { xStable = -124; }
			if (xStable > 263) { xStable = 263; }
		}
		this.movie.SetProperty("slider_arrow_lc1", "dpin", Number(xStable+11) + " 200", "mts_pnt2d");
		this.movie.SetProperty("slider_bracket_lc1", "dpin", (xStable) + " 208", "mts_pnt2d");
		this.movie.SetProperty("sz_slider_arrow_lc1", "dpin", Number(xStable+14) + " -282", "mts_pnt2d");
		this.movie.SetProperty("sz_slider_bracket_lc1", "dpin", (xStable) + " -274", "mts_pnt2d");
		if (hyper == 0) { xStableSet = Number(Math.floor((xStable-25)/30)); }
		else { xStableSet = Number(Math.round((xStable+210)/43)); }
		if (cChanged != xStableSet) { 
			cChanged = xStableSet;
			this.movie.TriggerAnim("MTSTimeElem.color_" + (xStableSet-1) + "_on_reset");
		}
	}
	
	this.set_position = function() {
		xStable = Number((Math.floor((xStable - 70) / 30) * 30 ) + 85);
		dragger(0);
	}
	
	this.to_hyper = function() {
		xStable = Number(cChanged*43-210); 
	}
	
	this.to_normal = function() {
		xStable = Number(cChanged*30+25); 
	}
} 
function ViewPointMethodsISInt() {
	this.view = 'Int';
	xStable = 99;
	xStableSet = 0;
	cChanged = "";
	
	this.canPlay = function() {
		return (bcanplay == 1) ? true : false;
	}
	this.setCanPlay = function(onOrOff) {
		bcanplay = (onOrOff) ? 1 : 0;
	}
	this.dragger = function(x) {
		xStable = xStable - Number(x);
		if (xStable < 99) { xStable = 99; }
		if (xStable > 324) { xStable = 324; }
		this.movie.SetProperty("slider_arrow_lc1", "dpin", Number(xStable+17) + " 199", "mts_pnt2d");
		this.movie.SetProperty("slider_bracket_lc1", "dpin", (xStable) + " 207", "mts_pnt2d");
		xStableSet = Number(Math.floor((xStable-6)/45));
		if (cChanged != xStableSet) { 
			cChanged = xStableSet;
			this.movie.TriggerAnim("MTSTimeElem.color_" + (xStableSet-1) + "_on_reset");
		}
	}
	
	this.set_position = function() {
		xStable = Number((Math.floor((xStable - 76) / 45) * 45 ) + 99);
		this.dragger(0);
	}
}


function ViewPointMethodsGSInt() {
	this.view = 'Int';
	this.imgIdx = new Array();
	this.imgIdx['a'] = 0;
	this.imgIdx['b'] = 1;
	this.imgIdx['c'] = 2;
	this.imgIdx['d'] = 3;
	this.imgIdx['e'] = 4;
	this.imgIdx['f'] = 5;
	this.imgIdx['g'] = 6;
	this.imgIdx['h'] = 7;
	
	this.canPlay = function() {
		return (bcanplay == 1) ? true : false;
	}
	this.setCanPlay = function(onOrOff) {
		bcanplay = (onOrOff) ? 1 : 0;
	}
	this.enlarge_image = function(letter) {
		galleryManager.doTabAction(null,'showLargeMovie',[this.imgIdx[letter]]);
}
	

}
function ViewPointMethodsGSExt() {
	this.view = 'Ext';
	this.canPlay = function() {
		return (canplay == 1) ? true : false;
	}
	this.setCanPlay = function(onOrOff) {
		canplay = (onOrOff) ? 1 : 0;
	}
	this.vwpt_start = function(stop1, stop2, stop3, ani) {
		if (this.canPlay()) {
			
			this.movie.PostEvent("stop_anim");
			this.movie.PostEvent("clps_intro_box");
			this.movie.SetProperty("MTSTimeElem."+stop1, "runs", 0, "mts_int");
			this.movie.SetProperty("MTSTimeElem."+stop2, "runs", 0, "mts_int");
			this.movie.SetProperty("MTSTimeElem."+stop3, "runs", 0, "mts_int");
			this.movie.TriggerAnim(ani);
		}
	}
	this.vwpt_trigger = function(ani) {
		if (this.canPlay()) {
			this.movie.PostEvent("stop_anim");
			this.movie.TriggerAnim(ani);
		}
	}
	

}
ViewPointMethodsGShExt = function() {};
ViewPointMethodsGShExt = ViewPointMethodsGSExt;
ViewPointMethodsGShInt = function() {};
ViewPointMethodsGShInt = ViewPointMethodsGSInt; 
ViewPointMethodsGShIntLarge = function() {};
ViewPointMethodsGShIntLarge = ViewPointMethodsGShIntLarge;

ViewPointMethodsRXhExt = function() {
	this.view = 'Ext';
	this.headlight_pos_x = new Array("279", "241", "201", "162", "123", "89", "60", "37", "21", "9", "5", "5", "10", "20", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "365", "340", "307");
	this.headlight_pos_y = new Array("82", "82", "82", "82", "82", "83", "83", "83", "82", "82", "82", "81", "80", "79", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "82", "82", "82");
	this.wheel_pos_x = new Array("0", "280", "253", "228", "198", "169", "143", "118", "98", "82", "70", "63", "61", "64", "72", "83", "96", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0");
	this.wheel_pos_y = new Array("0", "129", "129", "129", "129", "130", "130", "130", "129", "128", "128", "127", "126", "124", "122", "120", "120", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0");
	this.taillight_pos_x = new Array("0", "0", "0", "0", "0", "0", "403", "410", "413", "408", "398", "379", "355", "328", "301", "263", "225", "184", "145", "101", "68", "42", "22", "7", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0");
	this.taillight_pos_y = new Array("0", "0", "0", "0", "0", "0", "53", "53", "53", "53", "54", "55", "55", "56", "57", "58", "59", "59", "60", "59", "58", "57", "57", "54", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0");

	this.targets = 1;
	this.new_y = 1;
	this.show_hotspot = function() {
		if (this.targets == 1) {
			var pos = String(this.movie.GetProperty("MTSCamera", "rot_")).split(" ");
			var y = parseFloat(pos[1]);
			var rot_y = y;
			for (var i = 0; i < 36; i++) {
				if (rot_y < 0) { rot_y = rot_y + 360; }
				else { break; }
			}
			for (var i = 0; i < 36; i++) {
				if (rot_y > 360) { rot_y = rot_y - 360; }
				else { break; }
			}
			y = rot_y;
			y = y % 360;
			y = Math.round(y / 10);
			y = y % 36;
			this.new_y = Math.round(y + 1);
			this.movie.SetProperty("MTSCamera", "rot_", "0 " + rot_y + " 0", "mts_pnt3d");
			window.status = "n:" + this.new_y + " y1:" + pos[1] + " y2:" + rot_y + " rot:" + String(this.movie.GetProperty("MTSCamera", "rot_"));
			if (this.headlight_pos_x[this.new_y-1] != 0 && this.headlight_pos_y[this.new_y-1] != 0) {
				this.movie.SetProperty("headlight_layer", "dpin", this.headlight_pos_x[this.new_y-1] + " " + this.headlight_pos_y[this.new_y-1], "mts_pnt2d");
				this.movie.SetProperty("MTSInstance.headlight_parent", "clps", "0", "mts_int");
				this.movie.TriggerAnim("headlight_still_anim");
			}
			if (this.wheel_pos_x[this.new_y-1] != 0 && this.wheel_pos_y[this.new_y-1] != 0) {
				this.movie.SetProperty("wheel_layer", "dpin", this.wheel_pos_x[this.new_y-1] + " " + this.wheel_pos_y[this.new_y-1], "mts_pnt2d");
				this.movie.SetProperty("MTSInstance.wheel_parent", "clps", "0", "mts_int");
				this.movie.TriggerAnim("wheel_still_anim");
			}
			if (this.taillight_pos_x[this.new_y-1] != 0 && this.taillight_pos_y[this.new_y-1] != 0) {
				this.movie.SetProperty("taillight_layer", "dpin", this.taillight_pos_x[this.new_y-1] + " " + this.taillight_pos_y[this.new_y-1], "mts_pnt2d");
				this.movie.SetProperty("MTSInstance.taillight_parent", "clps", "0", "mts_int");
				this.movie.TriggerAnim("taillight_still_anim");
			}
		}
	}

	this.targets_on = function() {
		this.targets = 1;
		this.show_hotspot();
	}

	this.targets_off = function() {
		this.targets = 0;
	}

	this.headlight_zoom = function() {
		this.movie.TriggerAnim("headlight_zoom_" + this.new_y);
	}

	this.wheel_zoom = function() {
		this.movie.TriggerAnim("wheel_zoom_" + this.new_y);
	}

	this.taillight_zoom = function() {
		this.movie.TriggerAnim("taillight_zoom_" + this.new_y);
	}
	this.enlarge_image = function() {
		galleryManager.doTabAction(this,'showLargeMovie');
	}
}

ViewPointMethodsRXhExtLarge = function() {
	this.view = 'Ext';
	this.headlight_pos_x = new Array("475", "413", "347", "283", "219", "164", "116", "78", "52", "32", "26", "26", "34", "50", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "616", "575", "521");
	this.headlight_pos_y = new Array("152", "152", "152", "152", "152", "154", "154", "154", "152", "152", "152", "150", "149", "147", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "152", "152", "152");
	this.wheel_pos_x = new Array("0", "477", "433", "392", "342", "295", "252", "211", "178", "152", "132", "121", "118", "123", "136", "154", "175", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0");
	this.wheel_pos_y = new Array("0", "229", "229", "229", "229", "231", "231", "231", "229", "228", "228", "226", "224", "221", "218", "214", "214", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0");
	this.taillight_pos_x = new Array("0", "0", "0", "0", "0", "0", "679", "690", "695", "687", "670", "639", "600", "556", "511", "449", "387", "319", "255", "183", "129", "86", "54", "29", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0");
	this.taillight_pos_y = new Array("0", "0", "0", "0", "0", "0", "105", "105", "105", "105", "106", "108", "108", "109", "111", "113", "114", "114", "116", "114", "113", "111", "111", "106", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0");

	this.targets = 1;
	this.new_y = 1;
	this.show_hotspot = function() {
		if (this.targets == 1) {
			var pos = String(this.movie.GetProperty("MTSCamera", "rot_")).split(" ");
			var y = parseFloat(pos[1]);
			var rot_y = y;
			for (var i = 0; i < 36; i++) {
				if (rot_y < 0) { rot_y = rot_y + 360; }
				else { break; }
			}
			for (var i = 0; i < 36; i++) {
				if (rot_y > 360) { rot_y = rot_y - 360; }
				else { break; }
			}
			y = rot_y;
			y = y % 360;
			y = Math.round(y / 10);
			y = y % 36;
			this.new_y = Math.round(y + 1);
			this.movie.SetProperty("MTSCamera", "rot_", "0 " + rot_y + " 0", "mts_pnt3d");
			window.status = "n:" + this.new_y + " y1:" + pos[1] + " y2:" + rot_y + " rot:" + String(this.movie.GetProperty("MTSCamera", "rot_"));
			if (this.headlight_pos_x[this.new_y-1] != 0 && this.headlight_pos_y[this.new_y-1] != 0) {
				this.movie.SetProperty("headlight_layer", "dpin", this.headlight_pos_x[this.new_y-1] + " " + this.headlight_pos_y[this.new_y-1], "mts_pnt2d");
				this.movie.SetProperty("MTSInstance.headlight_parent", "clps", "0", "mts_int");
				this.movie.TriggerAnim("headlight_still_anim");
			}
			if (this.wheel_pos_x[this.new_y-1] != 0 && this.wheel_pos_y[this.new_y-1] != 0) {
				this.movie.SetProperty("wheel_layer", "dpin", this.wheel_pos_x[this.new_y-1] + " " + this.wheel_pos_y[this.new_y-1], "mts_pnt2d");
				this.movie.SetProperty("MTSInstance.wheel_parent", "clps", "0", "mts_int");
				this.movie.TriggerAnim("wheel_still_anim");
			}
			if (this.taillight_pos_x[this.new_y-1] != 0 && this.taillight_pos_y[this.new_y-1] != 0) {
				this.movie.SetProperty("taillight_layer", "dpin", this.taillight_pos_x[this.new_y-1] + " " + this.taillight_pos_y[this.new_y-1], "mts_pnt2d");
				this.movie.SetProperty("MTSInstance.taillight_parent", "clps", "0", "mts_int");
				this.movie.TriggerAnim("taillight_still_anim");
			}
		}
	}

	this.targets_on = function() {
		this.targets = 1;
		this.show_hotspot();
	}

	this.targets_off = function() {
		this.targets = 0;
	}

	this.headlight_zoom = function() {
		this.movie.TriggerAnim("headlight_zoom_" + this.new_y);
	}

	this.wheel_zoom = function() {
		this.movie.TriggerAnim("wheel_zoom_" + this.new_y);
	}

	this.taillight_zoom = function() {
		this.movie.TriggerAnim("taillight_zoom_" + this.new_y);
	}
	this.enlarge_image = function() {
		galleryManager.doTabAction(this,'showLargeMovie');
	}
}

ViewPointMethodsRXhInt = function() {
	this.view = 'Int';

	this.align = function(anim) {
		if (anim != "nav_zoom") {
			pos = String(this.movie.GetProperty("MTSCamera", "rot_")).split(" ");
			x = parseFloat(pos[0]);
			y = parseFloat(pos[1]);
			z = parseFloat(pos[2]);
			for (i = 0; i < 4; i++) {
				if (y < 0) { y = y + 360; }
			}
			for (i = 0; i < 4; i++) {
				if (y > 360) { y = y - 360; }
			}
			this.movie.SetProperty("MTSCamera", "rot_", x + " " + y + " " + z, "mts_pnt3d");
		}
		setTimeout(function() {triggerAnim(anim)}, 400);
	}
	this.enlarge_image = function() {
		galleryManager.doTabAction(this,'showLargeMovie');
	}
}
ViewPointMethodsRXhIntLarge = function() {};
ViewPointMethodsRXhIntLarge= ViewPointMethodsRXhInt;
/**
 * Class is responsible for all work regarding the Color Tab and its content.
 * @constructor
 */
function ColorTabController(galleryState, baseGalleryContentUrl) {
	
  	this.galleryState = galleryState;
  	this.baseGalleryContentUrl = baseGalleryContentUrl;
  	
  	this.colorImages = new Object();
    this.mainDivId = 'pgMainColor';
    
    this.tabState = new ColorState();
    this.disclaimers = new Object();
	/**
	 * Method handles all Initialization tasks including:
	 * @member ColorTabController
	 */
	this.init = function() {
       // Nothing to do
	}
	this.cleanup = function() {
	   this.removeContent();
	   
	   for(id in this.colorImages) {
	   	 var colorImage = this.colorImages[id]
	   	 colorImage.clearOnload();
	   	 colorImage = null;
	   }
	   this.colorImages = new Object();
	   this.tabState = null;
	}
		
	/**
	 * Method returns an Ajax.Updater object to be used to 
	 * gather the correct template "photoGallery.html" and onComplete
	 * will call _prepareContent, which will prep the content.
	 * @member ColorTabController
	 */
	this.buildAjaxUpdater = function() {
		return new Ajax.Updater(
			    'pgMainBodyContainer',
			     GalleryUtils.buildAjaxUrl([this.baseGalleryContentUrl + this.galleryState.galleryType + '/' + this.galleryState.modelId + '/colors.html']),
			    {
			 	    method: 'get',
				    wait: true,
				    onComplete: this._prepareContent.bind(this)
			    }
			  )
	}
	
	/**
	 * Method is called by onComplete of the Ajax.Updater proved by 
	 * buildAjaxUpdater().  Method will prep all images that need caching and
	 * will add Events where needed. And will switch the current view of the 
	 * Photo Gallery content, such as the SlideShow, or the Grid
	 * @member ColorTabController
	 */
	this._prepareContent = function() {
		if($(this.mainDivId)) {
			this._prepareSwatches();
			this._cacheAllColorImages();
			this.disclaimers = galleryManager.doGalleryAction(null, 'findDisclaimers');
			this._showSubNav(this._getCorrectSubNav());
			
		}	
		
	}
    this._getCorrectSubNav = function() {
		if($(this.galleryState.subNav))  {
			return $(this.galleryState.subNav).firstChild
		}
		else {
			var subNav = document.getElementsByClassName('pgSubNav','pgMainPhotosGrid','DIV')[0];
			
			return subNav.getElementsByTagName('LI')[0].firstChild;
		}
		
	}
    /**
	 * Method removes the Tab's content
	 * @member ColorTabController
	 */
	this.removeContent = function() {		
		if($(this.mainDivId)) {
		  $(this.mainDivId).parentNode.removeChild($(this.mainDivId));
		}
	}
	
	/**
	 * Method updates the sub navigation based on the subNav image that is passed into
	 * the method.
	 * 
	 * @param subNavImage - Dom Element reference of the image in the subNav that was clicked
	 * @member ColorTabController
	 */
	this._updateSubNav = function(subNavImage) {
  	  var subDivs = document.getElementsByClassName('pgSubNav', 'pgMainBodyContainer','DIV')
  	  var currentClassName = subNavImage.parentNode.className;
  	  
  	  this.galleryState.subNav = subNavImage.parentNode.id;
  	  
  	  subDivs.each(function(subDiv) {
  	 	var lis = subDiv.getElementsByTagName('LI');
  	 	
	  	// Turn off any element that is currently on
	  	for(var i=0; i<lis.length; i++) {
	  		var img = lis[i].firstChild;
	  		if(img.src.indexOf('On.gif') > -1) {
	  			img.src = img.src.replace('On.gif', '.gif');
	  			img.style.cursor = 'pointer';
	  		}
	  		// Turn on the element that is current
	  		if(currentClassName == lis[i].className) {
	  			img.src = img.src.replace('.gif', 'On.gif');		  			
	  			img.style.cursor = 'default';
	  		}
	  	 }
  	   })
  	   this._updateDisclaimers();
     }
     this._updateDisclaimers = function() {
     	var viewId = this.galleryState.subNav.replace('subNav','');
     	var disclaimers = this.disclaimers[viewId];
     	galleryManager.doGalleryAction(null, 'updateDisclaimers',[disclaimers]);
     }
     /**
      * Method take the Dom Element passed in and shows this view of the
      * Color Gallery. Example Exterior or Interior.
      * @param subNavImage - Dom Element reference of the image in the subNav that was clicked
	  * @member ColorTabController 
      */
     this.showSubNav = function(subNavImage) {
     	var subNavId = (subNavImage.parentNode.id);
     	if(this.tabState.currentColor && subNavId != this.galleryState.subNav) {
     		this._showSubNav(subNavImage);
     	}
     }
     /**
      * Method take the Dom Element passed in and shows this view of the
      * Color Gallery. Example Exterior or Interior.
      * @param subNavImage - Dom Element reference of the image in the subNav that was clicked
	  * @member ColorTabController 
      */
     this._showSubNav = function(subNavImage) {
		
		if(subNavImage) {
			var subNavId = (subNavImage.parentNode.id);
			
			var colorId = 'pgMain' + subNavId.replace('subNav','')
			var views = document.getElementsByClassName('pgMainColorView','pgMainColor','DIV');
			
			this._updateSubNav(subNavImage);
			
			for(var i=0; i<views.length; i++) {
				var view = views[i];
					
				if(colorId == view.id) {
					this.switchColor(view.id.replace('pgMain', '') + 0);
					view.style.display = 'block';
					
				}
				else {
					view.style.display = 'none';
				}
			}
		}
		else {
			$('pgMainExt').style.display = 'block';	
			this.switchColor('Ext' + 0);
		}
		 	
	}
	/**
	 * Method scrubs the DOM and find all swatches and then caches each
	 * on and off states and addes events to each once both on and off state images
	 * have been downloaded and cached.
	 * @member ColorTabController
	 */
	this._prepareSwatches = function() {
		var chipContainers = document.getElementsByClassName('pgColorChips', this.mainDivId, 'DIV');
		for(var i=0; i<chipContainers.length; i++) {
			var chipContainer = chipContainers[i];
			var cacheIdRoot = chipContainer.id.replace('pgColorChips','');
			var chipsImg = chipContainer.getElementsByTagName('IMG');
			
			// Cache each Chip Image and its on state, set an Onload event to switch out spacer.gif when
			// real image is cached.
			// also
			// add events to image when on state image is cached
				
			for(var x=0; x<chipsImg.length; x++) {
				var spacer = document.createElement('IMG');
				var colorImage = new ColorImage(cacheIdRoot + x);
				
				var chipImg = chipsImg[x];
				var images = chipImg.src.split('#');
				
				// Gather the color description off the alt attribute
				colorImage.colorDescription = chipImg.alt;
				
				// Set the new id on the span (parentNode) and set span as element
				chipImg.parentNode.id = colorImage.id;
				colorImage.swatchElement = chipImg.parentNode;

				// Quick replace with a spacer image so we dont see a missing image signal in firefox				
 				spacer.src = '/lexus-share/images/spacer.gif';
 				chipImg.parentNode.replaceChild(spacer, chipImg);		
				
				// Add onload event to real image
				colorImage.swatchImage.setOnload(function() {
    	      		GalleryUtils.replaceImage(this.image,this.currentImg);
        	  	}.bind({image:colorImage.swatchImage.image, currentImg: spacer}));
        	  
        	    colorImage.swatchOnImage.setOnload(function() {
        	       if(!this.obj || !this.obj.tabState)
        	       		return;
        	       	
        	       if(this.obj.tabState.currentColor && this.element.id == this.obj.tabState.currentColor.swatchElement.id) {
        	       	this.obj.swapImage(this.element, 'On','On',null);
        	       }
                  this.obj._addSwatchEvents(this.element);  
                  
        	    }.bind({obj:this, element:spacer.parentNode}));
        	  
        	  // Add real source to images
        	  colorImage.swatchImage.image.src = images[1];
        	  colorImage.swatchOnImage.image.src = images[1].replace('.jpg', 'On.jpg');
        	  
			  this.colorImages[colorImage.id] = colorImage;			  
			}
		}
	}
	/**
	 * Method adds events to the parameter element passed into the method.
	 * Used for added events to Color swatches.
	 * @param - element - DOM element of the Color Swatch we want events on
	 * @memeber ColorTabController
	 */
	this._addSwatchEvents = function(element) {
		element.onmouseover = function() {galleryManager.doTabAction(this,'swapImage',['On','On'],arguments[0])}.bind(element);
		element.onmouseout  = function() {galleryManager.doTabAction(this,'swapImage',['On','Out'],arguments[0])}.bind(element);
		element.onclick     = function() {galleryManager.doTabAction(this,'switchColor',[],arguments[0])}.bind(element);
	}
	/**
	 * Method removes events to the parameter element passed into the method.
	 * Used for removing events to Color swatches.
	 * @param - element - DOM element of the Color Swatch we want events on
	 * @memeber ColorTabController
	 */
	this._removeSwatchEvents = function(element) {
		element.onmouseover = null;
		element.onmouseout  = null;
		element.onclick     = null;
	}  
	/**
	 * Method handles the swapping from On and Off states of the Color
	 * Swatches.
	 * @param Parent Element of the image we want to swap states
	 * @param State we want the elemetn to change too
	 * @param Action/ NOT IN USE
	 * @param Current Event.
	 * @memeber ColorTabController
	 */
	this.swapImage = function(listItem, state, action,e) {
		/**
        * Stop event bubble propagation
        */
	    e = (e) ? e : window.event;
	    if(e)  
	    	Event.stop(e); 
	    
	    listItem.firstChild.className = 'pgColorChipImage';
	    switch (action) {
		  		case 'Over':
		  			swapOver(listItem.firstChild, state);
		  			break;
		  		case 'On':
		  			swapOn(listItem.firstChild, state);
		  			break;
                case 'Out':
		  			swapOut(listItem.firstChild, state);
		  			break;
		  	}
		
	}
	/**
	 * Method switches out the large Color image and changes the description text.
	 * @param Id or object of the Color swatch that was clicked.
	 * @param Current Event.
	 * @memeber ColorTabController
	 */
	this.switchColor = function(id, e) {
		
		var listItem = $(id);
		var currentImage = this.colorImages[listItem.id];
		
		// Add Events back for previous on color
		if(this.tabState.currentColor) {
			this._addSwatchEvents(this.tabState.currentColor.swatchElement);
			this.swapImage(this.tabState.currentColor.swatchElement, 'On','Out',e);
		}
		
		// Remove events for current clicked color and set as current
		this.tabState.currentColor = currentImage;
		this._removeSwatchEvents(this.tabState.currentColor.swatchElement);
		
		var colorVehicleElement = $('pgColorVehicle' + this.galleryState.getSubNavKey());
		
		// Replace Loading image with real image if image is downloaded
		if(currentImage.swatchLargeImage.image.complete && currentImage.swatchLargeImage.image.width > 0) {
  	    	GalleryUtils.replaceImage(currentImage.swatchLargeImage.image,colorVehicleElement.firstChild);
  	    	this.swapImage(listItem, 'On','On',e);
		}
  	   	// Replace Loading image with real image once image is downloaded
  	   	else {
			GalleryUtils.buildLoadingElement($('pgColorVehicle' + this.galleryState.getSubNavKey()),774,400,GalleryManager.LARGE, 'pgLoadingColor');
  	     	currentImage.swatchLargeImage.setOnload(function() {
          		GalleryUtils.replaceImage(this.largeImage,colorVehicleElement.firstChild);
          			this.obj.swapImage(this.listItem, 'On','On',e);
          		}.bind({obj:this, largeImage: currentImage.swatchLargeImage.image, listItem:listItem}));
          	
          	this._cacheColorImage(currentImage); 
  	   	}
  	
       // Add Alt Text as description of large image
  	   var description = currentImage.colorDescription;
  	   $('pgColorDescription' + currentImage.id.replace(/[0-9]/g, '')).innerHTML = description;
	}
	/**
	 * Method will begin to cache all Large Color Images.
	 * @member ColorTabController
	 */
	this._cacheAllColorImages = function() {
		for(id in this.colorImages) {
			this._cacheColorImage(this.colorImages[id]);
		}
	}
	/**
	 * Method will begin to cache the swatchLargeImage of the passed in
	 * ColorImage.
	 * @param (ColorImage) ColorImage that will have the swatchLargeImage cached
	 * @member ColorTabController
	 */
	this._cacheColorImage = function(colorImage) {
		colorImage.swatchLargeImage.image.src = colorImage.swatchImage.image.src.replace('gth_', 'g_');
	}
    //Perform the Init function on instantiation
    this.init();
}
ColorTabController.TAB_KEY = 'COLOR';
ColorTabController.prototype.TAB_KEY = 'COLOR';

function ColorImage(id) {
	this.id = id;
	this.swatchImage = new GalleryImage();
	this.swatchOnImage = new GalleryImage();
	this.swatchLargeImage = new GalleryImage();		
	this.colorDescription;
	this.swatchElement;
	
	
	this.clearOnload = function() {
		this.swatchImage.clearOnload();	
		this.swatchOnImage.clearOnload();
		this.swatchLargeImage.clearOnload();	
	}
} 
// could be extended
function ColorState() {
	this.defaultSubNav = 'subNavExt';
	this.currentColor;
	
	this.getNavRoot = function() {
		return this.subNav.replace('subNav','');
		
	}		
}


//**********************************************
// Gallery Utilities
//**********************************************
function GalleryUtils() {}

GalleryUtils.buildLoadingElement = function(target, width, height, size, loadingClassName, imageSrc) {
  var div = document.createElement('DIV');
  var img = document.createElement('IMG');
  var className = (loadingClassName) ? loadingClassName : 'pgLoading';
    
    
  width = (document.all) ? width - 2 : width;  
  height = (document.all) ? height - 2 : height;
  
  div.style.width = width + 'px';
  div.style.height = height + 'px';

  // center the image
  img.style.marginTop = ( ( height - 50 ) / 2) + 'px'; 
  
  if(size == GalleryManager.LARGE) {
    img.src = imageSrc || galleryManager.loadingImageLarge.src;
    div.className = className + 'Large'; 
  }
  else {
    img.src = imageSrc || galleryManager.loadingImageSmall.src;
    div.className = className + 'Small';
  }
    
  div.appendChild(img);

  target.removeChild(target.firstChild);
  target.appendChild(div);		
}
GalleryUtils.replaceImage = function(imageObject,currentDom) {
  
	if(!currentDom) {
		return
	}
	if(currentDom.nodeName == 'IMG') {
   		currentDom.style.background = "url('" + imageObject.src + "') #000000 no-repeat";
   		currentDom.src = imageObject.src;
	}
	//CHANGE THIS SECTION BACK TO OLD METHOD. BUT LEAVE IF BLOCK IN FOR IMAGES
	else {
	  	var imageDom = document.createElement('IMG');
  		imageDom.src = imageObject.src;
    	currentDom.parentNode.replaceChild(imageDom,currentDom);
	/*	
	  imageDom.style.display = 'none';
	  currentDom.parentNode.insertBefore(imageDom, currentDom);
	  currentDom.style.display = 'none';
	  imageDom.style.display = 'inline';
	  currentDom.parentNode.removeChild(currentDom);
	*/
	}
}
GalleryUtils.buildFlashMovie = function(destination, params) {
	 	
		var objectCall = 'AC_FL_RunContent(~params~);';
		var objectParams = '';
		
		for(param in params) {
			objectParams += "'" + param + "',";
			objectParams += "'" + params[param] + "',"
		}
		objectParams += "'" + destination + "'";

		objectCall = objectCall.replace('~params~', objectParams);
		
		eval(objectCall);
}
 
GalleryUtils.buildParamters = function(paramDivs) {
	var params = new Object();
	for(var i=0; i<paramDivs.length; i++) {
		var key = paramDivs[i].getAttribute('NAME');
		var value = paramDivs[i].innerHTML;	 			
		params[key] = value;
	}
  	return params;
}	

GalleryUtils.buildAjaxUrl = function(urlPieces) {
	urlPieces.push('?random=' + Math.random());
	return urlPieces.join('');
}  
/**
 * GallaryImage is used to wrap the normal Image object 
 * and call a intervalCallBack when this.image.onload is called and the 
 * image has not been fully downloaded (IE).
 */
function GalleryImage() {
	this.image = new Image();
	this.intervalKey;
	
	this.setOnload = function(func) {
		this.image.onload = function() {
			if(this.image.complete) {
				func();
			}
			else {
				this.intervalKey = setInterval(function(){this.intervalCallback(func)}.bind(this),500);		
			}
		}.bind(this)		
	}
	this.intervalCallback = function(func) {
	   if(this.image.complete) {
	   	  setTimeout(func,2500);
	   	  clearInterval(this.intervalKey);
	   }	
	}
	this.clearOnload = function() {
		this.image.onload = function() {}
	}
}

/* onload events */
onPageLoadEvents.addAction(GalleryManager.launchGalleryOnload);
//vent.observe(window, 'load', GalleryManager.launchGalleryOnload);

	var Demo = Class.create();

Object.extend(Demo.prototype, {
	initialize: function(element,id,groupId, name,path) {
		this.element = element;
		this.id = id;
		this.groupId = groupId;
		this.name = name;
		this.path = path;
		
		this.buttonElement;
		this.description;
		this.params;
		this.movie;
		this.type;
		this.meta;
	},
	addParams: function(params) {
		this.params = params;
	},
	addMeta: function(meta) {
		this.type = meta['type'];
		this.meta = meta;		
	},
	getParam: function(name) {
		return (this.params[name]) ? this.params[name] : '';
	},
	getMeta: function(name) {
		return (this.meta[name]) ? this.meta[name] : '';
	}
});

var DemoController = Class.create();
Object.extend(DemoController.prototype, {
	
	
	initialize: function(){
		this.demoContainer = 'demoContainer';
		this.demoGroups = new Object();
		this.currentGroup;
		this.currentDemo;
		this.onloadDemo;

		this.ajaxQueue;
		this.viewPointMethods;
		// search dom for demos/tutorials/videos and prepre anything that needs to be.
		this._findAllDemos();
		this._launchDemoOnload();
		
		this.backdrop;
	},
	
	openDemo: function(groupId, demoId) {

	
		if($('popupOverlay')) {
			hidePW();	// hide popup windows from glossary terms.
		}
		
		if(!PAGE_LOAD) {
	 		return;
	 	}

		this.currentGroup = this._getDemoGroup(groupId);
		
		if(!$(this.demoContainer )) {
			this._initializeDemo(demoId);
		}
		else {
			this._prepareDemoTemplate(demoId);
		}

		// Make sure we are at the top of the page
		scroll(0,0);
					
	},
	
	closeDemos: function() {
  	  	this.currentDemo = null;
  	  	this.currentGroup = null;
  	  	this._hideDemos();
	},
	
	showDemo: function(demoId) {
		this._playDemo(demoId);
	},
	playCurrentDemo: function() {
		
		this._playDemo(this.currentDemo.id)
	},
	playNextMovie: function() {
		var index;
		
		// If we only have one demo, play it again
		if(this.currentGroup.length < 2) {
			this.playCurrentDemo();
			return;
		}
		// Loop through and find where we are in the stack
		for(var i=0; i<this.currentGroup.length; i++) {
			var demo = this.currentGroup[i];
			if(demo.id == this.currentDemo.id) {
				index = i;
				break;
			}	
		}
		// If we are not on the last demo, play the next one
		if( (index+2) <=  this.currentGroup.length) {
			this.showDemo(this.currentGroup[index+1].id);
		}
		else {
			this.showDemo(this.currentGroup[0].id);
		}
	},
	_playDemo: function(demoId) {
		
		this.currentDemo = this._getDemo(demoId);
		// Retrieve and Build Demo via ajax call
		if(!this.currentDemo.params) {
			this._getDemoAjax(this.currentDemo);
		}
		//Prepare and Build demo since we already have the needed data
		else {
			this._prepareDemo(this.currentDemo);	
		}
	},
	_configureForViewPoint: function(movie) {
		if(movie) {
			vmp = movie;
		 	this.viewPointMethods = new Object();
		 	this.viewPointMethods.movie = movie;
		 	movie.Execute('ForceHostLayering(1)');
		 	Object.extend(this.viewPointMethods, ViewPointMethodsDemo.prototype);
		 	
		 	if(hasObject(window, 'ViewPointMethodsDemo' + this.modelId)) {
		 		Object.extend(this.viewPointMethods, eval(' new ViewPointMethodsDemo' + this.modelId + '()') );
			}
		}
	},
	 
	processViewPointAction: function(ref, func, args) {
		 if(this.viewPointMethods && this.viewPointMethods[func]) {
		   if(!args) 
		 	args = $A();
		   this.viewPointMethods[func].apply(this.viewPointMethods, args);
		  }
	 }, 
	
	_initializeDemo: function(demoId) {
		this._initializeAjax(demoId);
	},
	
	_getAjaxQueue: function() {
		return (this.ajaxQueue) ? this.ajaxQueue : new Ajax.Queue(Ajax.Queue.Single, false);
	},
	
	_initializeAjax: function(demoId) {
		var ajaxQueue = this._getAjaxQueue();
		ajaxQueue.addAction(
			new Ajax.Updater(
			    {success: document.body, failure: null }, 
			    GalleryUtils.buildAjaxUrl(['/lexus-share/demos/demo_template.html']), 
			    {
				    method: 'GET',
				    wait: true,
				    insertion: Insertion.Bottom,	
				    onComplete: function() {this.controller._prepareDemoTemplate(this.demoId)}.bind({controller: this, demoId: demoId})
			    }
			)
		);
		ajaxQueue.start();
	},
	
	_showDemos: function() {
		hideAllFlashInSafari();
		this._showWrapper();	
		$(this.demoContainer).style.display = 'block';
		
		// Mac browsers fix - Mac browsers seem to set visiblilty to hidden
		// when we close the demo and when we try to relaunch, no movie
		// is visible
		$('demoMovie').style.visibility = "visible";
		
	},
	
	_hideDemos: function() {
		$(this.demoContainer).style.display = 'none';
		$('demoMovie').innerHTML = null;
		this._hideWrapper();
		hidePW();	// hide popup windows from glossary terms.
		showAllFlashInSafari();
	},
	_showWrapper: function() {
		if(!this.backdrop) {
			this.backdrop = new Backdrop('demoWrapper','galleryWrap');
			this.backdrop.observe('click', this.closeDemos.bind(this), false);
		}
		this.backdrop.enable();
	},
	_hideWrapper: function() {
		  if(this.backdrop) {
			this.backdrop.disable();
		}
	},
	_prepareDemoTemplate: function(demoId) {
		if(this.demoContainer) {
			// Adjust left header image
			this._addMoviesToButtons();
			this._updateModelImage();
			this.showDemo(demoId);	
		}
	},
	
	_addMoviesToButtons: function() {
		var buttonContainer = $('demoButtonsContainer');
		emptyElement(buttonContainer);
		for(var i=0; i<this.currentGroup.length; i++) {
			
			var demo = this.currentGroup[i];
			var buttonDiv = document.createElement('DIV');
			var middleDiv = document.createElement('DIV');
			var textDiv   = document.createElement('SPAN');
			
			demo.buttonElement = buttonDiv;
			buttonDiv.className = 'demoButtonOff demoButton';
			
			middleDiv.className = 'demoValignMiddle';
			textDiv.innerHTML = demo.name;
			textDiv.className = 'demoButtonText';
			
			middleDiv.appendChild(textDiv);
			buttonDiv.appendChild(middleDiv);
			buttonContainer.appendChild(buttonDiv);
			
			this._addEventsToButton(buttonDiv,demo.id);
		}
	},
	_getDemoGroup: function(id) {
		return this.demoGroups[id];
	},
	
	_getDemo: function(id) {
		
		for(var i=0; i<this.currentGroup.length; i++) {
			if(this.currentGroup[i].id == id) {
				return this.currentGroup[i];
			}
		}
	},
	
	_getDemoAjax: function(demo) {
		
		var ajaxQueue = this._getAjaxQueue();
		ajaxQueue.addAction(
				new Ajax.Request(
			      GalleryUtils.buildAjaxUrl([demo.path]), 
			    {
				    method: 'GET',
				    wait:true,
				    onSuccess: 	this._callbackDemo.bind(this)
			    }
			)
		);
		ajaxQueue.start();
	},
	
	_callbackDemo: function() {

		var xml = arguments[0].responseXML.getElementsByTagName('lexus')[0];
		var data = this._getData(xml);
		var demo = this._getDemo(data.meta['demoId']);
		
		demo.addMeta(data.meta);
		demo.addParams(data.params);
		
		this._prepareDemo(demo);
	},
	
	_prepareDemo: function(demo) {
		this._adjustMargin(demo.getParam('width'), demo.getParam('height'));
		this._updateDescription(demo.getMeta('description'));
		this._updateTitle(demo.getMeta('title'));
		this._updateDisclaimers(demo.getMeta('disclaimers'));
		this._updateSoundControl(demo.getMeta('sound'));
		this._updateButtonsState(demo);
		this._updatePluginLink(demo.type);
		this._showDemos();
		this._setupScroll();
		
		//Build Movie based on type
		switch (demo.type) {
			case 'flash':
				this._buildFlashDemo(demo);
				break;
				
			case 'viewpoint':
				this._buildViewPointDemo(demo);				
				break;

			case 'mediaplayer':
				this._buildMediaPlayerDemo(demo);				
				break;

			default:
				break;
		}
	},
	_updatePluginLink: function(type) {
		$('demoPlugin').href = MovieUtils.getPluginDownloadLink(type);
	},
	_updateModelImage: function() {
		$('demoHeaderSection').src = DemoController.ROOT_IMAGES + 'vc_' + MODEL_ID.toLowerCase() + 'Head.gif';
	},
	
	_updateTypeImage: function(type) {
		//$('demoHeaderType').src = DemoController.ROOT_IMAGES + type + '.gif';
	},
	
	_updateButtonsState: function(demo) {
		var currentButton = (demo) ? demo.buttonElement : null;
		var buttons = document.getElementsByClassName('demoButton', 'demoButtonsContainer', 'DIV');
		
		for(var i=0; i<buttons.length; i++) {
			if(currentButton == buttons[i]) {
				buttons[i].className = 'demoButton demoButtonOn';
			}
			else {
				buttons[i].className = 'demoButton demoButtonOff';
			}
		}
	},
	
	_adjustMargin: function(width,height) {
		// Need to center movie vertically. Height for demoMovieContainer is 360. 
		var marginLeft = ( 642 - width*1 ) / 2;
		var marginTop = ( 360 - height*1 ) / 2;
		
		$('demoMovie').style.marginLeft= Math.round(marginLeft) + 'px';
		$('demoMovie').style.marginTop = Math.round(marginTop) + 'px';
	},
	
	_updateDescription: function(description) {
		$('demoDescription').innerHTML = description;
	},
	
	_updateTitle: function(title) {
		$('demoTitle').innerHTML = title;
	},
	
	_updateDisclaimers: function(disclaimers) {
		var disclaimerContainer = $('demoDisclaimerContainer');
		
		while(disclaimerContainer.childNodes.length > 0) {
			disclaimerContainer.removeChild(disclaimerContainer .firstChild);
		}
		
		for(var i=0; i<disclaimers.length; i++) {
			var disclaimerElement = document.createElement('DIV');
			disclaimerElement.className = 'demoDisclaimer'
			disclaimerElement.innerHTML = disclaimers[i];
			
			disclaimerContainer .appendChild(disclaimerElement);
		}
	},
	
	_updateSoundControl: function(sound) {
		
		switch (sound) {
			case 'external':				
				var demoSound = $('demoSound');
				var demoSoundImage = ($NL(demoSound.childNodes)).firstElement();
				demoSound.style.visibility = 'visible';
				
				Event.observe(demoSoundImage, 'click', function() {demoController.toggleSound(this)}.bind(demoSoundImage));
				break;
			 
			case 'internal':
			default:
				$('demoSound').style.visibility = 'hidden';
				break;
		}

	},
	
	toggleSound: function(soundImage){
		
		if(soundImage.src.indexOf('On.gif') > -1) {
			soundImage.src = soundImage.src.replace('On.gif', 'Off.gif');	
		}
		else {
			soundImage.src = soundImage.src.replace('Off.gif', 'On.gif');
		}
		
		// Need to add logic to broker sound request to current movie
	},
	
	_buildFlashDemo: function(demo) {
		// Add default parameters
		demo.params['codebase'] = 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0';
		demo.params['id'] = 'flashDemo';
		demo.params['allowScriptAccess'] = 'sameDomain';
		demo.params['quality'] = 'height';
		demo.params['bgcolor'] = '#FFFFFF';
		demo.params['play'] = 'true';
		
		demo.params['loop'] = 'true';
		demo.params['scale'] = 'showall';
		demo.params['devicefont'] = 'false';
		demo.params['menu'] = 'true';
		demo.params['salign'] = '';
		demo.params['wmode'] = 'transparent';
		
		MovieUtils.buildFlashMovie('demoMovie', demo.params, true);	
	},
	
	_buildViewPointDemo: function(demo) {
		
		// Add default parameters
		demo.params['broadcast'] = '/lexus-share/vp/bkey.mtx';
		demo.params['alt'] = 'popUp';
		
		demo.movie = MovieUtils.buildViewPointMovie('demoMovie', demo.params, true);
		this._configureForViewPoint(demo.movie);
	},
	
	_buildMediaPlayerDemo: function(demo) {
		
		MovieUtils.buildMediaPlayerMovie('demoMovie', demo.params, true);
	},

	_getData: function(xml) {
		var meta = new Object();
		var params = new Object();
		var disclaimers = new Array();
		var metaNode = xml.getElementsByTagName('meta')[0];
		var movieNode = xml.getElementsByTagName('movie')[0];
		
		// Get Movie parameters
		var paramElements = movieNode.getElementsByTagName('param');
		for(var i=0; i<paramElements.length; i++) {
			var element = paramElements[i];
			var name = element.getAttribute('name');
			
			params[name] = (element.firstChild) ? element.firstChild.nodeValue : "";
		}
		// Get Movie Meta Data
		var metaElements = metaNode.getElementsByTagName('param');
		for(var i=0; i<metaElements.length; i++) {
			var element = metaElements[i];
			var name = element.getAttribute('name');
			
			meta[name] = (element.firstChild) ? element.firstChild.nodeValue : "";
		}
		
		var disclaimersElements = metaNode.getElementsByTagName('disclaimer');
		
		for(var i=0; i<disclaimersElements.length; i++) {
			var element = disclaimersElements[i];
			var name = element.getAttribute('name');
			
			disclaimers.push(element.firstChild.nodeValue);
		}
		meta['disclaimers'] = disclaimers;
		return {params: params, meta: meta};
	},
	
	/**
	 * Method scrubs the DOM for all demos on the current page.
	 */
	_findAllDemos: function() {
		var groupElements = document.getElementsByClassName('demoGroup', null, 'DIV');
		var onloadDemoId = Address.getParameters()['demo'];
		// Loop through each Demo Group Found
		for(var x=0; x<groupElements.length; x++) {
			var groupElement = groupElements[x];
			var group = new Array();
			var groupId = x;
			var demoElements = document.getElementsByClassName('demoTarget',groupElement, 'DIV');
			
			// Loop through each Demo found within the current Demo Group
			for(var i=0; i<demoElements.length; i++) {
				var demoElement = demoElements[i];
				var demoId = demoElement.getAttribute('id').replace(new RegExp("-[0-9]$", "g"), '');
				var demoName = demoElement.getAttribute('name');
				var demoPath = [DemoController.ROOT_PATH,MODEL_ID,'/',demoId,'.xml'].join(''); 
			
				var demo = new Demo(demoElement,demoId, groupId,demoName,demoPath);			
				this._addEventsToDemo(demo.element, groupId, demo.id);
				
				this._addDemoToGroup(group, demo);
				
				if(demo.id == onloadDemoId) {
					this.onloadDemo = demo;
				}
			}
			this.demoGroups[groupId] = group;
		}
	},
	_addDemoToGroup: function(group, demo) {
		var found = false;
		for(var i=0; i<group.length; i++) {
			if(group[i].id == demo.id) {
				found = true;
				break;
			}
		}
		if(!found) {
			group.push(demo);
		}
	},
	_launchDemoOnload: function() {
		if(this.onloadDemo) {
			this.openDemo(this.onloadDemo.groupId, this.onloadDemo.id);
		}
	},
	/**
	 * Method adds onclick event to the demo element.
	 * @param demo {DEMO} - Object containing all info about the demo.
	 */
	_addEventsToDemo: function(element, groupId, demoId) {
		Event.observe(element, 'click', function() {demoController.openDemo(this.groupId, this.demoId);return false;}.bind({groupId: groupId, demoId:demoId}));
	},
	
	_addEventsToButton: function(element, demoId) {
		Event.observe(element, 'click', function() {demoController.showDemo(this);return false;}.bind(demoId));
	},
	
	_setupScroll: function() {
		var boundry = Dom.getBoundries('demoFooterContent');
		
		// We only show the scroll bar if we need it.
		if(boundry.height > 150) { 
			$('demoScrollbar').style.display = 'block';
			var scrollObj = new dw_scrollObj('demoFooterContentContainer', 'demoFooterContent', null);
		
			// arguments: dragBar id, track id, axis ("v" or "h"), x offset, y offset
			// (x/y offsets of dragBar in track)
			scrollObj.setUpScrollbar("demoDragBar", "demoTrack", "v", 0, 0);
		}
		else {
			$('demoScrollbar').style.display = 'none';
		}
    /*
		var scrollObj = new dw_scrollObj('demoFooterContentContainer', 'demoFooterContent', null);
	
		// arguments: dragBar id, track id, axis ("v" or "h"), x offset, y offset
		// (x/y offsets of dragBar in track)
		scrollObj.setUpScrollbar("demoDragBar", "demoTrack", "v", 0, 0);
	*/
	}
	
});	

var ViewPointMethodsDemo = Class.create();
Object.extend(ViewPointMethodsDemo.prototype, {
	initialize: {},
	change_copy: function(imgsrc) {
		Debug.debug('change_copy');
		// TODO - will add logic to update $('demoDisclaimerDescription')
	},
	
	disclaimer: function() {
		Debug.debug('disclaimer');
		// Nothing yet
	}
});
var demoController;
DemoController.buildDemoController = function() {
	demoController = new DemoController();
}
DemoController.ROOT_PATH = '/lexus-share/demos/';
DemoController.ROOT_IMAGES = '/lexus-share/images/demos/';
//vent.observe(window, 'load',DemoController.buildDemoController);
onPageLoadEvents.addAction(DemoController.buildDemoController);
/***************************************************************
 * Viewpoint Methods that have to be under window.xxxxxx
 ***************************************************************/
var vmp;
function change_copy() {
	
	demoController.processViewPointAction(null,'change_copy');
}
function disclaimer() {
	
	demoController.processViewPointAction(null,'disclaimer');
}

function playNextMovie() {
	Debug.debug('playNextMovie')
	demoController.playNextMovie();
}
function vwpt_callout() {
	demoController.playNextMovie();
	
}



	function VidPlayer() {
	// Constructor
	var id;													// id of the video to display
	var curId = null;										// id of the video currently loaded or last played
	var xmlPath = null;										// path of the xml file that holds data about video
	var wrapperId = "vidWrapper";							// id to assign to the wrapper of the VidPlayer
	var containerId = "vidContainer";						// id to assign to the container of the VidPlayer
	var linkKey = "vidLink";								// name of the class that all links to VidPlayer will have
	var rootPath= '/lexus-share/demos/';					// root of the path where vid file data and vid files
	var metaInfo = Object();								// meta information for the movie file
	var params = Object();									// parameters of the movie (ie size, type, etc);
	var ajaxQueue = new Ajax.Queue(Ajax.Queue.FIFO, false);	// ajaxQueue object to keep track of ajax requests
	var backdrop;
	
	// loops through the page and finds all a tags with 'linkKey' then adds an event to them.
	this.findVidLinks = function() {
		//find all 'a' tags with className = linkKey
		var elements = document.getElementsByClassName(linkKey, null, 'a');

		// loop through all found 'a' tags and apply onClick event to launch vidBox to it
		if(elements) {
			for(var x=0, y=elements.length; x < y; x++) {
				var element = elements[x];
		
				element.onclick = function() {
					vidPlay.openVidBox(this.id);
				}
			}
		}
	};
		
	// open video box
	this.openVidBox = function(newId) {		
		
		if(!PAGE_LOAD) {
	 		return;
	 	}

		id = newId;
		if(ajaxQueue === null) {
			ajaxQueue = new Ajax.Queue(Ajax.Queue.FIFO, false);
		}
		
		if(!$(containerId)) {
			this.buildInterface();	// build interface if not already built
		}
				
		if(id != curId) {
			this.getVidInfo();		// if data isn't the current data loaded, load and parse new data
			curId = id;
		} else {
			this.buildPlayer();
		}
		
		// Make sure we are at the top of the page
		scroll(0,0);
		
	};
	
	// close video box	
	this.closeVidBox = function() {
		ajaxQueue = null;			// unset ajaxQueue so no further request go through.
		
		this.closeVidLegalDisclaimer();
		// if wrapper and container are built hide them
		if($(containerId)) {
			$(containerId).style.display = 'none';
			
			$('vidMovie').removeChild($('vidMovie').firstChild);
		}
		this.hideWrapper();
	};
	
	
	// display video box
	this.showVidBox = function() {
		if($(wrapperId) && $(containerId)) {
			this.showWrapper();
			$(containerId).style.display = 'block';
		}
	};
	this.showWrapper = function() {
		if(!this.backdrop) {
			this.backdrop = new Backdrop(wrapperId,'galleryWrap');
			this.backdrop.observe('click', this.closeVidBox.bind(this), false);
		}
		this.backdrop.enable();
		
	};
	this.hideWrapper = function() {
		if(this.backdrop) {
			this.backdrop.disable();
		}
	};
	// builds interface
	this.buildInterface = function() {	

		// if wrapper doesn't exist, build it
		this.showWrapper();
		
		// get inteface
		ajaxQueue.addAction(new Ajax.Updater({success:document.body,failure:null},GalleryUtils.buildAjaxUrl(['/lexus-share/demos/vid_template.html']),{method:'GET', insertion:Insertion.Bottom}));
		ajaxQueue.start();
	};
	 
	// retrieves information about the video
	this.getVidInfo = function() {	
		// bind 'this' to populateVidInfo or else any 'this' methods calleds in populateVidInfo will not run.
		ajaxQueue.addAction(new Ajax.Request(GalleryUtils.buildAjaxUrl([rootPath+MODEL_ID+'/'+id+'.xml']),{method: 'GET', onComplete: this.populateVidInfo.bind(this)}));
		ajaxQueue.start();
	};
	
	// parse xml and place into video box
	this.populateVidInfo = function(xml) {
		this.metaInfo = Object();  // meta information for the movie file
		this.params = Object();	
		xml = xml.responseXML.getElementsByTagName('lexus')[0];
		var metaNode = xml.getElementsByTagName('meta')[0];
		var movieNode = xml.getElementsByTagName('movie')[0];	
				
		// parse all meta nodes
		var metaElements = metaNode.getElementsByTagName('param');
		for(var x=0, y=metaElements.length; x<y; x++) {
			if(metaElements[x].nodeType == 1) {
				this.metaInfo[metaElements[x].getAttribute('name')] = metaElements[x].firstChild.nodeValue;
			}
		}
		// parse all param nodes	
		var paramElements = movieNode.getElementsByTagName('param');	
		for(var i=0, j=paramElements.length; i<j; i++) {
			if(paramElements[i].nodeType == 1) {	
				this.params[paramElements[i].getAttribute('name')] = paramElements[i].firstChild.nodeValue;
			}
		}
		// set width to width param so that div still aligns to the center of the page.
		$(containerId).style.width = (parseInt(this.params.width, 0)+10)+"px";

		// if ie set class to ie so div aligns to the center of the page
		if(document.all) {
			$(containerId).className = "ie";
		}
		
		var disclaimersElements = metaNode.getElementsByTagName('disclaimer');
		var disclaimers = new Array();
		for(var i=0; i<disclaimersElements.length; i++) {
			var element = disclaimersElements[i];
			var name = element.getAttribute('name');
			
			disclaimers.push(element.firstChild.nodeValue);
		}
		this.metaInfo['disclaimers'] = disclaimers;
		
		// update movie info in display box
		$('vidTitle').innerHTML = this.metaInfo.title;
		$('vidDescription').innerHTML = this.metaInfo.description;
		this.buildPlayer();
	};
	
	// build flash version of video player
	this.buildFlashDemo = function() {

		// Add default parameters
		this.params.codebase = 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0';
		this.params.id = 'flashDemo';
		this.params.allowScriptAccess = 'sameDomain';
		this.params.quality = 'height';
		this.params.bgcolor = '#FFFFFF';
		this.params.play = 'true';
		this.params.loop = 'true';
		this.params.scale = 'showall';
		this.params.devicefont = 'false';
		this.params.menu = 'true';
		this.params.salign = '';
		
		MovieUtils.buildFlashMovie('vidMovie', this.params, true);	
	};
	
	// build view point version of demo
	this.buildViewPointDemo = function() {
		// Not Implemented  
	};
	
	// build media player version of demo
	this.buildMediaPlayerDemo = function() {
		MovieUtils.buildMediaPlayerMovie('vidMovie', this.params, true);
	};
	
	// find version to build then build it
	this.buildPlayer = function() {
		switch (this.metaInfo.type) {
			case 'flash':
				this.buildFlashDemo();
				break;
			case 'mediaplayer':
				this.buildMediaPlayerDemo();				
				break;

			default:
				break;
		}
		this._updatePluginLink(this.metaInfo.type);
		this._updateLegalDisclaimerLink();
		this.showVidBox();
	};
	this.openVidLegalDisclaimer = function() {
		this._getVidLegalDisclaimer();
		$('vidMovie').style.visibility = 'hidden';	
	}
	this._getVidLegalDisclaimer = function() {
		var updater = new Ajax.Updater(
							{success:document.body,failure:null},
							GalleryUtils.buildAjaxUrl(['/lexus-share/demos/vid_legal_disclaimers_template.html']),
							{
								onComplete:this._prepareVidLegalDisclaimer.bind(this), 
								method:'GET', 
								insertion:Insertion.Bottom
							})
		ajaxQueue.addAction(updater);
	};
	this.closeVidLegalDisclaimer = function() {
		if($('videoLegalDisclaimerContainer')) {
  			$('videoLegalDisclaimerContainer').parentNode.removeChild($('videoLegalDisclaimerContainer'));
  			$('vidMovie').style.visibility = 'visible';	
  		}
	};
	this._prepareVidLegalDisclaimer = function() {
		// Add current video's disclaimers
		if($('videoLegalDisclaimerContainer')) {
  			var disclaimers = this.metaInfo['disclaimers'];
  			var disclaimerContainer = $('legalDisclaimerHolder');
  			for(var i=0; i<disclaimers.length; i++) {
				var disclaimerElement = document.createElement('DIV');
				disclaimerElement.className = 'demoDisclaimer'
				disclaimerElement.innerHTML = disclaimers[i];
			
				disclaimerContainer.appendChild(disclaimerElement);
			}
  		}
  		// Add back event to back button
  		Event.observe('vidLegalBack', 'click', this.closeVidLegalDisclaimer.bind(this));
	};
	this._updatePluginLink = function(type) {
		$('demoPlugin').href = MovieUtils.getPluginDownloadLink(type);
	};
	this._updateLegalDisclaimerLink = function() {
		$('demoLegalDisclaimer').onclick = this.openVidLegalDisclaimer.bind(this);
		
	};

}

		
var vidPlay = new VidPlayer();

	/**
 * FormValidator
 * A class to manage form validation.  Create an instance of this object
 * by passing in the form element, or id of the form element you want to 
 * have validated.
 */
var FormValidator = Class.create();

Object.extend(FormValidator.prototype, {

	/**
	 * Constructor
	 */
	initialize: function(form_element){
		
		var form_element;
		var validators;
		
		this.form_element = $(form_element);
		this.validators = [];
		
		/**
		 * Extend the form element to make it easier to apply
		 * the validation within HTML.
		 */
		Object.extend(this.form_element, {
			validateAndSubmit: function(){
				if(this.validate())
					this.form_element.submit();
			}.bind(this)
		});

		/**
		 * Insert triggers for form handling
		 */
		
		Event.observe(this.form_element, 'submit', this.validate.bindAsEventListener(this), true);
		
	},
	
	/**
	 * This does most of the work.  You will probably not need to call this directly
	 * as this object will (semi)automatically attach itself to the form and intercept
	 * submit calls.
	 */
	validate: function(event){

		var errors = this.validators.inject([], function(errors, v){
			/**
			 * This line looks a bit cryptic.  What I'm doing here is
			 * a calling the validation function (v.func) and passing 
			 * in the value of the element ($F(v.element)) as the first
			 * parameter, and then the supplied options (v.options) after
			 * that.  If the function returns false, I add that validation
			 * object to the list of errors.
			 */
			if(!v.func.apply(this, [$F(v.element)].concat(v.options)))
				errors.push(v);
			
			return errors;
		});
		
		Debug.log('Checking errors: ', errors);
		
		if(errors.length) {
			Debug.log("Validation failed", errors);
			if(event)
				Event.stop(event);
			this.handleErrors(errors);
			return false;
		}
		else {
			Debug.log('Validation successful');
			return true;
		}

	},
	
	/**
	 * This function recieves an array of failed validation tasks
	 * and will process them accordingly.
	 */
	handleErrors: function(errors){
		//What do I do?
	},
	
	/**
	 * This is how you will by applying your validation rules.
	 * @param element		the form element to be validated or its id
	 * @param validation_func	a function that will validate the data.  There are several static 
	 *				validation function at the end of this file, but you can
	 *				also supply your own.
	 * @param message		the error message to be diplayed if the validaion fails
	 * @param options		an array of parameters to be passed to the validation function
	 */
	addValidator: function(element, validation_func, message, options){
		this.validators.push({element: $(element), func: validation_func, err_msg: message, options: options});
	},
	
	/**
	 * This function behaves the same as addValidator except you need to pass it
	 * the name of the field instead of the element object or id
	 */
	addValidatorByName: function(field_name, validation_func, message, options){

		if(document.all)
			search_elements = $NL(this.form_element.all);
		else
			search_elements = $NL(this.form_element.getElementsByTagName("*"));

		search_elements.each(function(e){
			if(e.name == field_name){
				this.addValidator(e, validation_func, message, options);
			}
		}.bind(this));
	}
});


/** 
 * Validate against a regular expression 
 */
FormValidator.validateRegExp = function(value, exp){
	//Debug.log('validateRegExp', value, exp, value.match(typeof exp == 'RegExp' ? exp : new RegExp(exp)), (typeof exp == 'RegExp' ? exp : new RegExp(exp)));
	return value.match(typeof exp == 'RegExp' ? exp : new RegExp(exp));
};

/** 
 * Validate that the value is a number 
 */	
FormValidator.validateNumeric = function(value){
	return value.match(new RegExp('^-?([0-9]+|[0-9]*\.[0-9]+)$'));
};

/** 
 * Validate the length of the value is within a given range. 
 * By supplying only one length, you can validate that the length
 * is exactly that length.
 */

FormValidator.validateLength = function(value, min_len, max_len){
	if(min_len && max_len){
		return (value.length >= min_len && value.length <= max_len);
	}
	else{
		return (value.length == min_len);
	}
};
	/**
 * @fileoverview This is it help proxy the different browsers console behaviors.
 * This file SHOULD BE REMOVED BEFORE the site is live
 */
function Debug() {}

Debug.log = function (message, objects) {
	if(document.all) {
		if(window.Logger) 
			Logger.log( message)
		
		return;
	}
	else if (navigator.userAgent.toLowerCase().indexOf('safari') > -1)		
		window.console.log("INFO: " + message);
	else if(window.console)
		console.log.apply(window, arguments);	
}
Debug.debug = function (message, objects) {
	if(document.all) {
		if(window.Logger) 
			Logger.debug(message)
		
		return;
	}
	else if (navigator.userAgent.toLowerCase().indexOf('safari') > -1)		
		window.console.log("DEBUG: " + message);
	else if(window.console)
		console.debug.apply(window, arguments);
}
Debug.warn = function (message, objects) {
	if(document.all) {
		if(window.Logger) 
			Logger.warn(message)
		return;
	}
	else if (navigator.userAgent.toLowerCase().indexOf('safari') > -1)		
		window.console.log("WARNING: " + message);
	else if(window.console)
		console.warn.apply(window, arguments)
}
Debug.error = function (message, objects) {
	if(document.all) {
		if(window.Logger) 
			Logger.error(message)
		return;
	}
	else if (navigator.userAgent.toLowerCase().indexOf('safari') > -1)		
		window.console.log("ERROR: " + message);
	else if(window.console)
		console.error.apply(window, arguments);
}	
	/* Gallery Functions */
function imgPreload(imgName) {
	var imgVar;
	imgVar = new Image();
	imgVar.src = imgName;
	return imgVar;
}

var curIdx = 0;

/* ********************************************************************************
   Photos
   ******************************************************************************** */
// Reset Thumbnails
function photoClearThumbs() {
	for(i=0; i < photos.length; i++) {
		var a = 'thumb' + i;
		document.getElementById(a).src = photos[i].thumb.src;
	}
}

// Thumbnail Over state
function photoTnOvr(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = photos[idx].thumb_ovr.src;
	}
}

// Thumbnail Off State
function photoTnOff(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = photos[idx].thumb.src;
	}
}

// Photo Activator
function viewPhoto(idx) {
	photoClearThumbs();
	var a = 'thumb' + idx;
	document.getElementById(a).src = photos[idx].thumb_on.src;
	document.getElementById('mainPhoto').src = photos[idx].image;
	curIdx = idx;
	self.focus();
}

// Thumbnail Over state
function photoTnOvrPopUp(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = photos[idx].thumb_ovr.src;
		document.getElementById('colorTitle').innerHTML = photos[idx].title;
	}
}

// Thumbnail Off State
function photoTnOffPopUp(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = photos[idx].thumb.src;
		document.getElementById('colorTitle').innerHTML = photos[curIdx].title;
	}
}

function viewPhotoPopUp(idx) {
	photoClearThumbs();
	var a = 'thumb' + idx;
	document.getElementById(a).src = photos[idx].thumb_on.src;
	document.getElementById('mainPhoto').src = photos[idx].image;
	document.getElementById('colorTitle').innerHTML = photos[idx].title;
	curIdx = idx;
	self.focus();
}



// Launch Gallery
function launchGallery() {
	height = 466;
	if (gModelName == "es"){
		height = 520;
	}
	var photoPopupURL = filenamePrefix + 'gallery_' + whereYouAt + '_photos_popup.html?photoNum=' + curIdx;
	popup(photoPopupURL, "zoom", 769, height, "scrollbars=no,menubar=no");
}

/* ********************************************************************************
   Colors
   ******************************************************************************** */
// Reset Thumbnails
function colorClearThumbs() {
	for(i=0; i < colors.length; i++) { 
		var a = 'thumb' + i;
		document.getElementById(a).src = colors[i].thumb.src;
	}
}

// Thumbnail Over state for Color
function colorTnOvr(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = colors[idx].thumb_ovr.src;
		document.getElementById('colorTitle').innerHTML = colors[idx].title;
	}
}

// Thumbnail Off State for Color
function colorTnOff(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = colors[idx].thumb.src;
		document.getElementById('colorTitle').innerHTML = colors[curIdx].title;
	}
}

// Photo Activator
function viewColor(idx) {
	colorClearThumbs();
	var a = 'thumb' + idx;
	document.getElementById(a).src = colors[idx].thumb_on.src;
	document.getElementById('mainPhoto').src = colors[idx].image;
	document.getElementById('colorTitle').innerHTML = colors[idx].title;

	curIdx = idx;
}




// Launch Gallery
function launchColorGallery() {
	var photoPopupURL = filenamePrefix + 'gallery_' + whereYouAt + '_colors_popup.html?photoNum=' + curIdx;
	popup(photoPopupURL, "zoom", 769, 466, "scrollbars=no,menubar=no");
}

/* ********************************************************************************
   360 Spins
   ******************************************************************************** */
var i = 0;
var j = 0;


// Clears all Animation flags, and starts new animation from beginning
// USED
function spinClearAnimation(type, id) {
	id = id || "";
	var destination = 'spinsGalleryViewer' + id;
	
	if(whereYouAt == 'interior') {
		flipDelay = 3000;
	} else {
		flipDelay = 1000;
	}
	
	if(type == "preset") {
		clearTimeout(presetTimeOut);
		curAnim = true;
		if(document.getElementById('instructions')) {
			document.getElementById('instructions').innerHTML = '<img src="/lexus-share/images/spacer.gif" width="469" height="25" alt="" />';
		}
		document.getElementById(destination).innerHTML = '<img src="/lexus-share/images/spacer.gif" id="mainPhoto' + id + '" name="mainPhoto" width="469" height="225" alt="" />';
		j = 0;
	} else {
		curAnim = false;
		
		// Choose Correct Instructional Image
		if(whereYouAt == 'exterior') {
			document.getElementById('instructions').innerHTML = '<img src="/lexus-share/images/gallery/gal_360_ext_instructions.gif" width="469" height="25" alt="" />';
		} else {
			document.getElementById('instructions').innerHTML = '<img src="/lexus-share/images/gallery/gal_360_int_instructions.gif" width="469" height="25" alt="" />';
		}
	}
	spinPlayAnimation(type, id);
}

// Swap image and reload in 3 sec
// USED
var presetTimeOut;
function spinPlayAnimation(type, id) {
	if(type == "preset" && curAnim == true) {
		// if j is at last frame, start from beginning
		if(j == spinPresetFrames.length) {
			j = 0;
		}
		// swap photo and increment
		if(document.getElementById('mainPhoto' + id)) {
			document.getElementById('mainPhoto' + id).src = spinPresetFrames[j].src;
			j++;
			// replay function
			presetTimeOut = setTimeout(function(){spinPlayAnimation('preset', this)}.bind(id), flipDelay);
		}
		else {
			stopSpin();
		}
		
	} else if(type == "interactive") {
	   
	   	if(Plugin.isInstalled('QuickTime') && Plugin.getVersionAsFloat('QuickTime') >= 5) {
		    //** Show QTVR **
			newAnimation = "<OBJECT CLASSID=\"clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B\" WIDTH=\"469\" HEIGHT=\"225\" CODEBASE=\"http://www.apple.com/qtactivex/qtplugin.cab\">\n";
			newAnimation = newAnimation + "<PARAM name=\"SRC\" VALUE=\"" + spinQTVR + "\">\n";
			newAnimation = newAnimation + "<PARAM name=\"AUTOPLAY\" VALUE=\"true\">\n";
			newAnimation = newAnimation + "<PARAM name=\"CONTROLLER\" VALUE=\"false\">\n";
			newAnimation = newAnimation + "<EMBED SRC=\"" + spinQTVR + "\" WIDTH=\"469\" HEIGHT=\"225\" AUTOPLAY=\"true\" CONTROLLER=\"false\" PLUGINSPAGE=\"http://www.apple.com/quicktime/download/\">\n";
			newAnimation = newAnimation + "</EMBED>\n";
			newAnimation = newAnimation + "</OBJECT>\n";
			
			document.getElementById('spinsGalleryViewer').innerHTML = newAnimation;
			return new Object();
	   	}
	   	else {
	   		MovieUtils.buildNoPlugin('spinsGalleryViewer', 'quicktime');
	   	}
	}
}

var curSpin = '';
// Main Asset Activator
// USED
function playSpin(type, destination) {
	if(type != curSpin) {
		curSpin = type;
		spinClearAnimation(type, destination);
	}
}
function stopSpin() {
	clearTimeout(presetTimeOut);
}
/* ********************************************************************************
   Videos ( New Type w/ possible Broadcast Spots)
   ******************************************************************************** */

/* ********************************************************************************
   Videos
   ******************************************************************************** */
// Reset Thumbnails
function vClearThumbs() {
	for(i=0; i < videos.length; i++) {
		var a = 'thumb' + i;
		document.getElementById(a).src = videos[i].thumb.src;
	}
	// Must loop through radio buttons and set to false due to Safari Bug
	for(i=0; i<document.forms[0].videos.length;i++) {
		document.forms[0].videos[i].checked = false;
	}
}

// Thumbnail Over state
function vTnOvr(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = videos[idx].thumb_ovr.src;
	}
}

// Thumbnail Off State
function vTnOff(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = videos[idx].thumb.src;
	}
}

// Main Asset Activator
function displayVideo(idx,bw) {
	// Reset all Thumbnails
	vClearThumbs();
	
	// Default Size if thumbnail clicked instead of radio button
	if(!bw) {
		speed = 'hi';
		vidWidth = 272;
		vidHeight = 204;
	} else {
		speed = 'lo';
		vidWidth = 160;
		vidHeight = 120;
	}
	var v = 'video' + idx + '_' + speed;

	// Turn Radio Button "On"
	document.getElementById(v).checked = true;
	
	// Turn Thumbnail "On"
	var a = 'thumb' + idx;
	document.getElementById(a).src = videos[idx].thumb_on.src;
	
	// Build Object/Embed Code
	if (pluginType != "none supported") {
		//** Show Movie. **
		videoCode = "<embed src=\"" + eval('videos[' + idx + '].video_' + pluginType + '_' + speed) + "\" width=\"" + vidWidth +"\" height=\"" + vidHeight +"\"\n";

		//** Show Movie.  Determine proper MIMEtype **
		if (pluginType == "wm") {
			videoCode += ' type="application/x-mplayer2" showcontrols="0" showpositioncontrols="0" showaudiocontrols="1" showtracker="1" showdisplay="0" showstatusbar="0" autosize="0" showgotobar="0" showcaptioning="0" autorewind="0" animationatstart="0" transparentatstart="0" allowscan="1" enablecontextmenu="1" clicktoplay="0" invokeurls="1" defaultframe="datawindow" pluginspage="http://www.microsoft.com/isapi/redir.dll?prd=windows&amp;sbp=mediaplayer&amp;ar=media&amp;sba=plugin&amp;">\n';
		} 
		videoCode += "</EMBED>\n";
		videoCode = '<table width="469" height="225" border="0" cellspacing="0" cellpadding="0"><tr><td align="center">' + videoCode + '</td></tr></table>';
	} else {
		//** Show Error Message - No Proper Plugins Detected **
		videoCode = "**PLACEHOLDER**<BR>No proper plugin detected.  Download a new one.";
	}
	
	// If image is same, then do not reload main asset
	document.getElementById('vGalleryViewer').innerHTML = videoCode;

	// Set Current Index
	curIdx = idx;
}

/* ********************************************************************************
   Wallpapers
   ******************************************************************************** */
var size = 1024;

// Reset Thumbnails
function wpClearThumbs() {
	for(i=0; i < wallpapers.length; i++) {
		var a = 'thumb' + i;
		document.getElementById(a).src = wallpapers[i].thumb.src;
	}
	// Must loop through radio buttons and set to false due to Safari Bug
	for(i=0; i<document.forms[0].wallpaper.length;i++) {
		document.forms[0].wallpaper[i].checked = false;
	}
}

// Thumbnail Over state
function wpTnOvr(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = wallpapers[idx].thumb_ovr.src;
	}
}

// Thumbnail Off State
function wpTnOff(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = wallpapers[idx].thumb.src;
	}
}

// Main Asset Activator
function viewWP(idx,reso) {
	// Reset all Thumbnails
	wpClearThumbs();
	
	// Default Size if thumbnail clicked instead of radio button
	if(!reso) {
		size = 1024;
	} else {
		size = reso;
	}
	var wp = 'wallpaper' + idx + '_' + size;
	
	// Set Radio Button Value
	document.getElementById(wp).checked = true;
	
	// Turn Thumbnail "On"
	var a = 'thumb' + idx;
	document.getElementById(a).src = wallpapers[idx].thumb_on.src;
	
	// If image is same, then do not reload main asset
	if(idx != curIdx) {
		document.getElementById('mainPhoto').src = wallpapers[idx].image.src;
	}

	// Set Current Index
	curIdx = idx;
}

function wpDownload() {
	// alert(curIdx + '_' + size);
	var pagePrefix = ""
	
	if (gModelName == "is_5speed") {
		pagePrefix = "5speed_";
	} else if (gModelName == "is_eshift") {
		pagePrefix = "eshift_";
	} else if (gModelName == "is_sportcross") {
		pagePrefix = "sportcross_";
	}
	popupPrimary(filenamePrefix + "gallery_wallpapers_popup.html?idx=" + curIdx + "&size=" + size, "wallpaper");
}		

/* ********************************************************************************
   Screen Savers
   ******************************************************************************** */
var i = 0;
var j = 0;

// Clears all Animation flags, and starts new animation from beginning
function ssClearAnimation(idx) {
	for(i=0; i<ss.length; i++) {
		ss[i].curAnim = false;
	}
	j = 0;
	ss[idx].curAnim = true;
	ssPlayAnimation(idx);
}

// Swap image and reload in 3 sec
function ssPlayAnimation(idx) {
	if(ss[idx].curAnim == true) {
		// if j is at last frame, start from beginning
		if(j == ss[idx].frame.length) {
			j = 0;
		}
		// swap photo and increment
		document.getElementById('mainPhoto').src = ss[idx].frame[j].src;
		j++;
		// alert(idx);
		// replay function
		setTimeout('ssPlayAnimation(' + idx + ');', 2000);
	}
}

// Reset Thumbnails
function ssClearThumbs() {
	// Loop through all objects in ss array
	for(i=0; i < ss.length; i++) {
		var a = 'thumb' + i;
		document.getElementById(a).src = ss[i].thumb.src;
	}
}

// Thumbnail Over state
function ssTnOvr(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = ss[idx].thumb_ovr.src;
	}
}

// Thumbnail Off State
function ssTnOff(idx) {
	var a = 'thumb' + idx;
	if(idx != curIdx) {
		document.getElementById(a).src = ss[idx].thumb.src;
	}
}

// Photo Activator
function viewSS(idx) {
	ssClearThumbs();

	var a = 'thumb' + idx;
	document.getElementById(a).src = ss[idx].thumb_on.src;
	if(document.getElementById('ssFileName'))
	{
			document.getElementById('ssFileName').innerHTML = ss[idx].ssFileName;

	}
	// Play Animation
	ssClearAnimation(idx);
	
	// Set Index to Activated Index
	curIdx = idx;
}

// Download Screensaver
function ssDownload() {
	s_linkType='o';
	s_linkName= ss[curIdx].ssFileName;
	s_prop14=ss[curIdx].ssFileName;
	s_lnk=s_co(this);
	s_gs('');
	window.location.href=ss[curIdx].download;
}

/**
 * 
 * Functions from loadFlash.js used by ES/360 pages.
 */
function writeFlashObject(url,w,h,wmode){

	document.write(buildFlashObject(url,w,h,wmode));
}
function buildFlashObject(url, w,h,wmode) {
var theSWF = "";
if (wmode == 'no'){
	wmodeObject ='';
	wmodeEmbed = '';
}else{
	wmodeObject ='<param name="wmode" value="transparent">';
	wmodeEmbed = ' wmode="transparent"';
}
	if (FlashEnabled){
			theSWF = 	'<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" width="'+w+'" height="'+h+'">'+
								'	<param name="movie" value="'+url+'">'+
								'	<param name="mode" value="transparent">'+
								'	<param name="quality" value="high">'+ wmodeObject +
								'	<embed'+ wmodeEmbed +' src="'+url+'" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="'+w+'" height="'+h+'"></embed>'+
								'</object>';
	}
	return theSWF;	
	
}

// New Legacy functions to 360s that still use old assets

function registerWithParent(id) {
	parent.galleryManager.doTabAction(this,'registerWithParent',[window.self,id]);
}	
	/******************************************************************
 * Browser/OS Sniffer
 *****************************************************************/

// Read in HTTP_USER_AGENT from browser
var agt = navigator.userAgent.toLowerCase();

// Assign OS Variables
var is_mac = (agt.indexOf("mac") != -1);
var is_win = (agt.indexOf("win") != -1);
var is_ie = (navigator.userAgent.toUpperCase().indexOf("MSIE") > -1)? true:false
var is_ff = (navigator.userAgent.toUpperCase().indexOf("FIREFOX") > -1)? true:false

// Sniff for the two major browsers
var ie  = (document.all)? true:false
var ns6 = ((document.getElementById)&&(!ie))? true:false

// Sniff for Mac, used for IE Mac browsers
var mac = (navigator.userAgent.toUpperCase().indexOf("MAC") > -1)? true:false

// Sniff for AOL, used in certain cases where AOL won't pop open a window the size we want it
var aol = (navigator.userAgent.toUpperCase().indexOf("AOL") > -1)? true:false

/******************************************************************
 * Functions from old menu_dhtml.js
 *****************************************************************/
// Used to test if a value is 'undefined'.  What 'undefined' represents is different for each
// browser, but any variable that has not been defined a value IS 'undefined' in all browsers.
// So, we'll test against this variable to see if another is 'undefined'.
var undef;
var bgXcoord = 0;
var HideText = "";

var PreloadComplete = false;
var HomePreloadComplete = false;

// var is declared in universal nav offsite code, used to define full path.
// we don't want to hose the value, so we'll check if it has one.
if (!T1navPath) {
	var T1navPath = "";
}

var topNavBYLCode = new Array();
topNavBYLCode["ls"] = "9100";	// LS 430

topNavBYLCode["gs_gateway"] = "93";	// GS Generic
topNavBYLCode["gs"] = "9399";	// GS Generic
topNavBYLCode["gs_hybrid"] = "9344";	// GS Generic


topNavBYLCode["es"] = "9000";	// ES 300
topNavBYLCode["is"] = "95";	// IS 300 Generic
topNavBYLCode["sc"] = "9270";	// SC 430
topNavBYLCode["lx"] = "9620";	// LX 470
topNavBYLCode["gx"] = "9700";	// GX 470
topNavBYLCode["rx_gateway"] = "94";	// RX Generic
topNavBYLCode["rx"] = "9499";	// RX 330 FWD/AWD
topNavBYLCode["rx_hybrid"] = "9444";	// RX Hybrid 400

// Layer Build functions.  The IF verifies that, if a layer doesn't exist
// the function will return null instead of a JavaScript error.
function refLayer(layerName) {
	var LAYref;
	if (ie) {
		if (document.all[layerName]) {
			LAYref = document.all[layerName];
			HideText = "hidden";
		} else {
			LAYref = null;
		}
	} else {
	    // default to NS6+
		if (document.getElementById(layerName)) {
			LAYref = document.getElementById(layerName);
			HideText = "hidden";
		} else {
			LAYref = null;
		}
	}
	return LAYref;
}

function gotoBYL() {
	if (topNavBYLCode[gModelName]) {
		top.location.href=T1navPath+"/lexusConfigApp/index.jsp?modelName="+gLegacyAbbrev+"&modelCode="+topNavBYLCode[gModelName];
	} else {
		top.location.href=T1navPath+"/lexusConfigApp/index.jsp";
	}
}

function gotoVC() {
	if (gVCmodel == "rx_gateway") {
		top.location.href=T1navPath+"/models/comparison/rx.html";
	}else if (gVCmodel == "gs_gateway") {
		top.location.href=T1navPath+"/models/comparison/gs.html";
	} else if ((gVCmodel != "") && (gVCmodel != "hybrid")) {
		top.location.href=T1navPath+"/models/comparison/"+gVCmodel+".html";
	} else {
		top.location.href=T1navPath+"/models/comparison/index.html";
	}
}

function gotoContactDealer() {
	top.location.href=T1navPath+"/lexus/jsp/pub/dealers/contact/dealer_contact.jsp";
}

// Detect Current Model section and prepopulate hidden values in Brochure page
function gotoBrochures() {
	var BaseURL=T1navPath+"/lexus/jsp/pub/models/brochures/index.jsp";

	if (gModelName != "") {
		top.location.href=BaseURL+"?modelName="+gModelName;
	} else {
		top.location.href=BaseURL;
	}
}

// Backup function just in case it's being called from an unknown script/page
function gotoBrochurePDA() {
	gotoBrochures();
}

function gotoOrderBrochure(WeShouldReturnTheURL) {
//	document.location.href = T1navPath+"/lexus/SendDocumentRequest?documentType=B"+ordBrochureURL;
	var BaseURL = "https://secure.lexus.com/lexus/jsp/pub-ssl/models/orderbrochure/orderbrochure.jsp";
	var FullURL = "";

	if (gModelName != "") {
		if(gModelName == "rx_hybrid") {
			FullURL=BaseURL+"?modelName=RX Hy&modelCode="+topNavBYLCode[gModelName];
		}else if(gModelName == "gs_hybrid") {
			FullURL=BaseURL+"?modelName=GS Hy&modelCode="+topNavBYLCode[gModelName];
		} else {
			FullURL=BaseURL+"?modelName="+gLegacyAbbrev+"&modelCode="+topNavBYLCode[gModelName];
		}
	} else {
		FullURL=BaseURL+"?modelName=none&modelCode=none";
	}

	if (WeShouldReturnTheURL) {
		return FullURL;
	} else {
		top.location.href=FullURL;
	}
}

/*
curISmodel = "";
function gotoISModel(isModelName) {
    //** Only used within IS model directory, to switch between models. **
	if (gPageName != "") {
		seIdx = gPageName.lastIndexOf("_se");
		if ((seIdx != -1) && (seIdx == gPageName.length-3) && (isModelName == "sportcross")) {
		  // We're on a Special Edition page, but we're jumping to a Sportcross page.
		  // Go to the normal page.
			top.location.href=T1navPath+isModelName+"_"+gPageName.substring(0,seIdx)+".html";
		} else {
			top.location.href=T1navPath+isModelName+"_"+gPageName+".html";
		}
	} else {
		top.location.href=T1navPath+isModelName+".html";
	}
}
*/
function lexusMagazine() {
	magPath = 'http://www.lexus.com/magazine/webEntry.html';
	popup(magPath, 'lexusMagazine', 700, 450, 'menubar=no, scrollbars=no');
	top.location.href=T1navPath+"/owner/";
}

function setGlobals(modelName, pageName) {
// These two vars are effectively the same, but they are used differently.
// For readability purposes, please keep both of them.
	gVCmodel =  modelName
	gModelName = modelName;
	gPageName = pageName;
	gLegacyAbbrev = modelName.toUpperCase();
	gBrochurePDAAbbrev = modelName;
}
/******************************************************************
 * END Functions from old menu_dhtml.js
 *****************************************************************/

//********************************
//** Query String Parsing START **
//********************************

	// This loads all variables in a querystring into an associative array named qsVars
	// I.e., qsVars[variable_name] == variable_value when querystring is ?variable_name=variable_value&...
	var qsVars = new Array();

	var queryString = location.search;

	if (queryString != "") {
 		// -- get rid of ? at start --
  		var qsdata = queryString.slice(1,queryString.length);
		var qsvalues = qsdata.split("&");
		for (i=0; i < qsvalues.length; i++) {
			var qsvaluepair = qsvalues[i].split("=");
			//alert(qsvaluepair[0]);
			//alert(qsvaluepair[1]);
			qsVars[qsvaluepair[0]] = qsvaluepair[1];
		}
	}

//********************************
//** Query String Parsing END **
//********************************

//****************************
//** Flash Sniffing START ****
//****************************

// Check for Flash, set vars if T/F
var Flash4 = false;
var Flash5 = false;
var Flash6 = false;
var FlashEnabled = false;
// Default is False, so we only need to set it as True.
if (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"] ) {
	// Check for Flash in Netscape
	var nsFlash = navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin;
	if (nsFlash) {
		var FlashVer = parseInt(nsFlash.description.substring(nsFlash.description.indexOf(".")-1));
		if (FlashVer >= 6) {
			Flash6 = true;
		} else if (FlashVer == 5) {
			Flash5 = true;
		} else if (FlashVer == 4) {
			Flash4 = true;
		}
	}
} else if (navigator.appName && navigator.appName.indexOf("Microsoft") != -1 && navigator.userAgent.indexOf("Windows") != -1 && navigator.userAgent.indexOf("Windows 3.1") == -1) {
	var f4Inst;
	var f5Inst;
	var f6Inst;

	eval('try { f4Inst = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.4"); f5Inst = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.5"); f6Inst = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); } catch (e) { }');

	if (f6Inst != null) {
		Flash6 = true;
	} else if (f5Inst != null) {
		Flash5 = true;
	} else if (f4Inst != null) {
		Flash4 = true;
	}

	f4Inst = null;
	f5Inst = null;
	f6Inst = null;
}

if (qsVars['flash'] == 'disabled') {
	Flash4 = false;
	Flash5 = false;
	Flash6 = false;
	alert('Flash has been disabled for testing purposes.');
	// FlashEnabled default is false
} else if (Flash5 || Flash6) {
	FlashEnabled = true;
}


//**************************
//** Flash Sniffing END ****
//**************************

//**************************
//** Misc Functions START **
//**************************

function newCursor(imgName, curName) {
if (PreloadComplete) {
	document.images[imgName].style.cursor = curName;
}
}

//****************************************************
//** Popup function Fixes IE making popup windows   **
//** 20px higher than specified when menubar is on  **
//** Parameters can be passed in as necessary 	    **
//** returns a reference to the	window if needed    **
//****************************************************

function popup(popupurl,winName,w,h,params) {
   // Build parameter list manually.  This lets us override individual defaults as needed.

	var paramList = "";
	if (params == undef) {
		params = "";
	}
	
	params = params.toLowerCase();
	
	// Centering the Popup
	if (params.indexOf("centered=yes") != -1)
		{
			t = Math.round((screen.height - h) / 2);
			l = Math.round((screen.width - w) / 2);
		}
	else
		{
			t = 35;
			l = 130;
		}

	if (params.indexOf("menubar=no") != -1) {
		paramList = paramList + ",menubar=no";
	} else {
	    // default
		paramList = paramList + ",menubar=yes";
	    // IE adds to the height with a menubar; subtract to keep height the same.
		if (ie && !mac) {
			h = h - 20;
		}
	}
	
	if(aol) // aol anti-spyware tools deduct from our viewable area
		{
		h = h + 45;
		}
	

	// For Mozilla Popups that don't need extra sapce
	if ((params.indexOf("scrollbars=no") != -1) || (params.indexOf("scrollbar=no") != -1)) {
		paramList = paramList + ",scrollbars=no";
	} else if (params.indexOf("mozscroll=auto") != -1 && !is_ie) {
		w = w;
	} else {
	    // default
		paramList = paramList + ",scrollbars=yes";
	    // IE needs extra space to allow for the phantom scrollbar, or we'll get horizontal scrollbars too.
	    // IE 6.x needs 4px more than IE 5.x, but IE 5.x's width needs vary a lot.  So, we'll set all
	    // IE browsers to use the wider IE 6.x size.
		if (ie && !aol)
		{
			w = w + 17;
		}
		else if(is_ff)
		{
			w = w + 19;
		}
		else
		{
			if(aol)
				w = w + 21;
			else
				w = w + 16;
		}
	}
	
	if (params.indexOf("resizable=yes") != -1) {
		paramList = paramList + ",resizable=yes";
	} else {
	    // default
		paramList = paramList + ",resizable=no";
	}
	
	if ((params.indexOf("toolbar=yes") != -1) || (params.indexOf("toolbars=yes") != -1)) {
		paramList = paramList + ",toolbar=yes";
	} else {
	    // default
		paramList = paramList + ",toolbar=no";
	}
	
	if ((params.indexOf("location=yes") != -1) || (params.indexOf("location=yes") != -1)) {
		paramList = paramList + ",location=yes";
	} else {
	    // default
		paramList = paramList + ",location=no";
	}
	
	if ((params.indexOf("status=yes") != -1)) {
		paramList = paramList + ",status=yes";
	} else {
	    // default
		paramList = paramList + ",status=no";
	}
	
	if ((params.indexOf("top=") != -1) || (params.indexOf("left=") != -1)) {
		paramArray = params.split(",");
		for (i=0; i<paramArray.length; i++) {
			if (paramArray[i].indexOf("top=") != -1) {
				pEles = paramArray[i].split("=");
				t = pEles[1];
			}
			if (paramArray[i].indexOf("left=") != -1) {
				pEles = paramArray[i].split("=");
				l = pEles[1];
			}
		}
	}
	// Override window name
	if (winName == "grad") {
	winName = "gradprogram";
	} else if (winName == "gradprog") {
	winName = "gradprogram";
	}
	
	//alert(paramList);
	return window.open(popupurl,winName,"top=" + t + ",left=" + l + ",width=" + w + ",height=" + h + paramList);
}

// Primary Popup 525x470
function popupPrimary(url,popupName,params) {
	// If Parameters are Empty
	var paramList = "";
	if (params == undef) {
		params = "";
	}

	popup(url,popupName,525,470,params);
}

// Secondary Popup 525x230
function popupSecondary(url,popupName,params) {
	// If Parameters are Empty
	var paramList = "";
	if (params == undef) {
		params = "";
	}

	popup(url,popupName,525,230,params);
}

//************************
//** Misc Functions END **
//************************

//************************
//	Standards Compliant Rollover Script
//	Author : Daniel Nolan
//	http://www.bleedingego.co.uk/webdev.php
//************************
function initRollovers() {
	if (!document.getElementById) return
	
	var aPreLoad = new Array();
	var sTempSrc;
	var aImages = document.getElementsByTagName('img');

	for (var i = 0; i < aImages.length; i++) {		
		if (aImages[i].className == 'imgover') {
			var src = aImages[i].getAttribute('src');
			var ftype = src.substring(src.lastIndexOf('.'), src.length);
			var hsrc = src.replace(ftype, '_ovr'+ftype);

			aImages[i].setAttribute('hsrc', hsrc);
			
			aPreLoad[i] = new Image();
			aPreLoad[i].src = hsrc;
			
			aImages[i].onmouseover = function() {
				sTempSrc = this.getAttribute('src');
				this.setAttribute('src', this.getAttribute('hsrc'));
			}	
			
			aImages[i].onmouseout = function() {
				if (!sTempSrc) sTempSrc = this.getAttribute('src').replace('_ovr'+ftype, ftype);
				this.setAttribute('src', sTempSrc);
			}

			// Added to relieve bug in Mozilla, when layer dissapears and mouse never goes "out", is stuck in hover state
			aImages[i].onclick = function() {
				if (!sTempSrc) sTempSrc = this.getAttribute('src').replace('_ovr'+ftype, ftype);
				this.setAttribute('src', sTempSrc);
			}
		}
	}
	LAYarrowHL = refLayer("arrowHL");
	PreloadComplete = true;
}

//*****************************************
//** Nav Rollover Arrows Functions START **
//** Needed for Events tertiary nav      **
//*****************************************
/*
	plArrowHL = new Image();
	plArrowHL.src = "/assets/common/arrow_highlight.gif";
	plArrowGR = new Image();
	plArrowGR.src = "/assets/common/arrow_gray.gif";

	function arrowHL(imgName) {
		if (document.images[imgName]) {
			document.images[imgName].src = plArrowHL.src;
		}
	}

	function arrowGR(imgName) {
		if (document.images[imgName]) {
			document.images[imgName].src = plArrowGR.src;
		}
	}
*/
// Parent Child Window Hook
function oFocus() {
	self.focus();
}

//***************************************
//** Nav Rollover Arrows Functions END **
//***************************************

// must run to declare default values
setGlobals('','')	
	function writeFlashObject(url,w,h,wmode){

	document.write(buildFlashObject(url,w,h,wmode));
}
function buildFlashObject(url, w,h,wmode) {
var theSWF = "";
if (wmode == 'no'){
	wmodeObject ='';
	wmodeEmbed = '';
}else{
	wmodeObject ='<param name="wmode" value="transparent">';
	wmodeEmbed = ' wmode="transparent"';
}
	if (FlashEnabled){
			theSWF = 	'<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" width="'+w+'" height="'+h+'">'+
								'	<param name="movie" value="'+url+'">'+
								'	<param name="mode" value="transparent">'+
								'	<param name="quality" value="high">'+ wmodeObject +
								'	<embed'+ wmodeEmbed +' src="'+url+'" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="'+w+'" height="'+h+'"></embed>'+
								'</object>';
	}
	return theSWF;	
	
}
function popup_large_view(viewType){
	if (viewType == 'interior'){
		popup('/assets/models/gallery/360/es/lg_interior.html','popupZoom',770,640,'scrollbars=no,menubar=no,toolbar=no,location=no,status=no');
	}else{
		popup('/assets/models/gallery/360/es/lg_exterior.html','popupZoom',770,640,'scrollbars=no,menubar=no,toolbar=no,location=no,status=no');
	}
}	
	/*
 * FlashObject embed
 * http://blog.deconcept.com/2004/10/14/web-standards-compliant-javascript-flash-detect-and-embed/
 *
 * by Geoff Stearns (geoff@deconcept.com, http://www.deconcept.com/)
 *
 * v1.0.7 - 11-17-2004
 *
 * Create and write a flash movie to the page, includes detection
 *
 * Usage:
 *
 *	myFlash = new FlashObject("path/to/swf.swf", "swfid", "width", "height", flashversion, "backgroundcolor");
 *	myFlash.altTxt = "Upgrade your Flash Player!";                // optional
 *	myFlash.addParam("wmode", "transparent");                     // optional
 *	myFlash.addVariable("varname1", "varvalue");                  // optional
 *	myFlash.addVariable("varname2", getQueryParamValue("myvar")); // optional
 *	myFlash.write();
 *
 */

FlashObject = function(swf, id, w, h, ver, c) {
	this.swf = swf;
	this.id = id;
	this.width = w;
	this.height = h;
	this.version = ver || 6; // default to 6
	this.align = "middle"; // default to middle
	this.redirect = "";
	this.sq = document.location.search.split("?")[1] || "";
	this.altTxt = "Please <a href='http://www.macromedia.com/go/getflashplayer'>upgrade your Flash Player</a>.";
	this.bypassTxt = "<p>Already have Flash Player? <a href='?detectflash=false&"+ this.sq +"'>Click here if you have Flash Player "+ this.version +" installed</a>.</p>";
	this.params = new Object();
	this.variables = new Object();
	if (c) this.color = this.addParam('bgcolor', c);
	this.addParam('quality', 'high'); // default to high
	this.doDetect = getQueryParamValue('detectflash');
}

FlashObject.prototype.addParam = function(name, value) {
	this.params[name] = value;
}

FlashObject.prototype.getParams = function() {
    return this.params;
}

FlashObject.prototype.getParam = function(name) {
    return this.params[name];
}

FlashObject.prototype.addVariable = function(name, value) {
	this.variables[name] = value;
}

FlashObject.prototype.getVariable = function(name) {
    return this.variables[name];
}

FlashObject.prototype.getVariables = function() {
    return this.variables;
}

FlashObject.prototype.getParamTags = function() {
    var paramTags = "";
    for (var param in this.getParams()) {
        paramTags += '<param name="' + param + '" value="' + this.getParam(param) + '" />';
    }
    if (paramTags == "") {
        paramTags = null;
    }
    return paramTags;
}

FlashObject.prototype.getHTML = function() {
    var flashHTML = "";
    if (window.ActiveXObject && navigator.userAgent.indexOf('Mac') == -1) { // PC IE
        flashHTML += '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + this.width + '" height="' + this.height + '" id="' + this.id + '" align="' + this.align + '">';
        flashHTML += '<param name="movie" value="' + this.swf + '" />';
        if (this.getParamTags() != null) {
            flashHTML += this.getParamTags();
        }
        if (this.getVariablePairs() != null) {
            flashHTML += '<param name="flashVars" value="' + this.getVariablePairs() + '" />';
        }
        flashHTML += '</object>';
    }
    else { // Everyone else
        flashHTML += '<embed type="application/x-shockwave-flash" src="' + this.swf + '" width="' + this.width + '" height="' + this.height + '" id="' + this.id + '" align="' + this.align + '"';
        for (var param in this.getParams()) {
            flashHTML += ' ' + param + '="' + this.getParam(param) + '"';
        }
        if (this.getVariablePairs() != null) {
            flashHTML += ' flashVars="' + this.getVariablePairs() + '"';
        }
        flashHTML += '></embed>';
    }
    return flashHTML;	
}


FlashObject.prototype.getVariablePairs = function() {
    var variablePairs = new Array();
    for (var name in this.getVariables()) {
        variablePairs.push(name + "=" + escape(this.getVariable(name)));
    }
    if (variablePairs.length > 0) {
        return variablePairs.join("&");
    }
    else {
        return null;
    }
}

FlashObject.prototype.write = function(elementId) {
	if(detectFlash(this.version) || this.doDetect=='false') {
		if (elementId) {
			document.getElementById(elementId).innerHTML = this.getHTML();
		} else {
			document.write(this.getHTML());
		}
	} else {
		if (this.redirect != "") {
			document.location.replace(this.redirect);
		} else {
			if (elementId) {
				document.getElementById(elementId).innerHTML = this.altTxt +""+ this.bypassTxt;
			} else {
				document.write(this.altTxt +""+ this.bypassTxt);
			}
		}
	}		
}

FlashObject.prototype.returnHTML = function(elementId) {
	if(detectFlash(this.version) || this.doDetect=='false') {
		if (elementId) {
			document.getElementById(elementId).innerHTML = this.getHTML();
		} else {
			return (this.getHTML());
		}
	} else {
		if (this.redirect != "") {
			document.location.replace(this.redirect);
		} else {
			if (elementId) {
				document.getElementById(elementId).innerHTML = this.altTxt +""+ this.bypassTxt;
			} else {
				return (this.altTxt +""+ this.bypassTxt);
			}
		}
	}		
}

function getFlashVersion() {
	var flashversion = 0;
	if (navigator.plugins && navigator.plugins.length) {
		var x = navigator.plugins["Shockwave Flash"];
		if(x){
			if (x.description) {
				var y = x.description;
	   			flashversion = y.charAt(y.indexOf('.')-1);
			}
		}
	} else {
		result = false;
	    for(var i = 15; i >= 3 && result != true; i--){
   			execScript('on error resume next: result = IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash.'+i+'"))','VBScript');
   			flashversion = i;
   		}
	}
	return flashversion;
}

function detectFlash(ver) {	
	if (getFlashVersion() >= ver) {
		return true;
	} else {
		return false;
	}
}

// get value of querystring param
function getQueryParamValue(param) {
	var q = document.location.search;
	var detectIndex = q.indexOf(param);
	var endIndex = (q.indexOf("&", detectIndex) != -1) ? q.indexOf("&", detectIndex) : q.length;
	if(q.length > 1 && detectIndex != -1) {
		return q.substring(q.indexOf("=", detectIndex)+1, endIndex);
	} else {
		return "";
	}
}

/* add Array.push if needed */
if(Array.prototype.push == null){
	Array.prototype.push = function(item){
		this[this.length] = item;
		return this.length;
	}
}	
	var vmp;
var VET_IfVer="05.00.01.04",
VET_ch,
VET_Ap=navigator.appName,
VET_Bv=parseInt(navigator.appVersion.substring(0,1)),
VET_Ag=navigator.userAgent.toLowerCase(),
VET_IE=VET_Ag.indexOf("msie")!=-1&&(VET_Bv>=4)&&VET_Ag.indexOf("opera")==-1,
VET_IE5=(VET_IE&&(VET_Ag.charAt(VET_Ag.indexOf('msie')+5)=='5')),
VET_Firefox=VET_Ag.indexOf('firefox')!=-1,
VET_Safari=((VET_Ag.indexOf("safari/")!=-1) && (parseInt(VET_Ag.substring(VET_Ag.indexOf("safari/")+7,VET_Ag.length)) >= 100)),
VET_NN=VET_Ap.indexOf("Netscape")!=-1,
VET_NN4=VET_NN&&VET_Bv==4,
VET_Gecko=VET_Ag.indexOf('gecko')!=-1,
VET_CS=VET_Ag.indexOf('cs 2000 7')!=-1,
VET_AOL=VET_Ag.indexOf('aol')!=-1,
VET_NN6=VET_NN&&(parseInt(navigator.vendorSub)==6),
VET_NN7=VET_NN&&(parseInt(navigator.vendorSub)==7)&&!VET_CS,
VET_AppVer=parseFloat(navigator.appVersion),
VET_Win=navigator.platform=="Win32",
VET_Mac=VET_Ag.indexOf('mac')!=-1,
VET_Java=navigator.javaEnabled(),
VET_Mim="application/x-mtx",
VET_Cv=VET_Hff=VET_Mc=VET_Dbg=VET_Sdr=0,
VET_NNtrgr="0",VET_Pu,
VET_AxPriID="03F998B2-0E00-11D3-A498-00104B6EB52E",
VET_AxPriNa="AxMetaStream.MetaStreamCtl",
VET_AxSecID="1B00725B-C455-4DE6-BFB6-AD540AD427CD",
VET_AxSecNa="AxMetaStream.MetaStreamCtlSecondary",
VET_AltPlugin=0,
VET_AxID=VET_AxPriID,
VET_Gnns=VET_Gac=VET_Gurl=VET_Gnam=VET_Gprp="",
VET_Dv="http://www.viewpoint.com/installer/",
VET_Re=VET_Dv+'index.html?',VET_Ln="none",VET_Tr="Trigger",VET_Rtyp=1,
VET_Ic="ISceneComponent",VET_Cf="ComponentFileName",
VET_Sc="SceneComponent.mtc",VET_Bk="BroadcastKeyFileURL",
VET_Premium=false,
VET_TopURL=""
if(!window.VET_WindowID)VET_WindowID=(new Date()).getTime()+"_"+Math.floor(Math.random()*10000)
	//These legacy is* definitions are for backwards compatibility only. Remove if you want.
	isIE=isIE4=VET_IE||VET_Gecko
	isNN=VET_NN4
	isNN6=VET_NN6
	isMac=VET_Mac
	isWin=VET_Win
function VET_Mili(){var v=new Date();return v.getTime()}
function VET_Rand(f){return Math.floor(Math.random()*f)}
VET_StartGid=((VET_Mili()%100000)*10000)+VET_Rand(10000)
MTSPlugin.prototype.genid=VET_StartGid
function Check_OSX(){if(!VET_Mac)return false;if(VET_Ag.indexOf("mac os x")!=-1)return true
	if(navigator.plugins)
		for(var i=0;i<navigator.plugins.length;i++){
			if(navigator.plugins[i].name.toLowerCase()=="default plugin carbon.cfm")return true
		}
	return false
}
VET_MacOSX=Check_OSX()
VET_UnknownOS=!VET_Mac&&!VET_Win
VET_UnknownBrowser=!VET_IE&&!VET_NN
VET_Pu="Javascript:MTSopenBrWindow('"+VET_Re+"'+VET_Rtyp+'&"+VET_IfVer+"&"+window.location.href+"','vet_install','width=500,height=400,toolbar=no,location=no,resizable=no')"
if(VET_IE&&!VET_Mac)document.write("<SCRIPT LANGUAGE=\"VBScript\">\nDim p_o\nFunction VET_IEChk(n)\nVET_IEChk=1\nOn Error Resume Next\nSet p_o=CreateObject(n)\nif IsObject(p_o) then\nVET_IEChk=0\nend if\nEnd Function\n</SCRIPT>\n")
function MTSDebugger(i){VET_Dbg=i}
function MTSConsole(p1,p2){arguments.length==1?_mtsConsole(p1):_mtsConsole(p1,p2)}
function VET_Ci(arg){
	if(VET_ch==null||VET_ch.closed){
		if(arguments.length==1&&arg==1&&!VET_Premium){
			VET_Premium=true
			MTSJumpToRedirector()
			return
		}
		var e=new Date();e.setTime(e.getTime()+30000)
		SetCookie("VETInstallerPopup",("AutoReload; expires="+e.toGMTString()))
		var c=GetCookie("VETInstallerPopup")
		if((c!=""&&c.substring(0,10)=="AutoReload")||IsMTSInstalled())location.reload()
	}
	else setTimeout("VET_Ci(0)",1000)
}
function MTSopenBrWindow(u,n,f){VET_ch=window.open(u,n,f);setTimeout("VET_Ci(1)",2000)}

function testPlugin(create)
{	
	if (create) {
		var divTemp = document.createElement("div");
		divTemp.setAttribute("id","vmpTempDiv");
		divTemp.setAttribute("style",'position: absolute; top: -100px; left: -100px; z-index: 1000;');
		document.body.appendChild(divTemp);
		document.getElementById('vmpTempDiv').innerHTML = '<embed Component="ISceneComponent" Componentfilename="SceneComponent.mtc" type="application/x-mtx" name="vmpTest" width="2" height="2" script="true" VMPClassID="{03F998B2-0E00-11D3-A498-00104B6EB52E}"></embed>';
	} else {
		if (typeof document.getElementById('vmpTempDiv') == "object") 
		{
			var tempRef = document.getElementById('vmpTempDiv');
			tempRef.parentNode.removeChild(tempRef);
			tempRef.innerHTML = "";
		}
	}
}

function VET_Np(mimetype,pluginName)
{
	if (VET_NN && VET_Gecko) navigator.plugins.refresh(false);
	if (navigator.plugins) 
	{
		for (var i = 0; i < navigator.plugins.length; i++) 
		{
			if (navigator.plugins[i].name.toLowerCase() == pluginName.toLowerCase()) 
			{
				for (var j = 0; j < navigator.plugins[i].length; j++) 
				{
					var mim = navigator.plugins[i][j]
					if (mim.enabledPlugin && (mim.type == mimetype)) 
					{
						if (VET_Win && VET_Gecko && (document.body != null)) 
						{
							testPlugin(true);
							if(typeof document.embeds.vmpTest.DoCommand != "undefined") 
							{
								testPlugin(false);
								return true
							} else {
								testPlugin(false);
								return false;
							}
						} else if (VET_Mac && VET_Gecko && (!VET_Safari)) {
							return false;
						} else {
							return true
						}
					}
				}
				return false
			}
		}
	return false
	}
}

function VET_Ax(){
	if(VET_IEChk(VET_AxPriNa)==0)return true
	if(VET_AltPlugin==1&&VET_IEChk(VET_AxSecNa)==0){VET_AxID=VET_AxSecID;return true}
	return false
}
function IsMTSInstalled(){
	var i = true, m = "MetaStream" + (VET_Mac? "3" : " 3 Plugin")
	if (VET_IE && !VET_Mac) i = VET_Ax()
	else i = VET_Np(VET_Mim, m)
	return i
}
var VET_IsIn=IsMTSInstalled()
MTSPlugin.prototype.createParams=function(pi){this.newParamString=""
	var cMV="50333440",gMV="50333440";this.LN=VET_Ln;var parms=""
	var hMV="50333440"
	if(pi!=null){var xso=pi.indexOf("xmltext")
		if(xso!=-1){var opi=pi,xs=xso+7
			while((xs<pi.length)&&(pi.substring(xs,xs+1)!="<"))xs++
			if(xs<pi.length){var xe=xs,xc=0
				while(xe<pi.length){var chr=pi.substring(xe++,xe)
					if(chr=="&")xc=2;else if(chr==";"){if(xc>0)xc--;else{xe--;break}}
				}
				var xt=pi.substring(xs,xe)
				parms+=AddParm("xmltext",xt)
				if(opi.substring(xe,xe+1)==";")xe++
				pi=opi.substring(0,xso)
				if(xe<opi.length-1)pi+=opi.substring(xe,opi.length)
			}
		}
	}
	if(pi!=null){var tA=pi.split(";")
		for(var i=0;i<tA.length;i++){
			if(tA[i]!=""){var tV=tA[i].split("=");re= / /g;
				tV[0]=tV[0].replace(re,"");var tv0l=tV[0].toLowerCase()
				if(tv0l=="genieminimumversion"){tV[1]=tV[1].replace(re,"");gMV=tV[1]}
				else if(tv0l=="hostminimumversion"){tV[1]=tV[1].replace(re,"");hMV=tV[1]}
				else if(tv0l=="componentminimumversion"){tV[1]=tV[1].replace(re,"");cMV=tV[1]}
				else if(tv0l=="classid"){tV[1]=tV[1].replace(re,"");VET_AxID=tV[1]}
				else if(tv0l=="layer"){tV[1]=tV[1].replace(re,"");this.LN=tV[1]}
				else if(tv0l=="nntrigger"){tV[1]=tV[1].replace(re,"");VET_NNtrgr=tV[1]}
				else if(tv0l=="componentname"){tV[1]=tV[1].replace(re,"");VET_Ic=tV[1]}
				else if(tv0l=="imagelink"){tV[1]=tV[1].replace(re,"");this.ImageLink=tV[1]}
				else if(tv0l=="altplugin"){tV[1]=tV[1].replace(re,"");if(tV[1]=="1"||tV[1]=='true')VET_AltPlugin=1;else VET_AltPlugin=0}
				else if(tv0l=="basehref"){tV[1]=tV[1].replace(re,"");if(tV[1]=="1")this.newParamString+="basehref"+"="+VET_href(this.LN)+";"}
				else if(tv0l=="topurl"){tV[1]=tV[1].replace(re,"");if(VET_TopURL=="")VET_TopURL=tV[1]}
				else{var idx=1,token1=tV[idx-1],token2=tV[idx];idx++
					while(tV[idx]!=null){token2+="="+tV[idx];idx++}
					parms+=AddParm(token1,token2)
					this.newParamString+=token1+"="+token2+";"
				}
			}
		}
	}
	if((VET_NN4&&VET_AppVer<4.5)||VET_Gecko)this.popUp=1
	parms+=AddParm("HostMinimumVersion",hMV)
	if(VET_Mac&&VET_MacOSX)
		parms+=AddParm("WindowID",VET_WindowID)
	parms+=AddParm("ComponentMinimumVersion",cMV)
	parms+=AddParm("GenieMinimumVersion",gMV)
	parms+=AddParm("VMPClassID",("{"+VET_AxID+"}"))
	parms+=AddParm("PageURL",window.location.href)
	if(this.LN!=VET_Ln&&VET_Mac&&VET_IE)this.newParamString+="layername="+this.LN+";"
	this.newParamString+="parentlocation="+self.location.href+";"
	this.newParamString+="mts3interfaceversion="+VET_IfVer+";"
	this.newParamString+="referrer="+(window.VET_Referrer?window.VET_Referrer:window.location.href)+";"
	return parms
}
function AddParm(n,v){if(VET_IE&&VET_Win)return MTSParm(n,v);else return (n+" = "+"'"+v+"' ")}
function GetCookie(a){var e,m=" "+document.cookie+";",N=" "+a+"=",s=m.indexOf(N),r="";if(s!=-1){s+=N.length;e=m.indexOf(";",s);r=unescape(m.substring(s,e))}return r}
function SetCookie(n,v){document.cookie=n+"="+escape(v)}
function ClearCookie(n){var e=new Date();e.setTime(e.getTime()-(3*24*60*60*1000));document.cookie=n+"=ImOutOfHere; expires="+e.toGMTString()}
function GetBase(){var ob=document.getElementsByTagName('BASE');return ((ob&&ob.length)?ob[0].href:null)}
function VET_href(ln){var t="mtsEmpty.html",doc="",c,l
	if(VET_NN4&&ln!=VET_Ln)doc="document."+ln+"."
	doc+="document."
	eval("c="+doc+"links.length")
	var y="write(\"<a href='\"+t+\"'></a>\")"
	eval(doc+y)
	eval("l="+doc+"links[c].href")
	if(t==l)l=""
	else{var re= /mtsEmpty.html/g;
		l=l.replace(re,"")}
	if(VET_Gecko)l=GetBase()
	return l
}
function MTS_IsString(s){if(s=="")return true;for(var i=0;i<s.length;i++){if(((s.charAt(i)<"0")||(s.charAt(i)>"9"))&&(s.charAt(i)!=".")&&(s.charAt(i)!="-"))return true}return false}
function MTSWrapValue(v){var rs=v.toString();if(MTS_IsString(rs))rs="'"+rs+"'";return rs}
function MTSPlugin(file,width,height,bkey,alt,parmsc){
	if (parmsc.toLowerCase().indexOf('imagelink')>-1) this.ImageLink="1";
	if((VET_Gecko)&&((alt.toLowerCase()=="classic")||(alt=="none"))){alt="premium";this.popUp=1}
	if((alt.toLowerCase()=="simple") || (alt.toLowerCase()=="premium") || (alt=="")){
		if(VET_NN4)alt="classic";
		else {
			eval("try{VET_TopURL=top.location.href}catch(e){}");//in eval so NN4 is happy
			VET_Premium=true
			if (!this.ImageLink=="1") alt="popup";
			this.popUp=1
		}
	}
	if(VET_Dbg==1&&arguments.length>6)MTSConsole("Error: MTSPlugin function takes up to 6 parameters. You supplied "+arguments.length+".")
	if((alt.toLowerCase()=="classic")||(alt.toLowerCase()=="none")){alt=VET_Ln;if(MTSPlugin.prototype.genid==VET_StartGid)VET_NNtrgr="1"}
	if(VET_Gecko&&(alt=="none"))alt="popup"
	var str=VET_Ln,na=this.name="MetaCtl"+MTSPlugin.prototype.genid.toString()
	MTSPlugin.prototype.genid++;this.LN=VET_Ln;this.ImageLink="0"
	if(VET_Hff==0&&VET_Mac&&(VET_IE||VET_Gecko))
	{
		//VET_Hff=1
		this.stream += "<div id='HiddenLayer' style='position:absolute;left:-1000px;top:-1000px;width:0px;height:0;z-index:0;visibility:hidden'><form name='MTS3'><input type=text name='mts3_js_jsfield'></form></div>";
		if(VET_Mac&&!VET_MacOSX)setTimeout('ExecValue()',3)
	}
	if(VET_MacOSX){this.sequenceID=0
		this.stream += "<div id='OSX_S_"+this._mtsPID()+"' name='OSX_S_"+this._mtsPID()+"' style='position:absolute;left:2px;top:0px;width:2px;height:2px;visibility:visible;z-index:999999'></div>";
	}
	var parms=this.createParams(parmsc)
	VET_IsIn=IsMTSInstalled()
	if((alt.length!=0)&&(!VET_IsIn))str=alt
	if((VET_NNtrgr=="1")&&(VET_Cv==0)&&VET_NN4)TriggerJS()
	if((((str.toLowerCase()==VET_Ln)&&(!VET_Mac))||((GetCookie(na)=="1")&&(!VET_Mac)))&&((!(this.popUp=="1"))||(str.toLowerCase()==VET_Ln))||(VET_IsIn)){
		if(VET_Win&&VET_IE){var ch=""
			if(file!="")ch=MTSParm("Source",file)
			ch+=MTSParm("Component",VET_Ic)+MTSParm(VET_Cf,VET_Sc)+MTSParm(VET_Bk,bkey)
			ch+=parms;ch+=MTSParm("properties",this.newParamString)
			var cbURL="https://components.viewpoint.com/MTSInstallers/MetaStream3.cab"+"?url="+(window.VET_Referrer?window.VET_Referrer:window.location.href)+"#Version=3,0,2,62"
			str=MTSMarkup("object",ch,"id",na,"classid",("CLSID:"+VET_AxID),"width",width,"height",height,((MTSPlugin.prototype.genid==VET_StartGid+1)?"codebase":"dummy"),cbURL)
			if(VET_Dbg==1)MTSConsole(str,na)
			this.stream += str;
		}else{var tag
			if(VET_Mac&&VET_NN4&&!VET_IsIn)tag="PLUGINSPAGE"
			else if(VET_Mac&&VET_IE&&!VET_IsIn)MTSJumpToRedirector(this.LN)
			else tag="PluginURL"
			str=MTSMarkup("embed","<!-- -->","component",VET_Ic,"componentfilename",VET_Sc,"source",file,"type",VET_Mim,"width",width,"height",height,"script",true,"name",na,VET_Bk,bkey,"properties",this.newParamString,"instancename", na, tag, VET_Pu, parms)
			if(this.LN!=VET_Ln){
				if(VET_Dbg==1)MTSConsole(str,na)
				if(VET_IE||VET_Gecko)this.stream += str;
				else{VET_Gnns=str;var v="document."+this.LN+".document.write(VET_Gnns);";eval(v)}
			}else{
				if(VET_Dbg==1)MTSConsole(str,na)
				this.stream += str;
			}
			if(GetCookie(na+VET_Tr)=="1"){ClearCookie(na+VET_Tr)
				if((this.popUp!='1')&&(VET_NN4))TriggerJS()
			}
		}
		if(this.ImageLink=="1")ClearCookie(na)
	}else{
		if((this.ImageLink!="1"&&this.popUp=="1")||((GetCookie(na)=="1")&&(this.popUp=="1"))||(str.toLowerCase()=="popup")||(VET_Mac&&((str==VET_Ln)||(GetCookie(na)=="1")))){
			if(this.ImageLink=="1")ClearCookie(na)
			if((alt!=VET_Ln)&&(alt.toLowerCase()!="popup")){VET_Gac=alt
				if((VET_NN4)&&(this.LN!=VET_Ln)){var outStr="document."+this.LN+".document.write(VET_Gac);"
					if(VET_Dbg==1)MTSConsole(outStr,na)
					eval(outStr)
				}else{
					if(VET_Dbg==1)MTSConsole(alt,na)
					this.stream += alt;
				}
			}
			MTSJumpToRedirector(this.LN)
		}else{
			if(this.ImageLink=="1"){
				VET_Premium=true;
				str2='JavaScript:mtsClick("'+this.LN+'")';
				str=MTSMarkup("A",str,"HREF",str2)
			}
			VET_Gac=str
			if(VET_NN4&&(this.LN!=VET_Ln)){var outStr="document."+this.LN+".document.write(VET_Gac);"
				if(VET_Dbg==1)MTSConsole(outStr,na)
				eval(outStr)
			}else{
				if(VET_Dbg==1)MTSConsole(str,na)
				this.stream += str;
			}
		}
	}
}
function mtsClick(ln){var t=""
	for(var i=VET_StartGid;i<MTSPlugin.prototype.genid;i++){t="MetaCtl"+i.toString();SetCookie(t,'1')}
	if(VET_NN4)SetCookie(("MetaCtl0"+VET_Tr),"1")
	ClearCookie("VETInstallerPopup")
	if(GetCookie("MetaCtl0")=="1")location.reload()
	else MTSJumpToRedirector(ln);
}
function ExecValue(){document.MTS3.mts3_js_jsfield.value="MTS3_Req";var v=document.MTS3.mts3_js_jsfield.value
	if((v!="")&&(v!="MTS3_Req")){eval(v);v="";document.MTS3.mts3_js_jsfield.value=""}
	if(v=="MTS3_Req")document.MTS3.mts3_js_jsfield.value=""
	setTimeout('ExecValue()',3)
}
MTSPlugin.prototype.stream = '';
MTSPlugin.prototype.OutputStream = function() {return this.stream;}
MTSPlugin.prototype.Console=function(m){_mtsConsole(m,this._mtsPID())}
MTSPlugin.prototype.Execute=function(a,b,c,d,e,f){var v,l=arguments.length;if(l==0)v=this._mtsCall();else if(l==1)v=this._mtsCall(a);else if(l==2)v=this._mtsCall(a,b);else if(l==3)v=this._mtsCall(a,b,c);else if(l==4)v=this._mtsCall(a,b,c,d);else if(l==5)v=this._mtsCall(a,b,c,d,e);else if(l==6)v=this._mtsCall(a,b,c,d,e,f);return v}
MTSPlugin.prototype.SetProperty=function(n,p,v,t,o){if(arguments.length==5)return this.Execute("SetProperty",n,p,MTSWrapValue(v),t,o);else return this.Execute("SetProperty",n,p,MTSWrapValue(v),t)}
MTSPlugin.prototype.GetProperty=function(n,p,t){return this.Execute("GetProperty",n,p,t)}
MTSPlugin.prototype.TriggerAnim=function(a){return this.Execute("TriggerAnimation",VET_An(a))}
MTSPlugin.prototype.ReverseAnim=function(a){return this.Execute("ReverseAnimation",VET_An(a))}
MTSPlugin.prototype.StopAnim=function(a){return this.Execute("StopAnimation",VET_An(a))}
MTSPlugin.prototype.StartAnim=function(a){return this.Execute("StartAnimation",VET_An(a))}
MTSPlugin.prototype.ResetAnim=function(a){return this.Execute("ResetAnimation",VET_An(a))}
MTSPlugin.prototype.ToggleCollapse=function(n){this.SetProperty(n,'clps',this.GetProperty(n,'clps')==0?1:0)}
MTSPlugin.prototype.SetCollapsed=function(n,v){return this.SetProperty(VET_In(n),'clps',MTSWrapValue(v),'mts_int')}
MTSPlugin.prototype.ToggleVisible=function(n){this.SetProperty(n,'visb',this.GetProperty(n,'visb')==0?1:0)}
MTSPlugin.prototype.SetVisible=function(n,v){return this.SetProperty(VET_In(n),'visb',MTSWrapValue(v),'mts_int')}
MTSPlugin.prototype.ClearScene=function(){return this.Execute("ClearScene")}
MTSPlugin.prototype.TogglePano=function(n){this.SetProperty('MTSScene','paac',this.GetProperty('MTSScene','paac')==0?1:0)}
MTSPlugin.prototype.Render=function(){return this.Execute("Render")}
MTSPlugin.prototype.LoadMTX=function(p){return this.Execute("LoadMTX",p)}
MTSPlugin.prototype.ResetCamera=function(){this.SetProperty('MTSScene','rstc','0')}
MTSPlugin.prototype.GetVer=function(c){return this.Execute("GetVersion",c)}
MTSPlugin.prototype.GetLastErrCode=function(){return this.Execute("GetLastErrCode")}
MTSPlugin.prototype.GetLastPluginErr=function(t){return this.Execute("GetLastPluginErr",t)}
MTSPlugin.prototype.SetPluginErr=function(t,v){return this.Execute("SetPluginErr",t,v)}
MTSPlugin.prototype.GetAllPluginErrFor=function(t){return this.Execute("GetAllPluginErrFor",t)}
MTSPlugin.prototype.ClearAllPluginErrs=function(t){return this.Execute("ClearAllPluginErrs",t)}
MTSPlugin.prototype.PostEvent=function(n,d){var a=arguments,x=d;for(var i=2;i<a.length;i++)x+=(","+arguments[i]);return this.Execute("PostEvent",n,x)}
function MTSMarkup(tag,c){var a=arguments
	if(a.length==0)return ""
	var i,s="<"+a[0]
	for(var i=2;i<a.length;i+=2){
		if(a[i+1]!=null)s+=(" "+a[i]+"=\'"+a[i+1]+"\'")
		else s+=" "+a[i]
	}
	s+=(c.length?(">"+c+"</"+a[0]+">"):("/>"))
	return s
}
function MTSParm(n,v){return MTSMarkup("param","","name",n,"value",v.toString())}
MTSPlugin.prototype._mtsPID=function(){return this.name}
function _mtsConsole(){if(VET_Dbg!=1)return;var a=arguments;var ct=a.length;if(ct==0)return
	var msg=a[0].toString(),pn=(ct==1)?"Default":((a[1].constructor==MTSPlugin)?a[1].name:a[1].toString())
	if(VET_Mc==0){VET_Mc=window.open("","console","width=700,height=400"+(VET_Mac&&VET_NN4?",":",resizable")+",scrollbars")
		if(!VET_Gecko)VET_Mc.document.write('<title>debug_output<\/title><plaintext>')
		VET_Mc.focus()
	}
	if(!VET_Mc.closed){var s=pn+"> "+msg+"\n"
		if(!VET_Gecko){VET_Mc.document.write(s)}
		else{var re= /</g;s=s.replace(re,"&lt;");re= />/g;s=s.replace(re,"&gt;");VET_Mc.document.write("<pre>"+s+"</pre>")}
	}
}
function VET_OSX_SendCommand(s,h,w){if(!(VET_IE||VET_Gecko))return
	var l=w.length;
	x="";
	o=VET_IE?eval("document.all['OSX_S_"+h+"']"):eval("document.getElementById('OSX_S_"+h+"')")
	for(var i=0;i<l;i++){var c=w.charAt(i)
		switch(c){
			case '\'':x+="`";break
			case '\"':x+="#";break
			case '#':x+="\\#";break
			case '`':x+="\\`";break
			case '\\':x+="\\\\";break
			default:x+=c;break
		}
	}
	o.innerHTML="<embed	Component='SCRIPT' type='application/x-mtx' name='MetaScriptCtl0' width='1' height='1' ScriptCommand='"+h+"_"+s+"_"+x+"' ScriptOutTgt='document.MTS3.mts3_js_jsfield.value' WindowID='"+VET_WindowID+"'>"
	return (document.MTS3 && document.MTS3.mts3_js_jsfield) ? document.MTS3.mts3_js_jsfield.value : "";
}
function VET_An(n){var s='MTSAnimator.';return n.indexOf(s)==0?n:s+n}
function VET_In(n){var s='MTSInstance.';return n.indexOf(s)==0?n:s+n}
MTSPlugin.prototype._mtsCall=function(){var ar=arguments,c=ar.length
	if(++c<2){alert('too little arguments for functions call');return false}
	var rg=ar[0]+'(',l=c-2,i,li=c-1,pn=this._mtsPID()
	for(var i=1;i<li;i++){rg+=ar[i];if(i<l)rg+=','}rg+=')'
	var pID=pn,r,replace= /MetaCtl/i;
	pID=pID.replace(replace,"")
	if(VET_Mac&&(VET_IE||VET_Gecko)){
		if(VET_MacOSX){
			r=VET_OSX_SendCommand(this.sequenceID++,pn,rg)
			if(VET_Dbg==1)MTSConsole(rg,pn)
		}else{var s=("MTS3_JS"+pn+":"+(rg)+";"),x='document.MTS3.mts3_js_jsfield.value=s;'
			eval(x)
			r=document.MTS3.mts3_js_jsfield.value;document.MTS3.mts3_js_jsfield.value=""
			if(VET_Dbg==1)MTSConsole(s)
		}
	}else{var p,d='document.'
		if(VET_Win&&VET_IE)p=d+'all.'+pn+'.PluginCommand(\"'+rg+'\",0,0);'
		else{var p1=d+'embeds.'+pn+'.DoCommand(\"'+rg+'\");'
			if(this.LN==VET_Ln)p=p1
			else{
				if(VET_Gecko)p=p1
				else p=d+this.LN+'.'+p1
			}
		}
		// LEXUS-TAG - custom coded, in firefox, when switching between movies.. 1st time
		// the second movie is shown, which means we are building it.. the DOCommand method
		// is not availible, so we check for this and dont process the method call if it doesn't exist
		var obj;
		if(VET_Win&&VET_IE) {
			obj = true;
		}
		else {
			obj = eval(d+'embeds.'+pn + '.DoCommand');
		}
		if(obj) {
			r=eval(p)
		}
		
		if(VET_Dbg==1)MTSConsole(rg,pn)
	}
	return r
}

function MTSJumpToRedirector(ln) {
	var c,t="var _FS='"
	if (VET_Sdr < 1 || VET_Premium) {
		VET_Sdr++
		c = GetCookie("VETInstallerPopup")
		var inf = (window.location.search.indexOf("noreloadredir") != -1)
		if((c != "" && c.substring(0,10) == "AutoReload") || inf){
			if((c.substring(10,17) == "Premium") || inf) {
				var e = new Date();
				e.setTime(e.getTime() + 30000)
				SetCookie("VETInstallerPopup",("AutoReload; expires=" + e.toGMTString()))
			}
			else ClearCookie("VETInstallerPopup")
			return
		}
		if (VET_Premium) {
			var e = new Date();
			e.setTime(e.getTime() + 30000)
			SetCookie("VETInstallerPopup",("AutoReloadPremium; expires="+e.toGMTString()))
			var p = GetCookie("VETInstallerPopup")
			if (p != "") VET_TopURL = window.location.href
			var trg = VET_Re + VET_IfVer + "&" + (VET_TopURL != "" ? VET_TopURL : window.location.href)
			setTimeout("top.location.href='" + trg + "';", 250);
			return
		}
	}
}

function TriggerJS(){VET_NNtrgr="0"
	if(IsMTSInstalled())return
	var sp="https://components.viewpoint.com/MTSInstallers/MetaStream3.jar"+"?url="+(window.VET_Referrer?window.VET_Referrer:window.location.href),VET_Cv=2
	if(VET_NN4&&VET_Win&&VET_Java){tr=netscape.softupdate.Trigger
		if(tr.UpdateEnabled()){upd=true
			if((mimeType=navigator.mimeTypes[VET_Mim])!=null&&(plugin=mimeType.enabledPlugin)!=null){
				descr_str=String(plugin.description)
				li=descr_str.lastIndexOf("r")
				if(li>=0){vers=parseInt(descr_str.substring(li+1).toString())
					if(!isNaN(vers)&&vers>=VET_Cv)upd=false
				}
			}
			if(upd)tr.StartSoftwareUpdate(sp,tr.DEFAULT_MODE)
		}
	}
}
function VET_Location(js){if(!VET_Gecko)eval(js);else setTimeout(js,100)}
function VET_OpenContent(ur,re,tar,nam,opt){var lo=((re!="")&&(re!="nil"))?re+ur:ur
	if(tar=="_blank")window.open(lo,nam=="nil"?"":nam,opt=="nil"?"":opt)
	else{var x="window.location.href";if(tar!="_top")x=tar;x+=("=%22"+lo+"%22");eval(unescape(x))}
}

		
	var popupExampleWindow;

function infoPopUp(popID, popWidth, popHeight) {

	// calculating the center of the browser window, so that we can center the popup over the window
	var windowWidth = (document.all) ? document.body.offsetWidth : window.innerWidth;
	var windowHeight = (document.all) ? document.body.offsetHeight : window.innerHeight;
	
	var left = Math.round( (windowWidth - popWidth) / 2 ) + "px";
	var top =  Math.round( (windowHeight - popHeight) / 2 ) + "px";

	// close the popup if its already opened
	closeExamplePopup ();

    // opens a new window and sets the object o your popup variable
	popupExampleWindow = window.open(popID+'','_blank','toolbar=no, location=no, directories=no, status=no, menubar=yes, scrollbars=yes, resizable=yes, copyhistory=yes, width='+popWidth+', height='+popHeight + ',top='+top+', left='+left);
	
	// make sure the popup is the focused window

	popupExampleWindow.focus(); 

    // Add events dynamically to the window, that makes sure we close the popup when navigating away from this page

	if (window.addEventListener) {

		window.addEventListener('unload', closeExamplePopup, null);

		} 

	else if (window.attachEvent) {

		window.attachEvent('on' + 'unload', closeExamplePopup);

		}
}


function closeExamplePopup () {

	// We only close the popup if its exists

	if(popupExampleWindow && ! popupExampleWindow.closed) {

		popupExampleWindow.close();
		popupExampleWindow = null;

	}

}

function hdDemoPopUp(popID, popWidth, popHeight) {

	// calculating the center of the browser window, so that we can center the popup over the window
	var windowWidth = (document.all) ? document.body.offsetWidth : window.innerWidth;
	var windowHeight = (document.all) ? document.body.offsetHeight : window.innerHeight;
	
	var left = Math.round( (windowWidth - popWidth) / 2 ) + "px";
	var top =  Math.round( (windowHeight - popHeight) / 2 ) + "px";

	// close the popup if its already opened
	closeExamplePopup ();

    // opens a new window and sets the object o your popup variable
	popupExampleWindow = window.open(popID+'','_blank','toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width='+popWidth+', height='+popHeight + ',top='+top+', left='+left);
	
	// make sure the popup is the focused window

	popupExampleWindow.focus(); 

    // Add events dynamically to the window, that makes sure we close the popup when navigating away from this page

	if (window.addEventListener) {

		window.addEventListener('unload', closeExamplePopup, null);

		} 

	else if (window.attachEvent) {

		window.attachEvent('on' + 'unload', closeExamplePopup);

		}
}


function closeExamplePopup () {

	// We only close the popup if its exists

	if(popupExampleWindow && ! popupExampleWindow.closed) {

		popupExampleWindow.close();
		popupExampleWindow = null;

	}

}

	// Popup Overlay JavaScript Document
/**************** The 4 functions below are performed when the popup layer is open ****************************/
function hidePW(){
 	Popup.close();
}
function initScrollPopupOverlay() {
  // arguments: id of layer containing scrolling layers (clipped layer), id of layer to scroll, 
  // if horizontal scrolling, id of element containing scrolling content (table?)
  var wndo1 = new dw_scrollObj('popupWn', 'popupLyr', null);

  // arguments: dragBar id, track id, axis ("v" or "h"), x offset, y offset
  // (x/y offsets of dragBar in track)
  wndo1.setUpScrollbar("dragBar", "track", "v", 0, 0);

  //dw_showLayers("scrollbar","popupOverlay");
  return wndo1;
}

function swapHdr(pType) { //changes the Header image in the PopupOverlay
	
	if(pType == 'gl') {
		$('popupHeader').className = 'glossaryHdr';
		
	}
	else {
		$('popupHeader').className = pType;
	}
}

var Glossary = new GlossaryLoad(); // A unique function for Glossary definitions
function GlossaryLoad() {
	var obj;
	var def_id;
}
GlossaryLoad.prototype.showGlossary = function (obj, def_id) {
	Popup.showDefinition (obj, def_id, 'gl');
};


function PopupPanel(){ //The generic PopupOverlay function
	
	var element;	//The popup panel root element
	var _cache;	//Cached popup results
	
	var html_is_loaded;	//If the html for the panel had been loaded
	var error_loading_panel;//If the panel cannot be loaded.  Disable popup if true;
	
	var currentID;
	var currentElement;
	
	this.ajaxQueueSingle = new Ajax.Queue(Ajax.Queue.Single, false);
	this.ajaxQueueFifo = new Ajax.Queue(Ajax.Queue.FIFO, true);
	
}

PopupPanel.prototype.loadPanelHTML = function(definition_id, popType){
	
	var onerror = function(){
		this.html_is_loaded = false;
		this.error_loading_panel = true;
	};
	
	var templateAjax = new Ajax.Updater(
		{success: document.body}, 
		'/lexus-share/includes/popup_panel.incl', 
		{ 
			method: 'get',
			onComplete: function() {this.oncomplete()}.bind(this),
			wait: true,
			insertion: Insertion.Bottom,
			onError: onerror.bind(this)
		});
	var glossaryAjax = this.buildAjaxUpdater(definition_id, popType);
	
	this.ajaxQueueFifo.addAction(templateAjax);
	this.ajaxQueueFifo.addAction(glossaryAjax);
	this.ajaxQueueFifo.start();			
};

PopupPanel.prototype.oncomplete = function(){
	this.html_is_loaded = true;
	this.error_loading_panel = false;
	
	this.element = $('popupOverlay');
	
	/* 
	//	These settings will have make the box scroll on hover and scroll twice as fast on click
	Event.observe($('upMover'), 'mouseover', function(){dw_scrollObj.initScroll('popupWn','up')});
	Event.observe($('upMover'), 'mouseout', function(){dw_scrollObj.stopScroll('popupWn','up')});
	Event.observe($('upMover'), 'mousedown', function(){dw_scrollObj.doubleSpeed('popupWn')});
	Event.observe($('upMover'), 'mouseup', function(){dw_scrollObj.resetSpeed('popupWn')});
	
	Event.observe($('downMover'), 'mouseover', function(){dw_scrollObj.initScroll('popupWn','down')});
	Event.observe($('downMover'), 'mouseout', function(){dw_scrollObj.stopScroll('popupWn','down')});
	Event.observe($('downMover'), 'mousedown', function(){dw_scrollObj.doubleSpeed('popupWn')});
	Event.observe($('downMover'), 'mouseup', function(){dw_scrollObj.resetSpeed('popupWn')});
	*/
	
	//	These settings will make the box scroll only when clicked
	Event.observe($('upMover'), 'mousedown', function(){dw_scrollObj.initScroll('popupWn','up')});
	Event.observe($('upMover'), 'mouseup', function(){dw_scrollObj.stopScroll('popupWn','up')});
	
	Event.observe($('downMover'), 'mousedown', function(){dw_scrollObj.initScroll('popupWn','down')});
	Event.observe($('downMover'), 'mouseup', function(){dw_scrollObj.stopScroll('popupWn','down')});

	
	Event.observe(window, 'keypress', function(event){if(event.keyCode == Event.KEY_ESC) hidePW();}.bindAsEventListener(this));

};
PopupPanel.prototype.showDefinition = function(element, definition_id, popType,dontMove){
	this.dont_move = (dontMove==1)?true:false;
	this.currentType = popType;
	this.currentElement = element;
	
	if(!PAGE_LOAD) {
		return;
	}
	
	if(this.html_is_loaded){
		this.ajaxQueueSingle.addAction(this.buildAjaxUpdater(definition_id, popType));
		this.ajaxQueueSingle.start();	
	}
	else {
		this.loadPanelHTML(definition_id, popType);
	}
	
	this.destroyScrollEvents();
	this.setupScrollEvents();
};

PopupPanel.prototype.close = function(){
  if(!$('popupOverlay')) {
  	return;
  }
  $('popupOverlay').style.display = 'none';
  $('popupOverlay').style.visibility = 'hidden'; 
  this.destroyScrollEvents();
}

PopupPanel.prototype.buildAjaxUpdater = function(definition_id, popType) {
	if (popType != 'gl') {
			var defURL = '/lexus-share/includes/' + definition_id.toLowerCase() + '.incl'
	}
	else { 
		var defURL = '/lexus-share/includes/glossary/' + definition_id.toUpperCase() + '.incl' 
	}
	
	return new Ajax.Updater(
		{success: 'popupLyr'},
		defURL, 
		{ 
			method: 'get',
			wait: true,
			onComplete: function() {this.preparePopupOvlay()}.bind(this)
		});
};
PopupPanel.prototype.preparePopupOvlay = function() {
	swapHdr(this.currentType);
	if(!this.dont_move){
		this.reposition(this.currentElement);
	}
	initScrollPopupOverlay();
		//Fix IE drawing problems by forcing it to redraw this element
		this.element.style.display = 'none';
		this.element.style.display = 'block';
};

PopupPanel.prototype.setupScrollEvents = function(){
	if(!this.scroll_events){
		var scroll_event = Event.observe(window, 'scroll', function(){this.reposition(this.currentElement)}.bind(this));
		var resize_event = Event.observe(window, 'resize', function(){this.reposition(this.currentElement)}.bind(this));
		this.scroll_events = [scroll_event, resize_event];
	}
};

PopupPanel.prototype.destroyScrollEvents = function(){
	if(this.scroll_events){
		Event.stopObserving(this.scroll_events[0]);
		Event.stopObserving(this.scroll_events[1]);
		this.scroll_events = false;
	}
};

PopupPanel.prototype.reposition = function(element){

	$('popupOverlay').style.display = 'block';
	var left = Position.cumulativeOffset(element)[0];
	var top = Position.cumulativeOffset(element)[1];
	var leftpos = (left - (this.element.offsetWidth / 2 ) - 5);
	var toppos = (top - (this.element.offsetHeight));
	
	var scrollX = (document.all)?document.documentElement.scrollLeft:window.pageXOffset;
	var scrollY = (document.all)?document.documentElement.scrollTop:window.pageYOffset;
	var window_width = (document.all)?document.documentElement.clientWidth:window.innerWidth;
	
	if(leftpos + this.element.offsetWidth >= (window_width + scrollX)){
		leftpos = ((window_width + scrollX) - this.element.offsetWidth) - 15;
	}
	
	$('popupOverlay').style.left = (leftpos > scrollX ? leftpos : scrollX) + 'px';
	$('popupOverlay').style.top = (toppos > scrollY ? toppos : scrollY) + 'px';
	
	// Initially hidden
	$('popupOverlay').style.visibility = 'visible';
};

var Popup = new PopupPanel();
