text: 'use strict';
  
  /**
   * @namespace Chart.helpers
   */
  var helpers = {
  	/**
  	 * An empty function that can be used, for example, for optional callback.
  	 */
  	noop: function() {},
  
  	/**
  	 * Returns a unique id, sequentially generated from a global variable.
  	 * @returns {Number}
  	 * @function
  	 */
  	uid: (function() {
  		var id = 0;
  		return function() {
  			return id++;
  		};
  	}()),
  
  	/**
  	 * Returns true if `value` is neither null nor undefined, else returns false.
  	 * @param {*} value - The value to test.
  	 * @returns {Boolean}
  	 * @since 2.7.0
  	 */
  	isNullOrUndef: function(value) {
  		return value === null || typeof value === 'undefined';
  	},
  
  	/**
  	 * Returns true if `value` is an array, else returns false.
  	 * @param {*} value - The value to test.
  	 * @returns {Boolean}
  	 * @function
  	 */
  	isArray: Array.isArray ? Array.isArray : function(value) {
  		return Object.prototype.toString.call(value) === '[object Array]';
  	},
  
  	/**
  	 * Returns true if `value` is an object (excluding null), else returns false.
  	 * @param {*} value - The value to test.
  	 * @returns {Boolean}
  	 * @since 2.7.0
  	 */
  	isObject: function(value) {
  		return value !== null && Object.prototype.toString.call(value) === '[object Object]';
  	},
  
  	/**
  	 * Returns `value` if defined, else returns `defaultValue`.
  	 * @param {*} value - The value to return if defined.
  	 * @param {*} defaultValue - The value to return if `value` is undefined.
  	 * @returns {*}
  	 */
  	valueOrDefault: function(value, defaultValue) {
  		return typeof value === 'undefined' ? defaultValue : value;
  	},
  
  	/**
  	 * Returns value at the given `index` in array if defined, else returns `defaultValue`.
  	 * @param {Array} value - The array to lookup for value at `index`.
  	 * @param {Number} index - The index in `value` to lookup for value.
  	 * @param {*} defaultValue - The value to return if `value[index]` is undefined.
  	 * @returns {*}
  	 */
  	valueAtIndexOrDefault: function(value, index, defaultValue) {
  		return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);
  	},
  
  	/**
  	 * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
  	 * value returned by `fn`. If `fn` is not a function, this method returns undefined.
  	 * @param {Function} fn - The function to call.
  	 * @param {Array|undefined|null} args - The arguments with which `fn` should be called.
  	 * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
  	 * @returns {*}
  	 */
  	callback: function(fn, args, thisArg) {
  		if (fn && typeof fn.call === 'function') {
  			return fn.apply(thisArg, args);
  		}
  	},
  
  	/**
  	 * Note(SB) for performance sake, this method should only be used when loopable type
  	 * is unknown or in none intensive code (not called often and small loopable). Else
  	 * it's preferable to use a regular for() loop and save extra function calls.
  	 * @param {Object|Array} loopable - The object or array to be iterated.
  	 * @param {Function} fn - The function to call for each item.
  	 * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
  	 * @param {Boolean} [reverse] - If true, iterates backward on the loopable.
  	 */
  	each: function(loopable, fn, thisArg, reverse) {
  		var i, len, keys;
  		if (helpers.isArray(loopable)) {
  			len = loopable.length;
  			if (reverse) {
  				for (i = len - 1; i >= 0; i--) {
  					fn.call(thisArg, loopable[i], i);
  				}
  			} else {
  				for (i = 0; i < len; i++) {
  					fn.call(thisArg, loopable[i], i);
  				}
  			}
  		} else if (helpers.isObject(loopable)) {
  			keys = Object.keys(loopable);
  			len = keys.length;
  			for (i = 0; i < len; i++) {
  				fn.call(thisArg, loopable[keys[i]], keys[i]);
  			}
  		}
  	},
  
  	/**
  	 * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
  	 * @see http://stackoverflow.com/a/14853974
  	 * @param {Array} a0 - The array to compare
  	 * @param {Array} a1 - The array to compare
  	 * @returns {Boolean}
  	 */
  	arrayEquals: function(a0, a1) {
  		var i, ilen, v0, v1;
  
  		if (!a0 || !a1 || a0.length !== a1.length) {
  			return false;
  		}
  
  		for (i = 0, ilen = a0.length; i < ilen; ++i) {
  			v0 = a0[i];
  			v1 = a1[i];
  
  			if (v0 instanceof Array && v1 instanceof Array) {
  				if (!helpers.arrayEquals(v0, v1)) {
  					return false;
  				}
  			} else if (v0 !== v1) {
  				// NOTE: two different object instances will never be equal: {x:20} != {x:20}
  				return false;
  			}
  		}
  
  		return true;
  	},
  
  	/**
  	 * Returns a deep copy of `source` without keeping references on objects and arrays.
  	 * @param {*} source - The value to clone.
  	 * @returns {*}
  	 */
  	clone: function(source) {
  		if (helpers.isArray(source)) {
  			return source.map(helpers.clone);
  		}
  
  		if (helpers.isObject(source)) {
  			var target = {};
  			var keys = Object.keys(source);
  			var klen = keys.length;
  			var k = 0;
  
  			for (; k < klen; ++k) {
  				target[keys[k]] = helpers.clone(source[keys[k]]);
  			}
  
  			return target;
  		}
  
  		return source;
  	},
  
  	/**
  	 * The default merger when Chart.helpers.merge is called without merger option.
  	 * Note(SB): this method is also used by configMerge and scaleMerge as fallback.
  	 * @private
  	 */
  	_merger: function(key, target, source, options) {
  		var tval = target[key];
  		var sval = source[key];
  
  		if (helpers.isObject(tval) && helpers.isObject(sval)) {
  			helpers.merge(tval, sval, options);
  		} else {
  			target[key] = helpers.clone(sval);
  		}
  	},
  
  	/**
  	 * Merges source[key] in target[key] only if target[key] is undefined.
  	 * @private
  	 */
  	_mergerIf: function(key, target, source) {
  		var tval = target[key];
  		var sval = source[key];
  
  		if (helpers.isObject(tval) && helpers.isObject(sval)) {
  			helpers.mergeIf(tval, sval);
  		} else if (!target.hasOwnProperty(key)) {
  			target[key] = helpers.clone(sval);
  		}
  	},
  
  	/**
  	 * Recursively deep copies `source` properties into `target` with the given `options`.
  	 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
  	 * @param {Object} target - The target object in which all sources are merged into.
  	 * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
  	 * @param {Object} [options] - Merging options:
  	 * @param {Function} [options.merger] - The merge method (key, target, source, options)
  	 * @returns {Object} The `target` object.
  	 */
  	merge: function(target, source, options) {
  		var sources = helpers.isArray(source) ? source : [source];
  		var ilen = sources.length;
  		var merge, i, keys, klen, k;
  
  		if (!helpers.isObject(target)) {
  			return target;
  		}
  
  		options = options || {};
  		merge = options.merger || helpers._merger;
  
  		for (i = 0; i < ilen; ++i) {
  			source = sources[i];
  			if (!helpers.isObject(source)) {
  				continue;
  			}
  
  			keys = Object.keys(source);
  			for (k = 0, klen = keys.length; k < klen; ++k) {
  				merge(keys[k], target, source, options);
  			}
  		}
  
  		return target;
  	},
  
  	/**
  	 * Recursively deep copies `source` properties into `target` *only* if not defined in target.
  	 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
  	 * @param {Object} target - The target object in which all sources are merged into.
  	 * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
  	 * @returns {Object} The `target` object.
  	 */
  	mergeIf: function(target, source) {
  		return helpers.merge(target, source, {merger: helpers._mergerIf});
  	},
  
  	/**
  	 * Applies the contents of two or more objects together into the first object.
  	 * @param {Object} target - The target object in which all objects are merged into.
  	 * @param {Object} arg1 - Object containing additional properties to merge in target.
  	 * @param {Object} argN - Additional objects containing properties to merge in target.
  	 * @returns {Object} The `target` object.
  	 */
  	extend: function(target) {
  		var setFn = function(value, key) {
  			target[key] = value;
  		};
  		for (var i = 1, ilen = arguments.length; i < ilen; ++i) {
  			helpers.each(arguments[i], setFn);
  		}
  		return target;
  	},
  
  	/**
  	 * Basic javascript inheritance based on the model created in Backbone.js
  	 */
  	inherits: function(extensions) {
  		var me = this;
  		var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
  			return me.apply(this, arguments);
  		};
  
  		var Surrogate = function() {
  			this.constructor = ChartElement;
  		};
  
  		Surrogate.prototype = me.prototype;
  		ChartElement.prototype = new Surrogate();
  		ChartElement.extend = helpers.inherits;
  
  		if (extensions) {
  			helpers.extend(ChartElement.prototype, extensions);
  		}
  
  		ChartElement.__super__ = me.prototype;
  		return ChartElement;
  	}
  };
  
  module.exports = helpers;
  
  // DEPRECATIONS
  
  /**
   * Provided for backward compatibility, use Chart.helpers.callback instead.
   * @function Chart.helpers.callCallback
   * @deprecated since version 2.6.0
   * @todo remove at version 3
   * @private
   */
  helpers.callCallback = helpers.callback;
  
  /**
   * Provided for backward compatibility, use Array.prototype.indexOf instead.
   * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+
   * @function Chart.helpers.indexOf
   * @deprecated since version 2.7.0
   * @todo remove at version 3
   * @private
   */
  helpers.indexOf = function(array, item, fromIndex) {
  	return Array.prototype.indexOf.call(array, item, fromIndex);
  };
  
  /**
   * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead.
   * @function Chart.helpers.getValueOrDefault
   * @deprecated since version 2.7.0
   * @todo remove at version 3
   * @private
   */
  helpers.getValueOrDefault = helpers.valueOrDefault;
  
  /**
   * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead.
   * @function Chart.helpers.getValueAtIndexOrDefault
   * @deprecated since version 2.7.0
   * @todo remove at version 3
   * @private
   */
  helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
  