text: 
      (function (factory) {
          if (typeof module === 'object' && typeof module.exports !== "undefined") {
              module.exports = factory;
          } else {
              factory(FusionCharts);
          }
      }(function (FusionCharts) {
  (function webpackUniversalModuleDefinition(root, factory) {
  	if(typeof exports === 'object' && typeof module === 'object')
  		module.exports = factory(require("jquery"));
  	else if(typeof define === 'function' && define.amd)
  		define(["jquery"], factory);
  	else {
  		var a = typeof exports === 'object' ? factory(require("jquery")) : factory(root["jquery"]);
  		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
  	}
  })(window, function(__WEBPACK_EXTERNAL_MODULE__1__) {
  return /******/ (function(modules) { // webpackBootstrap
  /******/ 	// The module cache
  /******/ 	var installedModules = {};
  /******/
  /******/ 	// The require function
  /******/ 	function __webpack_require__(moduleId) {
  /******/
  /******/ 		// Check if module is in cache
  /******/ 		if(installedModules[moduleId]) {
  /******/ 			return installedModules[moduleId].exports;
  /******/ 		}
  /******/ 		// Create a new module (and put it into the cache)
  /******/ 		var module = installedModules[moduleId] = {
  /******/ 			i: moduleId,
  /******/ 			l: false,
  /******/ 			exports: {}
  /******/ 		};
  /******/
  /******/ 		// Execute the module function
  /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  /******/
  /******/ 		// Flag the module as loaded
  /******/ 		module.l = true;
  /******/
  /******/ 		// Return the exports of the module
  /******/ 		return module.exports;
  /******/ 	}
  /******/
  /******/
  /******/ 	// expose the modules object (__webpack_modules__)
  /******/ 	__webpack_require__.m = modules;
  /******/
  /******/ 	// expose the module cache
  /******/ 	__webpack_require__.c = installedModules;
  /******/
  /******/ 	// define getter function for harmony exports
  /******/ 	__webpack_require__.d = function(exports, name, getter) {
  /******/ 		if(!__webpack_require__.o(exports, name)) {
  /******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
  /******/ 		}
  /******/ 	};
  /******/
  /******/ 	// define __esModule on exports
  /******/ 	__webpack_require__.r = function(exports) {
  /******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  /******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  /******/ 		}
  /******/ 		Object.defineProperty(exports, '__esModule', { value: true });
  /******/ 	};
  /******/
  /******/ 	// create a fake namespace object
  /******/ 	// mode & 1: value is a module id, require it
  /******/ 	// mode & 2: merge all properties of value into the ns
  /******/ 	// mode & 4: return value when already ns object
  /******/ 	// mode & 8|1: behave like require
  /******/ 	__webpack_require__.t = function(value, mode) {
  /******/ 		if(mode & 1) value = __webpack_require__(value);
  /******/ 		if(mode & 8) return value;
  /******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
  /******/ 		var ns = Object.create(null);
  /******/ 		__webpack_require__.r(ns);
  /******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
  /******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
  /******/ 		return ns;
  /******/ 	};
  /******/
  /******/ 	// getDefaultExport function for compatibility with non-harmony modules
  /******/ 	__webpack_require__.n = function(module) {
  /******/ 		var getter = module && module.__esModule ?
  /******/ 			function getDefault() { return module['default']; } :
  /******/ 			function getModuleExports() { return module; };
  /******/ 		__webpack_require__.d(getter, 'a', getter);
  /******/ 		return getter;
  /******/ 	};
  /******/
  /******/ 	// Object.prototype.hasOwnProperty.call
  /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
  /******/
  /******/ 	// __webpack_public_path__
  /******/ 	__webpack_require__.p = "";
  /******/
  /******/
  /******/ 	// Load entry module and return exports
  /******/ 	return __webpack_require__(__webpack_require__.s = 0);
  /******/ })
  /************************************************************************/
  /******/ ([
  /* 0 */
  /***/ (function(module, exports, __webpack_require__) {
  
  var jQuery = __webpack_require__(1);
  var HTMLTableTranscoder = __webpack_require__(2);
  
  var win = typeof window !== 'undefined' ? window : {};
  
  if (typeof FusionCharts === 'undefined') {
      FusionCharts = win.FusionCharts;
  }
  if (typeof jQuery === 'undefined') {
      jQuery = win.jQuery;
  }
  
  FusionCharts.addDep(HTMLTableTranscoder);
  
  var doc = win.document,
      jQ = jQuery,
      renderFusionCharts,
      captureAllFusionChartsEvents,
      getChartObjectsFromSelection,
      configureLinkedCharts,
      math = win.Math,
      mathMin = math.min,
  
  // FusionCharts = FusionCharts,
  isArray = function () {
      // Use compiler's own isArray when available
      if (Array.isArray) {
          return Array.isArray;
      }
  
      // Retain references to variables for performance optimization
      var objectToStringFn = Object.prototype.toString,
          arrayToStringResult = objectToStringFn.call([]);
  
      return function (subject) {
          return objectToStringFn.call(subject) === arrayToStringResult;
      };
  }(),
      realtimeCommandMap = {
      feed: 'feedData',
      setdata: 'setData',
      setdataforid: 'setDataForId',
      getdata: 'getData',
      getdataforid: 'getDataForId',
      clear: 'clearChart',
      stop: 'stopUpdate',
      start: 'restartUpdate'
  },
      optionsParser = {
      feedData: function (options) {
          if (typeof options === 'string') {
              return [options];
          } else if (typeof options === 'object' && options.stream) {
              return [options.stream];
          } else {
              return false;
          }
      },
      getData: function (options) {
          // index is passed in case of multivalue charts.
          if (!isNaN(options)) {
              return [options];
          } else if (typeof options === 'object' && options.index) {
              return [options.index];
          } else {
              return [];
          }
      },
      getDataForId: function (options) {
          // index is passed in case of multivalue charts.
          if (typeof options === 'string') {
              return [options];
          } else if (typeof options === 'object' && options.id) {
              return [options.id];
          } else {
              return [];
          }
      },
      setData: function (options, value, label) {
          var arr = [];
          if (typeof options !== 'object') {
              arr = [options, value, label];
          } else {
              options.value && arr.push(options.value);
              options.label && arr.push(options.label);
          }
  
          return arr;
      },
      setDataForId: function (options, value, label) {
          var arr = [];
          if (typeof options === 'string' || typeof value === 'string' || typeof label === 'string') {
              arr = [options, value, label];
          } else if (typeof options === 'object') {
              options.value && arr.push(options.value);
              options.label && arr.push(options.label);
          }
  
          return arr;
      },
      clearChart: function (options) {
          return [options];
      },
      stopUpdate: function (options) {
          return [options];
      },
      restartUpdate: function (options) {
          return [options];
      }
  };
  
  // Assign FusionCharts object to global jQuery object for easy use.
  jQ.FusionCharts = FusionCharts;
  
  /**
   * Used purely for rendering the FusionCharts.
   * Acts as a common method that is invoked by all the APIs that create a
   * FusionChart object
   *
   * @param {array} elemList is a list of all the HTML elements that
   * are selected using the jQuery selectors
   *
   * @param {object} chartOptions is the options that are to be passed to
   * the FusionCharts contructor.
   */
  
  renderFusionCharts = function (elemList, chartOptions) {
      var i, l, cO, chartObj, scriptElement;
  
      if (isArray(chartOptions) || chartOptions instanceof jQ) {
          l = mathMin(elemList.length, chartOptions.length);
      } else {
          l = elemList.length;
      }
  
      for (i = 0; i < l; i += 1) {
  
          // One-to-one mapping with the HTML elements in case of
          // multiple option objects.
          if (isArray(chartOptions) || chartOptions instanceof jQ) {
              cO = chartOptions[i];
          } else {
              cO = chartOptions;
          }
  
          // check if the element is appended to the window document or not.
          if (elemList[i].parentNode) {
              // Adding the renderAt option to the chartOptions tells the
              // constructor where to render the FusionCharts object.
              FusionCharts.render(jQ.extend({}, cO, {
                  renderAt: elemList[i]
              }));
          } else {
              chartObj = new FusionCharts(jQ.extend({}, cO, {
                  renderAt: elemList[i]
              }));
  
              if (!jQ.FusionCharts.delayedRender) {
                  jQ.FusionCharts.delayedRender = {};
              }
              jQ.FusionCharts.delayedRender[chartObj.id] = elemList[i];
  
              scriptElement = doc.createElement('script');
              scriptElement.setAttribute('type', 'text/javascript');
  
              if (/msie/i.test(win.navigator.userAgent) && !win.opera) {
                  scriptElement.text = 'FusionCharts.items[\'' + chartObj.id + '\'].render();';
              } else {
                  scriptElement.appendChild(doc.createTextNode('FusionCharts.items[\'' + chartObj.id + '\'].render()'));
              }
              elemList[i].appendChild(scriptElement);
          }
      }
      return elemList;
  };
  
  /**
   *  Using jQuery's event model for attaching handlers to FusionCharts events.
   *  This is achieved by listening to the FusionCharts "*" event and then
   *  triggering a jQuery event on the associated DOM element.
   */
  captureAllFusionChartsEvents = function (eve, args) {
      var containerElement, event;
  
      // Extending our event with the jQuery event model for proper
      // delegation and bubbling.
      event = jQ.extend({}, eve);
      jQ.extend(event, jQ.Event('fusioncharts' + eve.eventType));
  
      // Checking if there is an associated DOM object
      if (event.sender && event.sender.options) {
          containerElement = event.sender.options.containerElement || event.sender.options.containerElementId;
  
          if (typeof containerElement === 'object') {
              jQ(containerElement).trigger(event, args);
          } else if (jQ('#' + containerElement).length) {
              jQ('#' + containerElement).trigger(event, args);
          } else {
              jQ(doc).trigger(event, args);
          }
      } else {
          // If there is no DOM object associated with the FusionCharts object
          // then triggering the event on the document itself for any possible
          // global handlers that might want to capture it.
          jQ(doc).trigger(event, args);
      }
  };
  
  FusionCharts.addEventListener('*', captureAllFusionChartsEvents);
  
  /**
   * Used to select all the HTML object/embed elements that have been created
   * using the FusionCharts constructor
   *
   * @param {jQuery} obj, the selection of elements that need to be processed.
   *
   */
  getChartObjectsFromSelection = function (obj) {
  
      // The HTML object/embed may be part of the current selection or a
      // child of the current selection. Need to take both cases into account.
      // @note If the FusionCharts object has not been rendered yet, e.g in
      // case the container is not appended to the document, then 'find' for
      // that element will NOT return the corresponding FusionCharts object.
      return obj.filter(':FusionCharts').add(obj.find(':FusionCharts'));
  };
  
  /**
   *  Used to configure the links at various levels in a linked chart.
   *
   *  @param {jQuery} chartObjects The FusionCharts objects for which the link
   *  has to be configured.
   *
   *  @param {object} linkConfigObj contains the configuration details of the
   *  linked chart like swfUrl, height, width etc.
   *
   *  @param {string} level contains the level at which the user wants to
   *  configure the link.
   *
   */
  configureLinkedCharts = function (chartObjects, linkConfigObj, level) {
  
      if (typeof linkConfigObj === 'object') {
          chartObjects.each(function () {
              this.configureLink(linkConfigObj, level);
          });
      }
  };
  
  /**
   * @id: jQuery.fn.insertFusionCharts
   * @id: $.fn.insertFusionCharts
   *
   * @param {object} options contains the parameters that need to be passed
   * to the FusionCharts constructor
   *
   * Inserts the FusionCharts objects in the HTML elements that are selected
   * by the jQuery selector.
   */
  jQ.fn.insertFusionCharts = function (options) {
      return renderFusionCharts(this, options);
  };
  
  /**
   * @id: jQuery.fn.appendFusionCharts
   * @id: $.fn.appendFusionCharts
   *
   * @param {object} options contains that parameters that need to be passed
   * to the FusionCharts constructor
   *
   * Appends the FusionCharts objects immediately after the HTML elements
   * that are selected by the jQuery selector.
   */
  jQ.fn.appendFusionCharts = function (options) {
      options.insertMode = 'append';
      return renderFusionCharts(this, options);
  };
  
  /**
   * @id: jQuery.fn.prependFusionCharts
   * @id: $.fn.prependFusionCharts
   *
   * @param {object} options contains the parameters that need to be passed
   * to the FusionCharts constructor
   *
   *  Prepends the FusionCharts objects before the HTML elements that are
   *  selected by the jQuery selector.
   */
  jQ.fn.prependFusionCharts = function (options) {
      options.insertMode = 'prepend';
      return renderFusionCharts(this, options);
  };
  
  /**
   * @id: jQuery.fn.attrFusionCharts
   * @id: $.fn.attrFusionCharts
   *
   * @param {object|string} attr, If this is a string then it contains
   * the FusionCharts object's attribute that needs to be set or fetched.
   * If it is an object then, it contains the attributes along with the
   * corresponding values that need to be set on the FusionCharts object
   *
   * @param {string} attrVal, To be used if attr is a string. Contains the
   * value that needs to be set for the attribute that attr corresponds to.
   *
   *  Used to set or get the attribute(s) of the FusionCharts object.
   */
  jQ.fn.attrFusionCharts = function (attr, attrVal) {
  
      /**
       * @ignore
       * @todo Remove ignore
       *
       * @var {jQuery} chartsObjects stores the FusionCharts objects in
       * the selected HTML elements.
       * @var {object} transfer Holds all atttributes to be returned to the
       * callee Function.
       */
      var transfer = [],
          chartObjects = getChartObjectsFromSelection(this);
  
      if (attrVal !== undefined) {
          // Set the charts attribute attr with value attrVal.
  
          chartObjects.each(function () {
              this.FusionCharts.setChartAttribute(attr, attrVal);
          });
          return this;
      }
      if (typeof attr === 'object') {
          // Set the charts attributes, in the passed object's keys with
          // the corresponding values.
  
          chartObjects.each(function () {
              this.FusionCharts.setChartAttribute(attr);
          });
          return this;
      }
  
      // If both the above cases fail, user is trying to, in accordance with the
      // jQuery paradigm, get the value of the arrtibute.
      chartObjects.each(function () {
          transfer.push(this.FusionCharts.getChartAttribute(attr));
      });
      return transfer;
  };
  
  /**
   * @id jQuery.fn.updateFusionCharts
   * @id $.fn.updateFusionCharts
   *
   * @param {object} options Contains the new options that the FusionCharts
   * objects need to update themselves with. Currently, using this interface
   * the dataType, data, width, height, debugMode and swfUrl can be updated.
   */
  jQ.fn.updateFusionCharts = function (options) {
  
      var filterOpts = {},
          chartObjects = getChartObjectsFromSelection(this),
          updateOptions = [['swfUrl', false], ['type', false], ['height', false], ['width', false], ['containerBackgroundColor', true], ['containerBackgroundAlpha', true], ['dataFormat', false], ['dataSource', false]],
          i,
          l,
          fcChart,
          renderFlag,
          optStr,
          newChart;
  
      for (i = 0, l = updateOptions.length; i < l; i += 1) {
          optStr = updateOptions[i][0];
          filterOpts.type = filterOpts.type || filterOpts.swfUrl;
          if (options[optStr]) {
              if (updateOptions[i][1]) {
                  renderFlag = true;
              }
              filterOpts[optStr] = options[optStr];
          }
      }
  
      chartObjects.each(function () {
          // If height and width are given then resize the chart first.
          fcChart = this.FusionCharts;
          if (renderFlag) {
              newChart = fcChart.clone(filterOpts);
              newChart.render();
              return;
          }
  
          if (filterOpts.dataSource !== undefined || filterOpts.dataFormat !== undefined) {
              if (filterOpts.dataSource === undefined) {
                  fcChart.setChartData(fcChart.args.dataSource, filterOpts.dataFormat);
              } else if (filterOpts.dataFormat === undefined) {
                  fcChart.setChartData(filterOpts.dataSource, fcChart.args.dataFormat);
              } else {
                  fcChart.setChartData(filterOpts.dataSource, filterOpts.dataFormat);
              }
          }
          if (filterOpts.width !== undefined || filterOpts.height !== undefined) {
              fcChart.resizeTo(filterOpts.width, filterOpts.height);
          }
          if (filterOpts.type) {
              fcChart.chartType(filterOpts.type);
          }
      });
  
      return this;
  };
  
  /**
   *  @id: jQuery.fn.getFusionCharts
   *  @id: $.fn.getFusionCharts
   *
   *  @return {object} Contains an array of FusionCharts chart objects.
   */
  jQ.fn.getFusionCharts = function () {
      var charts = getChartObjectsFromSelection(this);
      var chartArr = [];
      charts.each(function () {
          chartArr.push(this.FusionCharts);
      });
      return chartArr;
  };
  
  /**
   *  @id: jQuery.fn.cloneFusionCharts
   *  @id: $.fn.cloneFusionCharts
   *
   *  @param {object} options The options object that takes the additional
   *  parameters to be passed while cloning the FusionCharts object.
   *
   *  @param {function} callback The callback function that has to be called
   *  once the FusionCharts objects have been cloned. This function will take
   *  the new clone objects as parameter.
   *
   */
  jQ.fn.cloneFusionCharts = function (callback, options) {
  
      var transfer, temp, chartObjects;
  
      // Check if the options parameter, which is not mandatory, has been
      // passed or not. If not, that means that options is the callback function.
      if (typeof callback !== 'function' && typeof options === 'function') {
          temp = callback;
          callback = options;
          options = temp;
      }
  
      transfer = [];
      chartObjects = getChartObjectsFromSelection(this);
  
      chartObjects.each(function () {
          transfer.push(this.FusionCharts.clone(options, {}, true));
      });
  
      callback.call(jQ(transfer), transfer);
  
      return this;
  };
  
  /**
   *  @id: jQuery.fn.disposeFusionCharts
   *  @id: $.fn.disposeFusionCharts
   *
   */
  jQ.fn.disposeFusionCharts = function () {
  
      var chartObjects = getChartObjectsFromSelection(this);
  
      chartObjects.each(function () {
          // Execute dispose on charts.
          this.FusionCharts.dispose();
  
          // Remove identifier reference variable
          delete this.FusionCharts;
  
          // cleanup any static objects pertaining to FusionCharts.
          if (this._fcDrillDownLevel === 0) {
              delete this._fcDrillDownLevel;
          }
      });
  
      return this;
  };
  
  /**
   * @id jQuery.fn.covertToFusionCharts
   * @id $.fn.convertToFusionCharts
   *
   * @param {object} chartOpts Configuration options to generate FusionCharts.
   * See documentation to get the list.
   *
   * @param {object} convertOpts Configuration options to convert the table
   * into a FusionCharts object.
   * See documentation to get the list.
   *
   */
  jQ.fn.convertToFusionCharts = function (chartOpts, convertOpts) {
  
      var transferObj = [];
  
      if (typeof chartOpts.dataConfiguration === 'undefined') {
          chartOpts.dataConfiguration = {};
      }
  
      jQ.extend(true, chartOpts.dataConfiguration, convertOpts);
  
      if (!chartOpts.dataSource) {
          chartOpts.dataSource = this.get(0);
      }
  
      if (!chartOpts.renderAt) {
          this.each(function () {
              transferObj.push(jQ('<div></div>').insertBefore(this).insertFusionCharts(chartOpts).get(0));
          });
      } else {
          if (typeof chartOpts.renderAt === 'string') {
              transferObj.push(jQ('#' + chartOpts.renderAt).insertFusionCharts(chartOpts).get(0));
          } else if (typeof chartOpts.renderAt === 'object') {
              transferObj.push(jQ(chartOpts.renderAt).insertFusionCharts(chartOpts).get(0));
          }
      }
  
      return jQ(transferObj);
  };
  
  /**
   * @id jQuery.fn.drillDownFusionChartsTo
   * @id $.fn.drillDownFusionChartsTo
   *
   * Used to set multi-level configurations of linked FusionCharts objects.
   * The levels are iterated depending on the number of configuration objects
   * in a single jQuery chain.
   *
   * To set the configuration at a specific level please refer to docs.
   */
  jQ.fn.drillDownFusionChartsTo = function () {
      var chartObjects = getChartObjectsFromSelection(this),
          j,
          len,
          i,
          l,
          configureOpts;
  
      // hack to support chaining of multiple drillDowns in a single chain
      if (typeof this._fcDrillDownLevel === 'undefined') {
          this._fcDrillDownLevel = 0;
      }
  
      for (j = 0, len = arguments.length; j < len; j += 1) {
          configureOpts = arguments[j];
  
          if (isArray(configureOpts)) {
              for (i = 0, l = configureOpts.length; i < l; i += 1) {
                  configureLinkedCharts(chartObjects, configureOpts[i], this._fcDrillDownLevel);
                  this._fcDrillDownLevel += 1;
              }
          } else {
              configureLinkedCharts(chartObjects, configureOpts, this._fcDrillDownLevel);
              this._fcDrillDownLevel += 1;
          }
      }
      return this;
  };
  
  /**
   * @id jQuery.fn.streamFusionChartsData
   * @id $.fn.streamFusionChartsData
   *
   * @param {string} command. Contains the type of operation to be performed on
   * the realtime charts. If not provided, by default the command would be 'feed'
   * that invokes the feedData method of the chart and passes the options to it.
   *
   * @param {object} options. Contains the options that has to be parsed (if it is a js object)
   * and passed to the chart method (corresponding to command).
   * If not an object, it is passed as is to the chart method.
   *
   * @param {object} value. To make the API morph the data setter methods (setData, setDataForId),
   * it can also be passed the same parameters as the setter functions.
   *
   * @param {object} label. To make the API morph the data setter methods (setData, setDataForId),
   * it can also be passed the same parameters as the setter functions.
  **/
  
  jQ.fn.streamFusionChartsData = function (command, options, value, label) {
  
      var chartObjects = getChartObjectsFromSelection(this),
          transfer = [],
          fcChart,
          method,
          params;
  
      // Convert the command to lower case and fetch the proper chart method name.
      method = realtimeCommandMap[command && command.toLowerCase()];
  
      // Check if the command provided is valid or not.
      if (method === undefined) {
          // this means the command is not a getter. which in turn means that
          // the command is a data stream string and has to be handled accordingly.
          if (arguments.length === 1) {
              params = [command];
              method = realtimeCommandMap.feed;
          } else {
              return this;
          }
      } else if (arguments.length === 1) {
          // command is to invoke a method without any parameters..
          params = [];
      } else {
          // optionsParser returns an array of parameters to be passed to the
          // chart method.
          params = optionsParser[method](options, value, label);
      }
  
      if (method === 'getData' || method === 'getDataForId') {
          chartObjects.each(function () {
              fcChart = this.FusionCharts;
              if (typeof fcChart[method] === 'function') {
                  transfer.push(fcChart[method].apply(fcChart, params));
              }
          });
          return transfer;
      } else {
          chartObjects.each(function () {
              fcChart = this.FusionCharts;
              if (typeof fcChart[method] === 'function') {
                  fcChart[method].apply(fcChart, params);
              }
          });
          return this;
      }
  };
  
  jQ.extend(jQ.expr[':'], {
      /**
       *  Extending the jQuery selector to select all object/embed elements that
       *  have been created using the FusionCharts constructor i.e that are an
       *  instance of FusionCharts.
       *
       *  @param {object} obj, Is the HTML element that is currently being
       *  checked.
       */
      FusionCharts: function (obj) {
          return obj.FusionCharts instanceof FusionCharts;
      }
  });
  
  /***/ }),
  /* 1 */
  /***/ (function(module, exports) {
  
  module.exports = __WEBPACK_EXTERNAL_MODULE__1__;
  
  /***/ }),
  /* 2 */
  /***/ (function(module, exports) {
  
  var win = window,
      doc = win.document,
      objectToStringFn = Object.prototype.toString,
      merge = function (obj1, obj2) {
      var item, str;
      //check whether obj2 is an array
      //if array then iterate through it's index
      //**** MOOTOOLS precution
      if (obj2 instanceof Array) {
          for (item = 0; item < obj2.length; item += 1) {
              if (typeof obj2[item] !== 'object') {
                  obj1[item] = obj2[item];
              } else {
                  if (typeof obj1[item] !== 'object') {
                      obj1[item] = obj2[item] instanceof Array ? [] : {};
                  }
                  merge(obj1[item], obj2[item]);
              }
          }
      } else {
          for (item in obj2) {
              if (typeof obj2[item] === 'object') {
                  str = objectToStringFn.call(obj2[item]);
                  if (str === '[object Object]') {
                      if (typeof obj1[item] !== 'object') {
                          obj1[item] = {};
                      }
                      merge(obj1[item], obj2[item]);
                  } else if (str === '[object Array]') {
                      if (!(obj1[item] instanceof Array)) {
                          obj1[item] = [];
                      }
                      merge(obj1[item], obj2[item]);
                  } else {
                      obj1[item] = obj2[item];
                  }
              } else {
                  obj1[item] = obj2[item];
              }
          }
      }
      return obj1;
  },
      extend = function (sink, source, proto, deep) {
      var item;
      // When 'proto' is marked as true, the methods and properties
      // of source is not added to the prototype of the sink.
      if (proto && sink.prototype) {
          sink = sink.prototype;
      }
  
      // If deep extend is specified, then we use the deep copy function
      // 'merge'
      if (deep === true) {
          merge(sink, source);
      }
      // Copy all methods and properties of the object passed in parameter
      // to the object to which this function is attached.
      else {
              for (item in source) {
                  sink[item] = source[item];
              }
          }
  
      return sink;
  },
  
  /**
   *  Used to remove all textNodes in an array of nodes. Textnodes get created
   *  inadvertently, when the table HTML has newline and space. Returns an
   *  array of nodes that is not an HTMLCollection and has only the non-text
   *  nodes in it.
   *
   *  @param {array} nodeArr Contains the array of nodes that have to be
   *  sanitized.
   */
  sanitizeNodesArray = function (nodeArr) {
      var l,
          i,
          sanitizedArr = [];
      for (i = 0, l = nodeArr.length; i < l; i += 1) {
          // if nodeType != 3 then the node is not a text node.
          if (nodeArr[i].nodeType !== 3) {
              sanitizedArr.push(nodeArr[i]);
          }
      }
      return sanitizedArr;
  },
  
  
  /**
   * Used to merge two JSON objects. The copy is a deep copy and not a
   * reference copy.
   *
   * @param: {object} srcJSON, the source json.
   *
   * @param: {object} targetJSON, that json that needs to be merged with the
   * source json.
   *
   */
  mergeJSON = function (srcJSON, targetJSON) {
      var i, len, item;
  
      if (targetJSON instanceof Array) {
          for (i = 0, len = targetJSON.length; i < len; i++) {
              if (targetJSON[i] instanceof Array) {
                  if (srcJSON[i] === undefined) {
                      srcJSON[i] = [];
                  }
                  mergeJSON(srcJSON[i], targetJSON[i]);
              } else if (typeof targetJSON[i] === 'object') {
                  if (typeof srcJSON[i] === 'undefined') {
                      srcJSON[i] = {};
                  }
                  mergeJSON(srcJSON[i], targetJSON[i]);
              } else {
                  srcJSON[i] = targetJSON[i];
              }
          }
      } else if (typeof targetJSON === 'object') {
          for (item in targetJSON) {
              if (typeof srcJSON[item] === 'undefined') {
                  if (targetJSON[item] instanceof Array) {
                      srcJSON[item] = [];
                      mergeJSON(srcJSON[item], targetJSON[item]);
                  } else if (typeof srcJSON[item] === 'object') {
                      srcJSON[i] = {};
                      mergeJSON(srcJSON[i], targetJSON[i]);
                  } else {
                      srcJSON[i] = targetJSON[i];
                  }
              }
          }
      }
  
      return srcJSON;
  },
  
  
  /**
   *  Returns the <tbody> element of the table. In order to support W3C
   *  non-compliant HTML, wherein the table does not have a <tbody> containing
   *  the <tr> & <td> elements, the table itself is returned.
   *
   *  @param {object} tbl Is the table whose tbody needs to fetched.
   *
   */
  getTbody = function (tbl) {
      var tbodyArr = sanitizeNodesArray(tbl.childNodes);
  
      // Checking if the table's childNode is a tbody or not
      if (tbodyArr.length) {
          if (tbodyArr[0].nodeName === 'TBODY') {
              return tbodyArr[0];
          } else if (tbodyArr[0].nodeName === 'THEAD' && tbodyArr[1] && tbodyArr[1].nodeName === 'TBODY') {
              return tbodyArr[1];
          }
      }
      return tbl;
  },
  
  
  /**
   *  Returns an array containing the <td> in the <thead> tag.
   *
   *  @param {object} tbl Is the table whose tbody needs to fetched.
   *
   */
  getThead = function (tbl) {
      var tbodyArr = sanitizeNodesArray(tbl.childNodes);
  
      // Checking if the table's childNode is a tbody or not
      if (tbodyArr.length) {
          if (tbodyArr[0].nodeName === 'THEAD' && tbodyArr[1] && tbodyArr[1].nodeName === 'TBODY') {
              return tbodyArr[0].childNodes;
          }
      }
      return [];
  },
  
  
  /**
   *  Used to return the text in a given Element. Needed as firefox does not
   *  support 'innerText', which is a W3C standard and instead uses
   *  textContent attribute to store the text.
   *
   *  @param {object} nodeEle The HTML element whose text is needed.
   */
  getTextFromNode = function (nodeEle) {
      return nodeEle.innerText !== undefined ? nodeEle.innerText : nodeEle.textContent;
  },
  
  
  /**
   *  Used to convert an array of rows into an array of corresponding columns.
   *
   *  @param {array} rowArr The array of table rows that has to be transposed
   *  into an array of columns.
   */
  getColumnArr = function (rowArr) {
  
      var i,
          j,
          l,
          len,
          cellArr,
          rowSpanInc,
          colSpan = 1,
          columnArrIdx,
          rowSpan = {},
          returnObj = [];
  
      for (i = 0, l = rowArr.length; i < l; i += 1) {
  
          // get all the cells of the row
          cellArr = sanitizeNodesArray(rowArr[i].childNodes);
          colSpan = 1;
          rowSpanInc = 0;
          for (j = 0, len = cellArr.length; j < len; j += 1) {
  
              // if a previous row had a cell with a rowspan then this
              // rowspan needs to be taken into account while creating
              // column array.
              columnArrIdx = j + colSpan + rowSpanInc - 1;
              if (rowSpan[columnArrIdx] && i - rowSpan[columnArrIdx].rowNum < rowSpan[columnArrIdx].row) {
                  rowSpanInc += rowSpan[columnArrIdx].col;
                  columnArrIdx += rowSpan[columnArrIdx].col;
              }
  
              if (parseInt(cellArr[j].getAttribute('rowspan'), 10) > 1) {
                  if (!rowSpan[columnArrIdx]) {
                      rowSpan[columnArrIdx] = {};
                  }
                  rowSpan[columnArrIdx].rowNum = i;
                  rowSpan[columnArrIdx].row = parseInt(cellArr[j].getAttribute('rowspan'), 10);
                  // If the cell has both a rowspan and a colspan then they
                  // both need to be taken into consideration while calculating
                  // the column of cells in the susequent rows
                  if (parseInt(cellArr[j].getAttribute('colspan'), 10) > 1) {
                      rowSpan[columnArrIdx].col = parseInt(cellArr[j].getAttribute('colspan'), 10);
                  } else {
                      rowSpan[columnArrIdx].col = 1;
                  }
              }
  
              // The previous cells colspan, and the previous rows rowspans
              // also needs to be added to the current cells index to get the
              // proper column index.
              while (returnObj.length <= columnArrIdx) {
                  returnObj.push({ childNodes: [] });
              }
              returnObj[columnArrIdx].childNodes.push(cellArr[j]);
  
              // Adding the current cells colspan for subsequent cells in the
              // current row.
              if (parseInt(cellArr[j].getAttribute('colspan'), 10) > 1) {
                  colSpan += parseInt(cellArr[j].getAttribute('colspan'), 10) - 1;
              }
          }
      }
  
      return returnObj;
  },
  
  
  /**
   * Used to check if an item is present in an array or not.
   *
   * @param {array} arr The array which has to be checked
   *
   * @param {string|number|object} item The item which needs be checked if
   * present in array arr or not.
   */
  arrayContains = function (arr, item) {
      var i = arr.length;
      // Using a decrementing while loop (optimization) since the order in which the
      // array is traversed doesn't matter.
      while (i) {
          i -= 1;
          if (arr[i] === item) {
              return true;
          }
      }
      return false;
  },
  
  
  /**
   * Used to check if a particular row or column has all non numeric (or blank)
   * content. If so, then that particular row/column must be ignored.
   *
   * @param {array} nodeArr Is an array of all the rows/columns of the table.
   *
   * @param {number} index of the row/column that is not to be analysed as it
   * has already been set aside as the label row/column.
   *
   * @param {number} j is the cell index at which we have to check for the
   * presence of numeric data in all the other rows and columns.
   */
  
  checkData = function (nodeArr, j, index) {
  
      var i,
          l,
          childArr = sanitizeNodesArray(nodeArr[j].childNodes),
          text;
  
      for (i = 0, l = childArr.length; i < l; i += 1) {
          if (i !== index) {
              text = getTextFromNode(childArr[i]);
              if (parseFloat(text) === text) {
                  return true;
              }
          }
      }
      return false;
  },
      _blankString = '__fcBLANK__',
      _blankNo = 0,
  
  /**
   * Used to get the table row that has the labels (categories or legend) and
   * extract the label details from the corresponding row.
   *
   * @param {array} nodeArr Is an array of all the rows/columns of the table.
   *
   * @param {array} ignoreArr Is an array of all the indexes in the nodeArr
   * that need to be ignored. The items of this array can be negative as well.
   *
   * @param {string} index If the label row/column details have been given by
   * the user then this will contain the index which has the labels.
   *
   */
  getLabels = function (nodeArr, ignoreArr, index, opts) {
  
      var len,
          l,
          i,
          j,
          childArr,
          mostEmptyCellRow = null,
          internalLabel = [],
          emptyCellCount = [],
          textCellCount = 0,
          temp,
          returnObj = {},
          spanTotal = 0,
          spanLen,
          isRowLabel,
          maxIdx,
          spanLength,
          totalSpanLength = 0,
          tLabels;
  
      if (typeof index === 'undefined') {
          // Checking if the user has provided the index. If index has not been
          // passed then we assume that the user does not want to give a label row
          // or column.
  
          // Creating custom labels for all cells in the first row/column.
          childArr = sanitizeNodesArray(nodeArr[0].childNodes);
          for (j = 0, len = childArr.length; j < len; j += 1) {
              spanLen = j + spanTotal;
              internalLabel[spanLen] = _blankString + (spanLen + 1);
  
              temp = parseInt(childArr[j].colSpan, 10);
              temp = temp > 1 ? temp : parseInt(childArr[j].rowSpan, 10);
              if (temp > 1) {
                  for (l = 1; l < temp; l += 1) {
                      internalLabel[spanLen + l] = _blankString + (spanLen + l + 1);
                  }
                  spanTotal += temp - 1;
              }
          }
  
          // Deleting the labels for the rows/columns that the user wants to
          // ignore.
          for (i = 0, l = j + spanTotal, len = ignoreArr.length; i < len; i += 1) {
              if (ignoreArr[i] > 0) {
                  delete internalLabel[ignoreArr[i] - 1];
              } else {
                  delete internalLabel[l + ignoreArr[i]];
              }
          }
  
          return { 'index': -1, 'labelObj': internalLabel };
      } else if (index === 0) {
          // Checking if the user has provided the index. Since we expect row/column
          // indices starting from 1, if index is 0 then we use our internal logic
          // to find the label array from the given nodeArr.
          for (i = 0, l = nodeArr.length; i < l; i += 1) {
              childArr = sanitizeNodesArray(nodeArr[i].childNodes);
              emptyCellCount[i] = 0;
              textCellCount = 0;
  
              if (opts && opts._extractByHeaderTag) {
                  for (j = 0, len = childArr.length; j < len; j += 1) {
                      if (childArr[j].nodeName.toLowerCase() != 'th') {
                          continue;
                      }
                      tLabels = getLabels(nodeArr, ignoreArr, i + 1);
                      delete tLabels.labelObj[opts._rowLabelIndex];
                      return tLabels;
                  }
              } else {
                  for (j = 0, len = childArr.length; j < len; j += 1) {
                      if (arrayContains(ignoreArr, j + 1) || arrayContains(ignoreArr, j - len)) {
                          continue;
                      }
                      temp = getTextFromNode(childArr[j]);
                      // Checking if the cell is emtpy.
                      if (temp.replace(/^\s*/, '').replace(/\s*$/, '') === '') {
                          emptyCellCount[i] += 1;
                          continue;
                      }
                      // Checking if the cell has a non-number content
                      if (parseFloat(temp) != temp) {
                          textCellCount += 1;
                          // If there are at least 2 cells that have non-number
                          // content then we assume that they contain labels and
                          // fetch the labels from this array of nodes.
                          if (textCellCount > 1) {
                              return getLabels(nodeArr, ignoreArr, i + 1);
                          }
                      }
                  }
              }
              // If there are empty cells then we assume that the array with
              // the most number of empty cells must be the label array.
              if (i > 0) {
                  if (emptyCellCount[i - 1] > emptyCellCount[i]) {
                      mostEmptyCellRow = i - 1;
                  } else if (emptyCellCount[i - 1] < emptyCellCount[i]) {
                      mostEmptyCellRow = i;
                  }
              }
          }
          if (mostEmptyCellRow !== null) {
              return getLabels(nodeArr, ignoreArr, mostEmptyCellRow + 1);
          } else {
              return getLabels(nodeArr, ignoreArr);
          }
      }
  
      // If this is a negative number then, calulate the index from the
      // end of the table. e.g -1 would imply the last row.
      if (index < 0) {
          index += nodeArr.length;
      } else if (index > 0) {
          index -= 1;
      }
  
      /**
       * Once we have the index of the row/column that contains the labels we
       * go through only that row/column and extract the labels.
       */
      childArr = sanitizeNodesArray(nodeArr[index].childNodes);
  
      isRowLabel = nodeArr[0].nodeType !== undefined ? true : false;
      for (j = 0, len = childArr.length; j < len; j += 1) {
          spanLength = 0;
          if (isRowLabel) {
              if (childArr[j].colSpan !== '1') {
                  spanLength = parseInt(childArr[j].colSpan, 10);
              }
          } else if (childArr[j].rowSpan !== '1') {
              spanLength = parseInt(childArr[j].rowSpan, 10);
          }
          spanLength = spanLength > 1 ? spanLength : 0;
          temp = getTextFromNode(childArr[j]);
          if (temp.replace(/^\s*/, '').replace(/\s*$/, '') !== '') {
              returnObj[j + totalSpanLength] = temp;
          } else if (checkData(getColumnArr(nodeArr), j, index)) {
              // if the label text is missing in one of the cells of the labels
              // row/column we check for the presence of numeric data in other
              // cells of the corresponding column/row.
  
              returnObj[j + totalSpanLength] = _blankString + _blankNo;
              _blankNo += 1;
          }
  
          if (spanLength > 1) {
              // If the spanLength > 1, then we create additional labels for
              // rows/columns pertaining to the rowspan or colspan.
              temp = returnObj[j + totalSpanLength];
              for (i = 1; i < spanLength; i += 1) {
                  returnObj[j + totalSpanLength + i] = temp + ' (' + i + ')';
              }
  
              // totalSpanLength is used to adjust the indices of the
              // subsequent cells using the rowspan/colspan of the current
              // cell.
              totalSpanLength += spanLength - 1;
          }
      }
  
      // Deleting the rows/columns that the user wants to ignore.
      maxIdx = len + totalSpanLength;
      for (i = 0, len = ignoreArr.length; i < len; i += 1) {
          if (ignoreArr[i] > 0) {
              delete returnObj[ignoreArr[i] - 1];
          } else {
              delete returnObj[maxIdx + ignoreArr[i]];
          }
      }
  
      return { 'labelObj': returnObj, 'index': index };
  },
      extractDataFromTable = function (tbl, opts) {
  
      if (typeof tbl === 'string') {
          tbl = doc.getElementById(tbl);
      }
  
      if (typeof win.jQuery !== 'undefined' && tbl instanceof win.jQuery) {
          // jshint ignore: line
          tbl = tbl.get(0);
      }
  
      if (!tbl) {
          return { data: null };
      }
  
      if (opts.hideTable) {
          tbl.style.display = 'none';
      }
  
      var i,
          j,
          rowCells,
          cellText,
          dataMap = {},
          mapColumnIdx,
          columnSpan,
          len,
          item,
          rowSpan,
          cellEle,
          columnSpanObj = {},
          rowSpanObj = {},
          tableRows = sanitizeNodesArray(getThead(tbl)).concat(sanitizeNodesArray(getTbody(tbl).childNodes)),
          l = tableRows.length,
          dataRows = 0,
          dataColumns = 0,
          tempColumn = 0,
          rowLabelMap,
          m,
          k = 0,
          columnLabelMap,
          isSingleSeries = false,
          chartType = opts.chartType,
          tempMap,
          singleSeriesCharts = ['column2d', 'column3d', 'pie3d', 'pie2d', 'line', 'bar2d', 'area2d', 'doughnut2d', 'doughnut3d', 'pareto2d', 'pareto3d'];
  
      if (singleSeriesCharts.indexOf(chartType) !== -1) {
          isSingleSeries = true;
      }
  
      // use rowLabelSource and colLabelSource to avoid confusion
      opts.rowLabelSource = parseInt(opts.labelSource, 10);
      opts.colLabelSource = parseInt(opts.legendSource, 10);
      // Create the labels objects for the chart.
  
      if (opts.major === 'column') {
          rowLabelMap = opts.useLabels ? getLabels(tableRows, opts.ignoreCols, opts.rowLabelSource) : getLabels(tableRows, opts.ignoreCols);
  
          columnLabelMap = opts.useLegend ? getLabels(getColumnArr(tableRows), opts.ignoreRows, opts.colLabelSource) : getLabels(getColumnArr(tableRows), opts.ignoreRows);
      } else {
          tempMap = getLabels(getColumnArr(tableRows), opts.ignoreRows, opts.rowLabelSource);
          if (!opts.useLabels) {
              rowLabelMap = getLabels(getColumnArr(tableRows), opts.ignoreRows);
          } else {
              rowLabelMap = tempMap;
          }
  
          opts._rowLabelIndex = tempMap.index;
          opts._extractByHeaderTag = true;
  
          columnLabelMap = opts.useLegend ? getLabels(tableRows, opts.ignoreCols, opts.colLabelSource, opts) : getLabels(tableRows, opts.ignoreCols);
  
          delete opts._extractByHeaderTag;
  
          tempMap = rowLabelMap;
          rowLabelMap = columnLabelMap;
          columnLabelMap = tempMap;
      }
  
      delete rowLabelMap.labelObj[columnLabelMap.index];
      delete columnLabelMap.labelObj[rowLabelMap.index];
  
      // Creating the 2d map depending on whether the rows are the primary
      // keys or the columns.
      if (opts.major === 'row') {
          for (item in columnLabelMap.labelObj) {
              dataMap[item] = {};
          }
      } else {
          for (item in rowLabelMap.labelObj) {
              dataMap[item] = {};
          }
      }
  
      // Populating the dataMap.
      for (i = 0; i < l; i += 1) {
          if (rowLabelMap.index === i || columnLabelMap.labelObj[i] === undefined) {
              continue;
          }
  
          dataRows += 1;
          rowCells = sanitizeNodesArray(tableRows[i].childNodes);
  
          // columnSpanObj maintains the number of colspans in the current
          // row.
          // rowSpanObj maintains the number of rowspans in a rows x columns
          // map.
          columnSpanObj[i] = 0;
          rowSpanObj[i] = {};
  
          for (j = 0, len = rowCells.length; j < len; j += 1) {
  
              cellEle = rowCells[j];
  
              columnSpan = parseInt(cellEle.getAttribute('colspan'), 10);
              rowSpan = parseInt(cellEle.getAttribute('rowspan'), 10);
  
              mapColumnIdx = j + columnSpanObj[i];
  
              // Calculating the position of the current cell in the dataMap.
              while (k < i) {
                  if (rowSpanObj[k]) {
                      for (m in rowSpanObj[k]) {
                          if (m > mapColumnIdx) {
                              break;
                          }
  
                          if (i - k <= rowSpanObj[k][m].row) {
                              mapColumnIdx += rowSpanObj[k][m].col;
                          }
                      }
                  }
                  k += 1;
              }
  
              if (columnSpan > 1) {
                  columnSpanObj[i] += columnSpan - 1;
              }
  
              if (rowSpan > 1) {
                  if (columnSpan > 1) {
                      rowSpanObj[i][mapColumnIdx] = {
                          row: rowSpan - 1,
                          col: columnSpan
                      };
                  } else {
                      rowSpanObj[i][mapColumnIdx] = {
                          row: rowSpan - 1,
                          col: 1
                      };
                  }
              }
              if (columnLabelMap.index === mapColumnIdx || rowLabelMap.labelObj[mapColumnIdx] === undefined) {
  
                  continue;
              }
  
              tempColumn += 1;
              cellText = getTextFromNode(cellEle);
              // If the cell does not have any text then we covert it by
              // default to 0 or to an parameterized option set by user.
              if (cellText.replace(/^\s*/, '').replace(/\s*$/, '') === '') {
                  if (opts.convertBlankTo) {
                      cellText = opts.convertBlankTo;
                  } else {
                      continue;
                  }
              }
  
              // Filling up the dataMap based on the rowspan, colspan and
              // position(row=i, column=mapColumnIdx) information of the
              // table cell.
              columnSpan = columnSpan > 1 ? columnSpan : 1;
              rowSpan = rowSpan > 1 ? rowSpan : 1;
  
              if (opts.major === 'row') {
                  k = 0;
                  while (k < columnSpan) {
                      m = 0;
                      while (m < rowSpan) {
                          dataMap[i + m][mapColumnIdx + k] = parseFloat(cellText);
                          m += 1;
                      }
                      k += 1;
                  }
              } else {
                  k = 0;
                  while (k < columnSpan) {
                      m = 0;
                      while (m < rowSpan) {
                          dataMap[mapColumnIdx + k][i + m] = parseFloat(cellText);
                          m += 1;
                      }
                      k += 1;
                  }
              }
          }
          if (tempColumn > dataColumns) {
              dataColumns = tempColumn;
          }
      }
  
      return {
          data: dataMap,
          chartType: chartType ? !isSingleSeries ? 'multi' : 'single' : dataRows > 1 && dataColumns > 1 ? 'multi' : 'single',
          labelMap: columnLabelMap,
          legendMap: rowLabelMap
      };
  },
      createChartFromTable = function (data, obj) {
  
      // Default configuration for HTMLTable data-handler
      var opts = {
          chartAttributes: {},
          major: 'row',
          useLabels: true,
          useLegend: true,
          labelSource: 0,
          legendSource: 0,
          ignoreCols: [],
          ignoreRows: [],
          showLabels: true,
          showLegend: true,
          seriesColors: [],
          convertBlankTo: '0',
          hideTable: false,
          chartType: obj.chartType && obj.chartType(),
  
          // Private Variables
          labels: [],
          legend: [],
          data: []
      },
          config = obj.args.dataConfiguration || {},
          i,
          item1,
          item2,
          categoryArr,
          datasetArr,
          chartJSON = {},
          datasets = {},
          dataObj,
          dataMap,
          labelMap,
          legendMap;
  
      extend(opts, config);
  
      dataObj = extractDataFromTable(data, opts);
      dataMap = dataObj.data;
  
      if (opts.major !== 'row') {
          labelMap = dataObj.legendMap, legendMap = dataObj.labelMap;
      } else {
          labelMap = dataObj.labelMap, legendMap = dataObj.legendMap;
      }
  
      // chartAttributes should contain the configuration attributes for the chart
      // e.g caption, xAxisName, yAxisName etc.
      chartJSON.chart = extend({}, opts.chartAttributes);
  
      if (dataObj.chartType === 'multi') {
          chartJSON.categories = [{ 'category': [] }];
          chartJSON.dataset = [];
  
          categoryArr = chartJSON.categories[0].category;
          datasetArr = chartJSON.dataset;
  
          i = 0;
          for (item1 in dataMap) {
  
              if (opts.showLabels === true) {
                  // If the user has provided custom labels then those should be
                  // shown instead of the extracted labels.
                  categoryArr.push(extend({
                      label: labelMap.labelObj[item1].indexOf(_blankString) != -1 ? '' : labelMap.labelObj[item1]
                  }, opts.labels[i]));
              } else {
                  categoryArr.push({ 'label': '' });
              }
              i += 1;
              for (item2 in dataMap[item1]) {
                  if (typeof datasets[item2] === 'undefined') {
                      datasets[item2] = [];
                  }
                  datasets[item2].push({ 'value': dataMap[item1][item2] });
              }
          }
  
          i = 0;
          for (item1 in datasets) {
              if (opts.showLegend === true) {
                  // If the user has provided custom labels then those should be
                  // shown instead of the extracted labels.
                  datasetArr.push(extend({
                      'seriesname': legendMap.labelObj[item1].indexOf(_blankString) !== -1 ? '' : legendMap.labelObj[item1],
                      'data': datasets[item1]
                  }, opts.legend[i]));
              } else {
                  datasetArr.push({
                      'seriesname': '',
                      'data': datasets[item1]
                  });
              }
              i += 1;
          }
      } else if (dataObj.chartType === 'single') {
          chartJSON.data = [];
          datasetArr = chartJSON.data;
  
          i = 0;
          if (opts.showLabels) {
              for (item1 in dataMap) {
                  for (item2 in dataMap[item1]) {
                      datasetArr.push(extend({
                          label: labelMap.labelObj[item1].indexOf(_blankString) !== -1 ? '' : labelMap.labelObj[item1],
                          value: dataMap[item1][item2]
                      }, opts.labels[i]));
  
                      i += 1;
                  }
              }
          } else {
              for (item1 in dataMap) {
                  for (item2 in dataMap[item1]) {
                      datasetArr.push({ 'value': dataMap[item1][item2] });
                  }
              }
          }
      }
  
      return {
          data: chartJSON,
          error: undefined
      };
  },
      htmlTableToJSON = function (data, obj) {
      return createChartFromTable(data, obj);
  };
  
  /**
   * method to set the HTML table data
   * @param {Object} dom: HTML table dom
   */
  function setHTMLTableData(dom) {
      this.setChartData(dom, 'htmltable');
  }
  /**
   * method to add functions in the fusioncharts prototype
   * @param {Function} FusionCharts is required
   * @return {Object} for extension
   */
  function wrapper(FusionCharts) {
      FusionCharts && (FusionCharts.prototype.setHTMLTableData = setHTMLTableData);
      return {
          format: 'htmltable',
          toJSON: htmlTableToJSON
      };
  }
  
  module.exports = {
      extension: wrapper,
      name: 'HTMLTable',
      type: 'transcoder',
      requiresFusionCharts: true
  };
  
  /***/ })
  /******/ ]);
  });}));
  