text: /**
   * @license Highcharts JS v5.0.0 (2016-09-29)
   * Highcharts Drilldown module
   * 
   * Author: Torstein Honsi
   * License: www.highcharts.com/license
   *
   */
  (function(factory) {
      if (typeof module === 'object' && module.exports) {
          module.exports = factory;
      } else {
          factory(Highcharts);
      }
  }(function(Highcharts) {
      (function(H) {
          /**
           * Highcharts Drilldown module
           * 
           * Author: Torstein Honsi
           * License: www.highcharts.com/license
           *
           */
  
          'use strict';
  
          var noop = H.noop,
              color = H.color,
              defaultOptions = H.defaultOptions,
              each = H.each,
              extend = H.extend,
              format = H.format,
              pick = H.pick,
              wrap = H.wrap,
              Chart = H.Chart,
              seriesTypes = H.seriesTypes,
              PieSeries = seriesTypes.pie,
              ColumnSeries = seriesTypes.column,
              Tick = H.Tick,
              fireEvent = H.fireEvent,
              inArray = H.inArray,
              ddSeriesId = 1;
  
          // Utilities
          /*
           * Return an intermediate color between two colors, according to pos where 0
           * is the from color and 1 is the to color. This method is copied from ColorAxis.js
           * and should always be kept updated, until we get AMD support.
           */
          function tweenColors(from, to, pos) {
              // Check for has alpha, because rgba colors perform worse due to lack of
              // support in WebKit.
              var hasAlpha,
                  ret;
  
              // Unsupported color, return to-color (#3920)
              if (!to.rgba.length || !from.rgba.length) {
                  ret = to.input || 'none';
  
                  // Interpolate
              } else {
                  from = from.rgba;
                  to = to.rgba;
                  hasAlpha = (to[3] !== 1 || from[3] !== 1);
                  ret = (hasAlpha ? 'rgba(' : 'rgb(') +
                      Math.round(to[0] + (from[0] - to[0]) * (1 - pos)) + ',' +
                      Math.round(to[1] + (from[1] - to[1]) * (1 - pos)) + ',' +
                      Math.round(to[2] + (from[2] - to[2]) * (1 - pos)) +
                      (hasAlpha ? (',' + (to[3] + (from[3] - to[3]) * (1 - pos))) : '') + ')';
              }
              return ret;
          }
          /**
           * Handle animation of the color attributes directly
           */
          each(['fill', 'stroke'], function(prop) {
              H.Fx.prototype[prop + 'Setter'] = function() {
                  this.elem.attr(prop, tweenColors(color(this.start), color(this.end), this.pos));
              };
          });
  
          // Add language
          extend(defaultOptions.lang, {
              drillUpText: '◁ Back to {series.name}'
          });
          defaultOptions.drilldown = {
  
              animation: {
                  duration: 500
              },
              drillUpButton: {
                  position: {
                      align: 'right',
                      x: -10,
                      y: 10
                  }
                  // relativeTo: 'plotBox'
                  // theme
              }
          };
  
          /**
           * A general fadeIn method
           */
          H.SVGRenderer.prototype.Element.prototype.fadeIn = function(animation) {
              this
                  .attr({
                      opacity: 0.1,
                      visibility: 'inherit'
                  })
                  .animate({
                      opacity: pick(this.newOpacity, 1) // newOpacity used in maps
                  }, animation || {
                      duration: 250
                  });
          };
  
          Chart.prototype.addSeriesAsDrilldown = function(point, ddOptions) {
              this.addSingleSeriesAsDrilldown(point, ddOptions);
              this.applyDrilldown();
          };
          Chart.prototype.addSingleSeriesAsDrilldown = function(point, ddOptions) {
              var oldSeries = point.series,
                  xAxis = oldSeries.xAxis,
                  yAxis = oldSeries.yAxis,
                  newSeries,
                  pointIndex,
                  levelSeries = [],
                  levelSeriesOptions = [],
                  level,
                  levelNumber,
                  last,
                  colorProp;
  
  
  
              colorProp = {
                  colorIndex: pick(point.colorIndex, oldSeries.colorIndex)
              };
  
  
              if (!this.drilldownLevels) {
                  this.drilldownLevels = [];
              }
  
              levelNumber = oldSeries.options._levelNumber || 0;
  
              // See if we can reuse the registered series from last run
              last = this.drilldownLevels[this.drilldownLevels.length - 1];
              if (last && last.levelNumber !== levelNumber) {
                  last = undefined;
              }
  
              ddOptions = extend(extend({
                  _ddSeriesId: ddSeriesId++
              }, colorProp), ddOptions);
              pointIndex = inArray(point, oldSeries.points);
  
              // Record options for all current series
              each(oldSeries.chart.series, function(series) {
                  if (series.xAxis === xAxis && !series.isDrilling) {
                      series.options._ddSeriesId = series.options._ddSeriesId || ddSeriesId++;
                      series.options._colorIndex = series.userOptions._colorIndex;
                      series.options._levelNumber = series.options._levelNumber || levelNumber; // #3182
  
                      if (last) {
                          levelSeries = last.levelSeries;
                          levelSeriesOptions = last.levelSeriesOptions;
                      } else {
                          levelSeries.push(series);
                          levelSeriesOptions.push(series.options);
                      }
                  }
              });
  
              // Add a record of properties for each drilldown level
              level = extend({
                  levelNumber: levelNumber,
                  seriesOptions: oldSeries.options,
                  levelSeriesOptions: levelSeriesOptions,
                  levelSeries: levelSeries,
                  shapeArgs: point.shapeArgs,
                  bBox: point.graphic ? point.graphic.getBBox() : {}, // no graphic in line series with markers disabled
                  lowerSeriesOptions: ddOptions,
                  pointOptions: oldSeries.options.data[pointIndex],
                  pointIndex: pointIndex,
                  oldExtremes: {
                      xMin: xAxis && xAxis.userMin,
                      xMax: xAxis && xAxis.userMax,
                      yMin: yAxis && yAxis.userMin,
                      yMax: yAxis && yAxis.userMax
                  }
              }, colorProp);
  
              // Push it to the lookup array
              this.drilldownLevels.push(level);
  
              newSeries = level.lowerSeries = this.addSeries(ddOptions, false);
              newSeries.options._levelNumber = levelNumber + 1;
              if (xAxis) {
                  xAxis.oldPos = xAxis.pos;
                  xAxis.userMin = xAxis.userMax = null;
                  yAxis.userMin = yAxis.userMax = null;
              }
  
              // Run fancy cross-animation on supported and equal types
              if (oldSeries.type === newSeries.type) {
                  newSeries.animate = newSeries.animateDrilldown || noop;
                  newSeries.options.animation = true;
              }
          };
  
          Chart.prototype.applyDrilldown = function() {
              var drilldownLevels = this.drilldownLevels,
                  levelToRemove;
  
              if (drilldownLevels && drilldownLevels.length > 0) { // #3352, async loading
                  levelToRemove = drilldownLevels[drilldownLevels.length - 1].levelNumber;
                  each(this.drilldownLevels, function(level) {
                      if (level.levelNumber === levelToRemove) {
                          each(level.levelSeries, function(series) {
                              if (series.options && series.options._levelNumber === levelToRemove) { // Not removed, not added as part of a multi-series drilldown
                                  series.remove(false);
                              }
                          });
                      }
                  });
              }
  
              this.redraw();
              this.showDrillUpButton();
          };
  
          Chart.prototype.getDrilldownBackText = function() {
              var drilldownLevels = this.drilldownLevels,
                  lastLevel;
              if (drilldownLevels && drilldownLevels.length > 0) { // #3352, async loading
                  lastLevel = drilldownLevels[drilldownLevels.length - 1];
                  lastLevel.series = lastLevel.seriesOptions;
                  return format(this.options.lang.drillUpText, lastLevel);
              }
  
          };
  
          Chart.prototype.showDrillUpButton = function() {
              var chart = this,
                  backText = this.getDrilldownBackText(),
                  buttonOptions = chart.options.drilldown.drillUpButton,
                  attr,
                  states;
  
  
              if (!this.drillUpButton) {
                  attr = buttonOptions.theme;
                  states = attr && attr.states;
  
                  this.drillUpButton = this.renderer.button(
                          backText,
                          null,
                          null,
                          function() {
                              chart.drillUp();
                          },
                          attr,
                          states && states.hover,
                          states && states.select
                      )
                      .addClass('highcharts-drillup-button')
                      .attr({
                          align: buttonOptions.position.align,
                          zIndex: 7
                      })
                      .add()
                      .align(buttonOptions.position, false, buttonOptions.relativeTo || 'plotBox');
              } else {
                  this.drillUpButton.attr({
                          text: backText
                      })
                      .align();
              }
          };
  
          Chart.prototype.drillUp = function() {
              var chart = this,
                  drilldownLevels = chart.drilldownLevels,
                  levelNumber = drilldownLevels[drilldownLevels.length - 1].levelNumber,
                  i = drilldownLevels.length,
                  chartSeries = chart.series,
                  seriesI,
                  level,
                  oldSeries,
                  newSeries,
                  oldExtremes,
                  addSeries = function(seriesOptions) {
                      var addedSeries;
                      each(chartSeries, function(series) {
                          if (series.options._ddSeriesId === seriesOptions._ddSeriesId) {
                              addedSeries = series;
                          }
                      });
  
                      addedSeries = addedSeries || chart.addSeries(seriesOptions, false);
                      if (addedSeries.type === oldSeries.type && addedSeries.animateDrillupTo) {
                          addedSeries.animate = addedSeries.animateDrillupTo;
                      }
                      if (seriesOptions === level.seriesOptions) {
                          newSeries = addedSeries;
                      }
                  };
  
              while (i--) {
  
                  level = drilldownLevels[i];
                  if (level.levelNumber === levelNumber) {
                      drilldownLevels.pop();
  
                      // Get the lower series by reference or id
                      oldSeries = level.lowerSeries;
                      if (!oldSeries.chart) { // #2786
                          seriesI = chartSeries.length; // #2919
                          while (seriesI--) {
                              if (chartSeries[seriesI].options.id === level.lowerSeriesOptions.id &&
                                  chartSeries[seriesI].options._levelNumber === levelNumber + 1) { // #3867
                                  oldSeries = chartSeries[seriesI];
                                  break;
                              }
                          }
                      }
                      oldSeries.xData = []; // Overcome problems with minRange (#2898)
  
                      each(level.levelSeriesOptions, addSeries);
  
                      fireEvent(chart, 'drillup', {
                          seriesOptions: level.seriesOptions
                      });
  
                      if (newSeries.type === oldSeries.type) {
                          newSeries.drilldownLevel = level;
                          newSeries.options.animation = chart.options.drilldown.animation;
  
                          if (oldSeries.animateDrillupFrom && oldSeries.chart) { // #2919
                              oldSeries.animateDrillupFrom(level);
                          }
                      }
                      newSeries.options._levelNumber = levelNumber;
  
                      oldSeries.remove(false);
  
                      // Reset the zoom level of the upper series
                      if (newSeries.xAxis) {
                          oldExtremes = level.oldExtremes;
                          newSeries.xAxis.setExtremes(oldExtremes.xMin, oldExtremes.xMax, false);
                          newSeries.yAxis.setExtremes(oldExtremes.yMin, oldExtremes.yMax, false);
                      }
                  }
              }
  
              // Fire a once-off event after all series have been drilled up (#5158)
              fireEvent(chart, 'drillupall');
  
              this.redraw();
  
              if (this.drilldownLevels.length === 0) {
                  this.drillUpButton = this.drillUpButton.destroy();
              } else {
                  this.drillUpButton.attr({
                          text: this.getDrilldownBackText()
                      })
                      .align();
              }
  
              this.ddDupes.length = []; // #3315
          };
  
  
          ColumnSeries.prototype.supportsDrilldown = true;
  
          /**
           * When drilling up, keep the upper series invisible until the lower series has
           * moved into place
           */
          ColumnSeries.prototype.animateDrillupTo = function(init) {
              if (!init) {
                  var newSeries = this,
                      level = newSeries.drilldownLevel;
  
                  each(this.points, function(point) {
                      if (point.graphic) { // #3407
                          point.graphic.hide();
                      }
                      if (point.dataLabel) {
                          point.dataLabel.hide();
                      }
                      if (point.connector) {
                          point.connector.hide();
                      }
                  });
  
  
                  // Do dummy animation on first point to get to complete
                  setTimeout(function() {
                      if (newSeries.points) { // May be destroyed in the meantime, #3389
                          each(newSeries.points, function(point, i) {
                              // Fade in other points			  
                              var verb = i === (level && level.pointIndex) ? 'show' : 'fadeIn',
                                  inherit = verb === 'show' ? true : undefined;
                              if (point.graphic) { // #3407
                                  point.graphic[verb](inherit);
                              }
                              if (point.dataLabel) {
                                  point.dataLabel[verb](inherit);
                              }
                              if (point.connector) {
                                  point.connector[verb](inherit);
                              }
                          });
                      }
                  }, Math.max(this.chart.options.drilldown.animation.duration - 50, 0));
  
                  // Reset
                  this.animate = noop;
              }
  
          };
  
          ColumnSeries.prototype.animateDrilldown = function(init) {
              var series = this,
                  drilldownLevels = this.chart.drilldownLevels,
                  animateFrom,
                  animationOptions = this.chart.options.drilldown.animation,
                  xAxis = this.xAxis;
  
              if (!init) {
                  each(drilldownLevels, function(level) {
                      if (series.options._ddSeriesId === level.lowerSeriesOptions._ddSeriesId) {
                          animateFrom = level.shapeArgs;
  
                      }
                  });
  
                  animateFrom.x += (pick(xAxis.oldPos, xAxis.pos) - xAxis.pos);
  
                  each(this.points, function(point) {
                      var animateTo = point.shapeArgs;
  
  
  
                      if (point.graphic) {
                          point.graphic
                              .attr(animateFrom)
                              .animate(
                                  extend(point.shapeArgs, {
                                      fill: point.color || series.color
                                  }),
                                  animationOptions
                              );
                      }
                      if (point.dataLabel) {
                          point.dataLabel.fadeIn(animationOptions);
                      }
                  });
                  this.animate = null;
              }
  
          };
  
          /**
           * When drilling up, pull out the individual point graphics from the lower series
           * and animate them into the origin point in the upper series.
           */
          ColumnSeries.prototype.animateDrillupFrom = function(level) {
              var animationOptions = this.chart.options.drilldown.animation,
                  group = this.group,
                  series = this;
  
              // Cancel mouse events on the series group (#2787)
              each(series.trackerGroups, function(key) {
                  if (series[key]) { // we don't always have dataLabelsGroup
                      series[key].on('mouseover');
                  }
              });
  
  
              delete this.group;
              each(this.points, function(point) {
                  var graphic = point.graphic,
                      animateTo = level.shapeArgs,
                      complete = function() {
                          graphic.destroy();
                          if (group) {
                              group = group.destroy();
                          }
                      };
  
                  if (graphic) {
  
                      delete point.graphic;
  
  
  
                      if (animationOptions) {
                          graphic.animate(
                              animateTo,
                              H.merge(animationOptions, {
                                  complete: complete
                              })
                          );
                      } else {
                          graphic.attr(animateTo);
                          complete();
                      }
                  }
              });
          };
  
          if (PieSeries) {
              extend(PieSeries.prototype, {
                  supportsDrilldown: true,
                  animateDrillupTo: ColumnSeries.prototype.animateDrillupTo,
                  animateDrillupFrom: ColumnSeries.prototype.animateDrillupFrom,
  
                  animateDrilldown: function(init) {
                      var level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
                          animationOptions = this.chart.options.drilldown.animation,
                          animateFrom = level.shapeArgs,
                          start = animateFrom.start,
                          angle = animateFrom.end - start,
                          startAngle = angle / this.points.length;
  
                      if (!init) {
                          each(this.points, function(point, i) {
                              var animateTo = point.shapeArgs;
  
  
  
                              if (point.graphic) {
                                  point.graphic
                                      .attr(H.merge(animateFrom, {
                                          start: start + i * startAngle,
                                          end: start + (i + 1) * startAngle
                                      }))[animationOptions ? 'animate' : 'attr'](
                                          animateTo,
                                          animationOptions
                                      );
                              }
                          });
                          this.animate = null;
                      }
                  }
              });
          }
  
          H.Point.prototype.doDrilldown = function(_holdRedraw, category, originalEvent) {
              var series = this.series,
                  chart = series.chart,
                  drilldown = chart.options.drilldown,
                  i = (drilldown.series || []).length,
                  seriesOptions;
  
              if (!chart.ddDupes) {
                  chart.ddDupes = [];
              }
  
              while (i-- && !seriesOptions) {
                  if (drilldown.series[i].id === this.drilldown && inArray(this.drilldown, chart.ddDupes) === -1) {
                      seriesOptions = drilldown.series[i];
                      chart.ddDupes.push(this.drilldown);
                  }
              }
  
              // Fire the event. If seriesOptions is undefined, the implementer can check for 
              // seriesOptions, and call addSeriesAsDrilldown async if necessary.
              fireEvent(chart, 'drilldown', {
                  point: this,
                  seriesOptions: seriesOptions,
                  category: category,
                  originalEvent: originalEvent,
                  points: category !== undefined && this.series.xAxis.getDDPoints(category).slice(0)
              }, function(e) {
                  var chart = e.point.series && e.point.series.chart,
                      seriesOptions = e.seriesOptions;
                  if (chart && seriesOptions) {
                      if (_holdRedraw) {
                          chart.addSingleSeriesAsDrilldown(e.point, seriesOptions);
                      } else {
                          chart.addSeriesAsDrilldown(e.point, seriesOptions);
                      }
                  }
              });
  
  
          };
  
          /**
           * Drill down to a given category. This is the same as clicking on an axis label.
           */
          H.Axis.prototype.drilldownCategory = function(x, e) {
              var key,
                  point,
                  ddPointsX = this.getDDPoints(x);
              for (key in ddPointsX) {
                  point = ddPointsX[key];
                  if (point && point.series && point.series.visible && point.doDrilldown) { // #3197
                      point.doDrilldown(true, x, e);
                  }
              }
              this.chart.applyDrilldown();
          };
  
          /**
           * Return drillable points for this specific X value
           */
          H.Axis.prototype.getDDPoints = function(x) {
              var ret = [];
              each(this.series, function(series) {
                  var i,
                      xData = series.xData,
                      points = series.points;
  
                  for (i = 0; i < xData.length; i++) {
                      if (xData[i] === x && series.options.data[i].drilldown) {
                          ret.push(points ? points[i] : true);
                          break;
                      }
                  }
              });
              return ret;
          };
  
  
          /**
           * Make a tick label drillable, or remove drilling on update
           */
          Tick.prototype.drillable = function() {
              var pos = this.pos,
                  label = this.label,
                  axis = this.axis,
                  isDrillable = axis.coll === 'xAxis' && axis.getDDPoints,
                  ddPointsX = isDrillable && axis.getDDPoints(pos);
  
              if (isDrillable) {
                  if (label && ddPointsX.length) {
                      label.drillable = true;
  
  
  
                      label
                          .addClass('highcharts-drilldown-axis-label')
  
                      .on('click', function(e) {
                          axis.drilldownCategory(pos, e);
                      });
  
                  } else if (label && label.drillable) {
  
  
  
                      label.on('click', null); // #3806			
                      label.removeClass('highcharts-drilldown-axis-label');
                  }
              }
          };
  
          /**
           * Always keep the drillability updated (#3951)
           */
          wrap(Tick.prototype, 'addLabel', function(proceed) {
              proceed.call(this);
              this.drillable();
          });
  
  
          /**
           * On initialization of each point, identify its label and make it clickable. Also, provide a
           * list of points associated to that label.
           */
          wrap(H.Point.prototype, 'init', function(proceed, series, options, x) {
              var point = proceed.call(this, series, options, x),
                  xAxis = series.xAxis,
                  tick = xAxis && xAxis.ticks[x];
  
              if (point.drilldown) {
  
                  // Add the click event to the point 
                  H.addEvent(point, 'click', function(e) {
                      if (series.xAxis && series.chart.options.drilldown.allowPointDrilldown === false) {
                          series.xAxis.drilldownCategory(x, e);
                      } else {
                          point.doDrilldown(undefined, undefined, e);
                      }
                  });
                  /*wrap(point, 'importEvents', function (proceed) { // wrapping importEvents makes point.click event work
                  	if (!this.hasImportedEvents) {
                  		proceed.call(this);
                  		H.addEvent(this, 'click', function () {
                  			this.doDrilldown();
                  		});
                  	}
                  });*/
  
              }
  
              // Add or remove click handler and style on the tick label
              if (tick) {
                  tick.drillable();
              }
  
              return point;
          });
  
          wrap(H.Series.prototype, 'drawDataLabels', function(proceed) {
              var css = this.chart.options.drilldown.activeDataLabelStyle,
                  renderer = this.chart.renderer;
  
              proceed.call(this);
  
              each(this.points, function(point) {
                  var pointCSS = {};
                  if (point.drilldown && point.dataLabel) {
                      if (css.color === 'contrast') {
                          pointCSS.color = renderer.getContrast(point.color || this.color);
                      }
                      point.dataLabel
                          .addClass('highcharts-drilldown-data-label');
  
  
                  }
              }, this);
          });
  
          // Mark the trackers with a pointer 
          var type,
              drawTrackerWrapper = function(proceed) {
                  proceed.call(this);
                  each(this.points, function(point) {
                      if (point.drilldown && point.graphic) {
                          point.graphic.addClass('highcharts-drilldown-point');
  
  
                      }
                  });
              };
          for (type in seriesTypes) {
              if (seriesTypes[type].prototype.supportsDrilldown) {
                  wrap(seriesTypes[type].prototype, 'drawTracker', drawTrackerWrapper);
              }
          }
  
      }(Highcharts));
  }));
  