text: /**
   * @license Highcharts JS v2.1.7 (2011-10-19)
   * Exporting module
   *
   * (c) 2010-2011 Torstein Hønsi
   *
   * License: www.highcharts.com/license
   */
  
  // JSLint options:
  /*global Highcharts, document, window, Math, setTimeout */
  
  (function () { // encapsulate
  
  // create shortcuts
  var HC = Highcharts,
  	Chart = HC.Chart,
  	addEvent = HC.addEvent,
  	createElement = HC.createElement,
  	discardElement = HC.discardElement,
  	css = HC.css,
  	merge = HC.merge,
  	each = HC.each,
  	extend = HC.extend,
  	math = Math,
  	mathMax = math.max,
  	doc = document,
  	win = window,
  	hasTouch = doc.documentElement.ontouchstart !== undefined,
  	M = 'M',
  	L = 'L',
  	DIV = 'div',
  	HIDDEN = 'hidden',
  	NONE = 'none',
  	PREFIX = 'highcharts-',
  	ABSOLUTE = 'absolute',
  	PX = 'px',
  	UNDEFINED,
  	defaultOptions = HC.getOptions();
  
  	// Add language
  	extend(defaultOptions.lang, {
  		downloadPNG: 'Download PNG image',
  		downloadJPEG: 'Download JPEG image',
  		downloadPDF: 'Download PDF document',
  		downloadSVG: 'Download SVG vector image',
  		exportButtonTitle: 'Export to raster or vector image',
  		printButtonTitle: 'Print the chart'
  	});
  
  // Buttons and menus are collected in a separate config option set called 'navigation'.
  // This can be extended later to add control buttons like zoom and pan right click menus.
  defaultOptions.navigation = {
  	menuStyle: {
  		border: '1px solid #A0A0A0',
  		background: '#FFFFFF'
  	},
  	menuItemStyle: {
  		padding: '0 5px',
  		background: NONE,
  		color: '#303030',
  		fontSize: hasTouch ? '14px' : '11px'
  	},
  	menuItemHoverStyle: {
  		background: '#4572A5',
  		color: '#FFFFFF'
  	},
  
  	buttonOptions: {
  		align: 'right',
  		backgroundColor: {
  			linearGradient: [0, 0, 0, 20],
  			stops: [
  				[0.4, '#F7F7F7'],
  				[0.6, '#E3E3E3']
  			]
  		},
  		borderColor: '#B0B0B0',
  		borderRadius: 3,
  		borderWidth: 1,
  		//enabled: true,
  		height: 20,
  		hoverBorderColor: '#909090',
  		hoverSymbolFill: '#81A7CF',
  		hoverSymbolStroke: '#4572A5',
  		symbolFill: '#E0E0E0',
  		//symbolSize: 12,
  		symbolStroke: '#A0A0A0',
  		//symbolStrokeWidth: 1,
  		symbolX: 11.5,
  		symbolY: 10.5,
  		verticalAlign: 'top',
  		width: 24,
  		y: 10
  	}
  };
  
  
  
  // Add the export related options
  defaultOptions.exporting = {
  	//enabled: true,
  	//filename: 'chart',
  	type: 'image/png',
  	url: 'http://export.highcharts.com/',
  	width: 800,
  	enableImages: false,
  	buttons: {
  		exportButton: {
  			//enabled: true,
  			symbol: 'exportIcon',
  			x: -10,
  			symbolFill: '#A8BF77',
  			hoverSymbolFill: '#768F3E',
  			_id: 'exportButton',
  			_titleKey: 'exportButtonTitle',
  			menuItems: [{
  				textKey: 'downloadPNG',
  				onclick: function () {
  					this.exportChart();
  				}
  			}, {
  				textKey: 'downloadJPEG',
  				onclick: function () {
  					this.exportChart({
  						type: 'image/jpeg'
  					});
  				}
  			}, {
  				textKey: 'downloadPDF',
  				onclick: function () {
  					this.exportChart({
  						type: 'application/pdf'
  					});
  				}
  			}, {
  				textKey: 'downloadSVG',
  				onclick: function () {
  					this.exportChart({
  						type: 'image/svg+xml'
  					});
  				}
  			}/*, {
  				text: 'View SVG',
  				onclick: function() {
  					var svg = this.getSVG()
  						.replace(/</g, '\n&lt;')
  						.replace(/>/g, '&gt;');
  
  					doc.body.innerHTML = '<pre>'+ svg +'</pre>';
  				}
  			}*/]
  
  		},
  		printButton: {
  			//enabled: true,
  			symbol: 'printIcon',
  			x: -36,
  			symbolFill: '#B5C9DF',
  			hoverSymbolFill: '#779ABF',
  			_id: 'printButton',
  			_titleKey: 'printButtonTitle',
  			onclick: function () {
  				this.print();
  			}
  		}
  	}
  };
  
  
  
  extend(Chart.prototype, {
  	/**
  	 * Return an SVG representation of the chart
  	 *
  	 * @param additionalOptions {Object} Additional chart options for the generated SVG representation
  	 */
  	getSVG: function (additionalOptions) {
  		var chart = this,
  			chartCopy,
  			sandbox,
  			svg,
  			seriesOptions,
  			config,
  			pointOptions,
  			pointMarker,
  			options = merge(chart.options, additionalOptions); // copy the options and add extra options
  
  		// IE compatibility hack for generating SVG content that it doesn't really understand
  		if (!doc.createElementNS) {
  			/*jslint unparam: true*//* allow unused parameter ns in function below */
  			doc.createElementNS = function (ns, tagName) {
  				var elem = doc.createElement(tagName);
  				elem.getBBox = function () {
  					return HC.Renderer.prototype.Element.prototype.getBBox.apply({ element: elem });
  				};
  				return elem;
  			};
  			/*jslint unparam: false*/
  		}
  
  		// create a sandbox where a new chart will be generated
  		sandbox = createElement(DIV, null, {
  			position: ABSOLUTE,
  			top: '-9999em',
  			width: chart.chartWidth + PX,
  			height: chart.chartHeight + PX
  		}, doc.body);
  
  		// override some options
  		extend(options.chart, {
  			renderTo: sandbox,
  			forExport: true
  		});
  		options.exporting.enabled = false; // hide buttons in print
  
  		if (!options.exporting.enableImages) {
  			options.chart.plotBackgroundImage = null; // the converter doesn't handle images
  		}
  
  		// prepare for replicating the chart
  		options.series = [];
  		each(chart.series, function (serie) {
  			seriesOptions = serie.options;
  
  			seriesOptions.animation = false; // turn off animation
  			seriesOptions.showCheckbox = false;
  			seriesOptions.visible = serie.visible;
  
  			if (!options.exporting.enableImages) {
  				// remove image markers
  				if (seriesOptions && seriesOptions.marker && /^url\(/.test(seriesOptions.marker.symbol)) {
  					seriesOptions.marker.symbol = 'circle';
  				}
  			}
  
  			seriesOptions.data = [];
  
  			each(serie.data, function (point) {
  
  				// extend the options by those values that can be expressed in a number or array config
  				config = point.config;
  				pointOptions = {
  					x: point.x,
  					y: point.y,
  					name: point.name
  				};
  
  				if (typeof config === 'object' && point.config && config.constructor !== Array) {
  					extend(pointOptions, config);
  				}
  
  				pointOptions.visible = point.visible;
  				seriesOptions.data.push(pointOptions); // copy fresh updated data
  
  				if (!options.exporting.enableImages) {
  					// remove image markers
  					pointMarker = point.config && point.config.marker;
  					if (pointMarker && /^url\(/.test(pointMarker.symbol)) {
  						delete pointMarker.symbol;
  					}
  				}
  			});
  
  			options.series.push(seriesOptions);
  		});
  
  		// generate the chart copy
  		chartCopy = new Highcharts.Chart(options);
  
  		// reflect axis extremes in the export
  		each(['xAxis', 'yAxis'], function (axisType) {
  			each(chart[axisType], function (axis, i) {
  				var axisCopy = chartCopy[axisType][i],
  					extremes = axis.getExtremes(),
  					userMin = extremes.userMin,
  					userMax = extremes.userMax;
  
  				if (userMin !== UNDEFINED || userMax !== UNDEFINED) {
  					axisCopy.setExtremes(userMin, userMax, true, false);
  				}
  			});
  		});
  
  		// get the SVG from the container's innerHTML
  		svg = chartCopy.container.innerHTML;
  
  		// free up memory
  		options = null;
  		chartCopy.destroy();
  		discardElement(sandbox);
  
  		// sanitize
  		svg = svg
  			.replace(/zIndex="[^"]+"/g, '')
  			.replace(/isShadow="[^"]+"/g, '')
  			.replace(/symbolName="[^"]+"/g, '')
  			.replace(/jQuery[0-9]+="[^"]+"/g, '')
  			.replace(/isTracker="[^"]+"/g, '')
  			.replace(/url\([^#]+#/g, 'url(#')
  			.replace(/<svg /, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
  			.replace(/ href=/g, ' xlink:href=')
  			/*.replace(/preserveAspectRatio="none">/g, 'preserveAspectRatio="none"/>')*/
  			/* This fails in IE < 8
  			.replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight
  				return s2 +'.'+ s3[0];
  			})*/
  
  			// Replace HTML entities, issue #347
  			.replace(/&nbsp;/g, '\u00A0') // no-break space
  			.replace(/&shy;/g,  '\u00AD') // soft hyphen
  
  			// IE specific
  			.replace(/id=([^" >]+)/g, 'id="$1"')
  			.replace(/class=([^" ]+)/g, 'class="$1"')
  			.replace(/ transform /g, ' ')
  			.replace(/:(path|rect)/g, '$1')
  			.replace(/<img ([^>]*)>/gi, '<image $1 />')
  			.replace(/<\/image>/g, '') // remove closing tags for images as they'll never have any content
  			.replace(/<image ([^>]*)([^\/])>/gi, '<image $1$2 />') // closes image tags for firefox
  			.replace(/width=(\d+)/g, 'width="$1"')
  			.replace(/height=(\d+)/g, 'height="$1"')
  			.replace(/hc-svg-href="/g, 'xlink:href="')
  			.replace(/style="([^"]+)"/g, function (s) {
  				return s.toLowerCase();
  			});
  
  		// IE9 beta bugs with innerHTML. Test again with final IE9.
  		svg = svg.replace(/(url\(#highcharts-[0-9]+)&quot;/g, '$1')
  			.replace(/&quot;/g, "'");
  		if (svg.match(/ xmlns="/g).length === 2) {
  			svg = svg.replace(/xmlns="[^"]+"/, '');
  		}
  
  		return svg;
  	},
  
  	/**
  	 * Submit the SVG representation of the chart to the server
  	 * @param {Object} options Exporting options. Possible members are url, type and width.
  	 * @param {Object} chartOptions Additional chart options for the SVG representation of the chart
  	 */
  	exportChart: function (options, chartOptions) {
  		var form,
  			chart = this,
  			svg = chart.getSVG(chartOptions);
  
  		// merge the options
  		options = merge(chart.options.exporting, options);
  
  		// create the form
  		form = createElement('form', {
  			method: 'post',
  			action: options.url
  		}, {
  			display: NONE
  		}, doc.body);
  
  		// add the values
  		each(['filename', 'type', 'width', 'svg'], function (name) {
  			createElement('input', {
  				type: HIDDEN,
  				name: name,
  				value: {
  					filename: options.filename || 'chart',
  					type: options.type,
  					width: options.width,
  					svg: svg
  				}[name]
  			}, null, form);
  		});
  
  		// submit
  		form.submit();
  
  		// clean up
  		discardElement(form);
  	},
  
  	/**
  	 * Print the chart
  	 */
  	print: function () {
  
  		var chart = this,
  			container = chart.container,
  			origDisplay = [],
  			origParent = container.parentNode,
  			body = doc.body,
  			childNodes = body.childNodes;
  
  		if (chart.isPrinting) { // block the button while in printing mode
  			return;
  		}
  
  		chart.isPrinting = true;
  
  		// hide all body content
  		each(childNodes, function (node, i) {
  			if (node.nodeType === 1) {
  				origDisplay[i] = node.style.display;
  				node.style.display = NONE;
  			}
  		});
  
  		// pull out the chart
  		body.appendChild(container);
  
  		// print
  		win.print();
  
  		// allow the browser to prepare before reverting
  		setTimeout(function () {
  
  			// put the chart back in
  			origParent.appendChild(container);
  
  			// restore all body content
  			each(childNodes, function (node, i) {
  				if (node.nodeType === 1) {
  					node.style.display = origDisplay[i];
  				}
  			});
  
  			chart.isPrinting = false;
  
  		}, 1000);
  
  	},
  
  	/**
  	 * Display a popup menu for choosing the export type
  	 *
  	 * @param {String} name An identifier for the menu
  	 * @param {Array} items A collection with text and onclicks for the items
  	 * @param {Number} x The x position of the opener button
  	 * @param {Number} y The y position of the opener button
  	 * @param {Number} width The width of the opener button
  	 * @param {Number} height The height of the opener button
  	 */
  	contextMenu: function (name, items, x, y, width, height) {
  		var chart = this,
  			navOptions = chart.options.navigation,
  			menuItemStyle = navOptions.menuItemStyle,
  			chartWidth = chart.chartWidth,
  			chartHeight = chart.chartHeight,
  			cacheName = 'cache-' + name,
  			menu = chart[cacheName],
  			menuPadding = mathMax(width, height), // for mouse leave detection
  			boxShadow = '3px 3px 10px #888',
  			innerMenu,
  			hide,
  			menuStyle;
  
  		// create the menu only the first time
  		if (!menu) {
  
  			// create a HTML element above the SVG
  			chart[cacheName] = menu = createElement(DIV, {
  				className: PREFIX + name
  			}, {
  				position: ABSOLUTE,
  				zIndex: 1000,
  				padding: menuPadding + PX
  			}, chart.container);
  
  			innerMenu = createElement(DIV, null,
  				extend({
  					MozBoxShadow: boxShadow,
  					WebkitBoxShadow: boxShadow,
  					boxShadow: boxShadow
  				}, navOptions.menuStyle), menu);
  
  			// hide on mouse out
  			hide = function () {
  				css(menu, { display: NONE });
  			};
  
  			addEvent(menu, 'mouseleave', hide);
  
  
  			// create the items
  			each(items, function (item) {
  				if (item) {
  					var div = createElement(DIV, {
  						onmouseover: function () {
  							css(this, navOptions.menuItemHoverStyle);
  						},
  						onmouseout: function () {
  							css(this, menuItemStyle);
  						},
  						innerHTML: item.text || chart.options.lang[item.textKey]
  					}, extend({
  						cursor: 'pointer'
  					}, menuItemStyle), innerMenu);
  
  					div[hasTouch ? 'ontouchstart' : 'onclick'] = function () {
  						hide();
  						item.onclick.apply(chart, arguments);
  					};
  
  				}
  			});
  
  			chart.exportMenuWidth = menu.offsetWidth;
  			chart.exportMenuHeight = menu.offsetHeight;
  		}
  
  		menuStyle = { display: 'block' };
  
  		// if outside right, right align it
  		if (x + chart.exportMenuWidth > chartWidth) {
  			menuStyle.right = (chartWidth - x - width - menuPadding) + PX;
  		} else {
  			menuStyle.left = (x - menuPadding) + PX;
  		}
  		// if outside bottom, bottom align it
  		if (y + height + chart.exportMenuHeight > chartHeight) {
  			menuStyle.bottom = (chartHeight - y - menuPadding)  + PX;
  		} else {
  			menuStyle.top = (y + height - menuPadding) + PX;
  		}
  
  		css(menu, menuStyle);
  	},
  
  	/**
  	 * Add the export button to the chart
  	 */
  	addButton: function (options) {
  		var chart = this,
  			renderer = chart.renderer,
  			btnOptions = merge(chart.options.navigation.buttonOptions, options),
  			onclick = btnOptions.onclick,
  			menuItems = btnOptions.menuItems,
  			/*position = chart.getAlignment(btnOptions),
  			buttonLeft = position.x,
  			buttonTop = position.y,*/
  			buttonWidth = btnOptions.width,
  			buttonHeight = btnOptions.height,
  			box,
  			symbol,
  			button,
  			borderWidth = btnOptions.borderWidth,
  			boxAttr = {
  				stroke: btnOptions.borderColor
  
  			},
  			symbolAttr = {
  				stroke: btnOptions.symbolStroke,
  				fill: btnOptions.symbolFill
  			};
  
  		if (btnOptions.enabled === false) {
  			return;
  		}
  
  		// element to capture the click
  		function revert() {
  			symbol.attr(symbolAttr);
  			box.attr(boxAttr);
  		}
  
  		// the box border
  		box = renderer.rect(
  			0,
  			0,
  			buttonWidth,
  			buttonHeight,
  			btnOptions.borderRadius,
  			borderWidth
  		)
  		//.translate(buttonLeft, buttonTop) // to allow gradients
  		.align(btnOptions, true)
  		.attr(extend({
  			fill: btnOptions.backgroundColor,
  			'stroke-width': borderWidth,
  			zIndex: 19
  		}, boxAttr)).add();
  
  		// the invisible element to track the clicks
  		button = renderer.rect(
  				0,
  				0,
  				buttonWidth,
  				buttonHeight,
  				0
  			)
  			.align(btnOptions)
  			.attr({
  				id: btnOptions._id,
  				fill: 'rgba(255, 255, 255, 0.001)',
  				title: chart.options.lang[btnOptions._titleKey],
  				zIndex: 21
  			}).css({
  				cursor: 'pointer'
  			})
  			.on('mouseover', function () {
  				symbol.attr({
  					stroke: btnOptions.hoverSymbolStroke,
  					fill: btnOptions.hoverSymbolFill
  				});
  				box.attr({
  					stroke: btnOptions.hoverBorderColor
  				});
  			})
  			.on('mouseout', revert)
  			.on('click', revert)
  			.add();
  
  		//addEvent(button.element, 'click', revert);
  
  		// add the click event
  		if (menuItems) {
  			onclick = function () {
  				revert();
  				var bBox = button.getBBox();
  				chart.contextMenu('export-menu', menuItems, bBox.x, bBox.y, buttonWidth, buttonHeight);
  			};
  		}
  		/*addEvent(button.element, 'click', function() {
  			onclick.apply(chart, arguments);
  		});*/
  		button.on('click', function () {
  			onclick.apply(chart, arguments);
  		});
  
  		// the icon
  		symbol = renderer.symbol(
  				btnOptions.symbol,
  				btnOptions.symbolX,
  				btnOptions.symbolY,
  				(btnOptions.symbolSize || 12) / 2
  			)
  			.align(btnOptions, true)
  			.attr(extend(symbolAttr, {
  				'stroke-width': btnOptions.symbolStrokeWidth || 1,
  				zIndex: 20
  			})).add();
  
  
  
  	}
  });
  
  // Create the export icon
  HC.Renderer.prototype.symbols.exportIcon = function (x, y, radius) {
  	return [
  		M, // the disk
  		x - radius, y + radius,
  		L,
  		x + radius, y + radius,
  		x + radius, y + radius * 0.5,
  		x - radius, y + radius * 0.5,
  		'Z',
  		M, // the arrow
  		x, y + radius * 0.5,
  		L,
  		x - radius * 0.5, y - radius / 3,
  		x - radius / 6, y - radius / 3,
  		x - radius / 6, y - radius,
  		x + radius / 6, y - radius,
  		x + radius / 6, y - radius / 3,
  		x + radius * 0.5, y - radius / 3,
  		'Z'
  	];
  };
  // Create the print icon
  HC.Renderer.prototype.symbols.printIcon = function (x, y, radius) {
  	return [
  		M, // the printer
  		x - radius, y + radius * 0.5,
  		L,
  		x + radius, y + radius * 0.5,
  		x + radius, y - radius / 3,
  		x - radius, y - radius / 3,
  		'Z',
  		M, // the upper sheet
  		x - radius * 0.5, y - radius / 3,
  		L,
  		x - radius * 0.5, y - radius,
  		x + radius * 0.5, y - radius,
  		x + radius * 0.5, y - radius / 3,
  		'Z',
  		M, // the lower sheet
  		x - radius * 0.5, y + radius * 0.5,
  		L,
  		x - radius * 0.75, y + radius,
  		x + radius * 0.75, y + radius,
  		x + radius * 0.5, y + radius * 0.5,
  		'Z'
  	];
  };
  
  
  // Add the buttons on chart load
  Chart.prototype.callbacks.push(function (chart) {
  	var n,
  		exportingOptions = chart.options.exporting,
  		buttons = exportingOptions.buttons;
  
  	if (exportingOptions.enabled !== false) {
  
  		for (n in buttons) {
  			chart.addButton(buttons[n]);
  		}
  	}
  });
  
  
  }());
  