text: /**
   * @license @product.name@ JS v@product.version@ (@product.date@)
   * Prototype adapter
   *
   * @author Michael Nelson, Torstein Hønsi.
   *
   * Feel free to use and modify this script.
   * Highcharts license: www.highcharts.com/license.
   */
  
  // JSLint options:
  /*global Effect, Class, Event, Element, $, $$, $A */
  
  // Adapter interface between prototype and the Highcharts charting library
  var HighchartsAdapter = (function () {
  
  var hasEffect = typeof Effect !== 'undefined';
  
  return {
  
  	/**
  	 * Initialize the adapter. This is run once as Highcharts is first run.
  	 * @param {Object} pathAnim The helper object to do animations across adapters.
  	 */
  	init: function (pathAnim) {
  		if (hasEffect) {
  			/**
  			 * Animation for Highcharts SVG element wrappers only
  			 * @param {Object} element
  			 * @param {Object} attribute
  			 * @param {Object} to
  			 * @param {Object} options
  			 */
  			Effect.HighchartsTransition = Class.create(Effect.Base, {
  				initialize: function (element, attr, to, options) {
  					var from,
  						opts;
  
  					this.element = element;
  					this.key = attr;
  					from = element.attr ? element.attr(attr) : $(element).getStyle(attr);
  
  					// special treatment for paths
  					if (attr === 'd') {
  						this.paths = pathAnim.init(
  							element,
  							element.d,
  							to
  						);
  						this.toD = to;
  
  
  						// fake values in order to read relative position as a float in update
  						from = 0;
  						to = 1;
  					}
  
  					opts = Object.extend((options || {}), {
  						from: from,
  						to: to,
  						attribute: attr
  					});
  					this.start(opts);
  				},
  				setup: function () {
  					HighchartsAdapter._extend(this.element);
  					// If this is the first animation on this object, create the _highcharts_animation helper that
  					// contain pointers to the animation objects.
  					if (!this.element._highchart_animation) {
  						this.element._highchart_animation = {};
  					}
  
  					// Store a reference to this animation instance.
  					this.element._highchart_animation[this.key] = this;
  				},
  				update: function (position) {
  					var paths = this.paths,
  						element = this.element,
  						obj;
  
  					if (paths) {
  						position = pathAnim.step(paths[0], paths[1], position, this.toD);
  					}
  
  					if (element.attr) { // SVGElement
  						
  						if (element.element) { // If not, it has been destroyed (#1405)
  							element.attr(this.options.attribute, position);
  						}
  					
  					} else { // HTML, #409
  						obj = {};
  						obj[this.options.attribute] = position;
  						$(element).setStyle(obj);
  					}
  					
  				},
  				finish: function () {
  					// Delete the property that holds this animation now that it is finished.
  					// Both canceled animations and complete ones gets a 'finish' call.
  					if (this.element && this.element._highchart_animation) { // #1405
  						delete this.element._highchart_animation[this.key];
  					}
  				}
  			});
  		}
  	},
  	
  	/**
  	 * Run a general method on the framework, following jQuery syntax
  	 * @param {Object} el The HTML element
  	 * @param {String} method Which method to run on the wrapped element
  	 */
  	adapterRun: function (el, method) {
  		
  		// This currently works for getting inner width and height. If adding
  		// more methods later, we need a conditional implementation for each.
  		return parseInt($(el).getStyle(method), 10);
  		
  	},
  
  	/**
  	 * Downloads a script and executes a callback when done.
  	 * @param {String} scriptLocation
  	 * @param {Function} callback
  	 */
  	getScript: function (scriptLocation, callback) {
  		var head = $$('head')[0]; // Returns an array, so pick the first element.
  		if (head) {
  			// Append a new 'script' element, set its type and src attributes, add a 'load' handler that calls the callback
  			head.appendChild(new Element('script', { type: 'text/javascript', src: scriptLocation}).observe('load', callback));
  		}
  	},
  
  	/**
  	 * Custom events in prototype needs to be namespaced. This method adds a namespace 'h:' in front of
  	 * events that are not recognized as native.
  	 */
  	addNS: function (eventName) {
  		var HTMLEvents = /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,
  			MouseEvents = /^(?:click|mouse(?:down|up|over|move|out))$/;
  		return (HTMLEvents.test(eventName) || MouseEvents.test(eventName)) ?
  			eventName :
  			'h:' + eventName;
  	},
  
  	// el needs an event to be attached. el is not necessarily a dom element
  	addEvent: function (el, event, fn) {
  		if (el.addEventListener || el.attachEvent) {
  			Event.observe($(el), HighchartsAdapter.addNS(event), fn);
  
  		} else {
  			HighchartsAdapter._extend(el);
  			el._highcharts_observe(event, fn);
  		}
  	},
  
  	// motion makes things pretty. use it if effects is loaded, if not... still get to the end result.
  	animate: function (el, params, options) {
  		var key,
  			fx;
  
  		// default options
  		options = options || {};
  		options.delay = 0;
  		options.duration = (options.duration || 500) / 1000;
  		options.afterFinish = options.complete;
  
  		// animate wrappers and DOM elements
  		if (hasEffect) {
  			for (key in params) {
  				// The fx variable is seemingly thrown away here, but the Effect.setup will add itself to the _highcharts_animation object
  				// on the element itself so its not really lost.
  				fx = new Effect.HighchartsTransition($(el), key, params[key], options);
  			}
  		} else {
  			if (el.attr) { // #409 without effects
  				for (key in params) {
  					el.attr(key, params[key]);
  				}
  			}
  			if (options.complete) {
  				options.complete();
  			}
  		}
  
  		if (!el.attr) { // HTML element, #409
  			$(el).setStyle(params);
  		}
  	},
  
  	// this only occurs in higcharts 2.0+
  	stop: function (el) {
  		var key;
  		if (el._highcharts_extended && el._highchart_animation) {
  			for (key in el._highchart_animation) {
  				// Cancel the animation
  				// The 'finish' function in the Effect object will remove the reference
  				el._highchart_animation[key].cancel();
  			}
  		}
  	},
  
  	// um.. each
  	each: function (arr, fn) {
  		$A(arr).each(fn);
  	},
  	
  	inArray: function (item, arr) {
  		return arr.indexOf(item);
  	},
  
  	/**
  	 * Get the cumulative offset relative to the top left of the page. This method, unlike its
  	 * jQuery and MooTools counterpart, still suffers from issue #208 regarding the position
  	 * of a chart within a fixed container.
  	 */
  	offset: function (el) {
  		return $(el).cumulativeOffset();
  	},
  
  	// fire an event based on an event name (event) and an object (el).
  	// again, el may not be a dom element
  	fireEvent: function (el, event, eventArguments, defaultFunction) {
  		if (el.fire) {
  			el.fire(HighchartsAdapter.addNS(event), eventArguments);
  		} else if (el._highcharts_extended) {
  			eventArguments = eventArguments || {};
  			el._highcharts_fire(event, eventArguments);
  		}
  
  		if (eventArguments && eventArguments.defaultPrevented) {
  			defaultFunction = null;
  		}
  
  		if (defaultFunction) {
  			defaultFunction(eventArguments);
  		}
  	},
  
  	removeEvent: function (el, event, handler) {
  		if ($(el).stopObserving) {
  			if (event) {
  				event = HighchartsAdapter.addNS(event);
  			}
  			$(el).stopObserving(event, handler);
  		} if (window === el) {
  			Event.stopObserving(el, event, handler);
  		} else {
  			HighchartsAdapter._extend(el);
  			el._highcharts_stop_observing(event, handler);
  		}
  	},
  	
  	washMouseEvent: function (e) {
  		return e;
  	},
  
  	// um, grep
  	grep: function (arr, fn) {
  		return arr.findAll(fn);
  	},
  
  	// um, map
  	map: function (arr, fn) {
  		return arr.map(fn);
  	},
  
  	// extend an object to handle highchart events (highchart objects, not svg elements).
  	// this is a very simple way of handling events but whatever, it works (i think)
  	_extend: function (object) {
  		if (!object._highcharts_extended) {
  			Object.extend(object, {
  				_highchart_events: {},
  				_highchart_animation: null,
  				_highcharts_extended: true,
  				_highcharts_observe: function (name, fn) {
  					this._highchart_events[name] = [this._highchart_events[name], fn].compact().flatten();
  				},
  				_highcharts_stop_observing: function (name, fn) {
  					if (name) {
  						if (fn) {
  							this._highchart_events[name] = [this._highchart_events[name]].compact().flatten().without(fn);
  						} else {
  							delete this._highchart_events[name];
  						}
  					} else {
  						this._highchart_events = {};
  					}
  				},
  				_highcharts_fire: function (name, args) {
  					var target = this;
  					(this._highchart_events[name] || []).each(function (fn) {
  						// args is never null here
  						if (args.stopped) {
  							return; // "throw $break" wasn't working. i think because of the scope of 'this'.
  						}
  
  						// Attach a simple preventDefault function to skip default handler if called
  						args.preventDefault = function () {
  							args.defaultPrevented = true;
  						};
  						args.target = target;
  
  						// If the event handler return false, prevent the default handler from executing
  						if (fn.bind(this)(args) === false) {
  							args.preventDefault();
  						}
  					}
  .bind(this));
  				}
  			});
  		}
  	}
  };
  }());
  