text:
/**
 * @license Highcharts JS v6.2.0 (2018-10-17)
 * Tree Grid
 *
 * (c) 2016 Jon Arild Nygard
 *
 * --- WORK IN PROGRESS ---
 *
 * License: www.highcharts.com/license
 */
'use strict';
(function (factory) {
	if (typeof module === 'object' && module.exports) {
		module.exports = factory;
	} else if (typeof define === 'function' && define.amd) {
		define(function () {
			return factory;
		});
	} else {
		factory(Highcharts);
	}
}(function (Highcharts) {
	(function (H) {
		/**
		* (c) 2016 Highsoft AS
		* Authors: Lars A. V. Cabrera
		*
		* License: www.highcharts.com/license
		*/

		var argsToArray = function (args) {
		        return Array.prototype.slice.call(args, 1);
		    },
		    dateFormat = H.dateFormat,
		    defined = H.defined,
		    each = H.each,
		    isArray = H.isArray,
		    isNumber = H.isNumber,
		    isObject = function (x) {
		        // Always use strict mode
		        return H.isObject(x, true);
		    },
		    merge = H.merge,
		    pick = H.pick,
		    wrap = H.wrap,
		    Axis = H.Axis,
		    Tick = H.Tick;

		/**
		 * Set grid options for the axis labels. Requires Highcharts Gantt.
		 *
		 * @type      {object}
		 * @since     6.2.0
		 * @product   gantt
		 * @apioption xAxis.grid
		 */

		/**
		 * Enable grid on the axis labels. Defaults to true for Gantt charts.
		 *
		 * @type      {boolean}
		 * @since     6.2.0
		 * @default   true
		 * @product   gantt
		 * @apioption xAxis.grid.enabled
		 */

		/**
		 * Set specific options for each column (or row for horizontal axes) in the
		 * grid. Each extra column/row is its own axis, and the axis options can be set
		 * here.
		 *
		 * @type      {Array<object>}
		 * @sample    gantt/demo/left-axis-table
		 *            Left axis as a table
		 * @apioption xAxis.grid.columns
		 */

		/**
		 * Set border color for the label grid lines.
		 *
		 * @type      {Highcharts.ColorString}
		 * @apioption xAxis.grid.borderColor
		 */

		/**
		 * Set border width of the label grid lines.
		 *
		 * @type      {number}
		 * @default 1
		 * @apioption xAxis.grid.borderWidth
		 */

		/**
		 * Set cell height for grid axis labels. By default this is calculated from font
		 * size.
		 *
		 * @type      {number}
		 * @default null
		 * @apioption xAxis.grid.cellHeight
		 */

		// Enum for which side the axis is on.
		// Maps to axis.side
		var axisSide = {
		    top: 0,
		    right: 1,
		    bottom: 2,
		    left: 3,
		    0: 'top',
		    1: 'right',
		    2: 'bottom',
		    3: 'left'
		};

		/**
		 * Checks if an axis is a navigator axis.
		 * @return {Boolean} true if axis is found in axis.chart.navigator
		 */
		Axis.prototype.isNavigatorAxis = function () {
		    return /highcharts-navigator-[xy]axis/.test(this.options.className);
		};

		/**
		 * Checks if an axis is the outer axis in its dimension. Since
		 * axes are placed outwards in order, the axis with the highest
		 * index is the outermost axis.
		 *
		 * Example: If there are multiple x-axes at the top of the chart,
		 * this function returns true if the axis supplied is the last
		 * of the x-axes.
		 *
		 * @return true if the axis is the outermost axis in its dimension;
		 *         false if not
		 */
		Axis.prototype.isOuterAxis = function () {
		    var axis = this,
		        chart = axis.chart,
		        thisIndex = -1,
		        isOuter = true;

		    each(chart.axes, function (otherAxis, index) {
		        if (otherAxis.side === axis.side && !otherAxis.isNavigatorAxis()) {
		            if (otherAxis === axis) {
		                // Get the index of the axis in question
		                thisIndex = index;

		                // Check thisIndex >= 0 in case thisIndex has
		                // not been found yet
		            } else if (thisIndex >= 0 && index > thisIndex) {
		                // There was an axis on the same side with a
		                // higher index.
		                isOuter = false;
		            }
		        }
		    });
		    // There were either no other axes on the same side,
		    // or the other axes were not farther from the chart
		    return isOuter;
		};

		/**
		 * Get the largest label width and height.
		 * @param {object} ticks All the ticks on one axis.
		 * @param {array} tickPositions All the tick positions on one axis.
		 * @return {object} object containing the properties height and width.
		 */
		Axis.prototype.getMaxLabelDimensions = function (ticks, tickPositions) {
		    var dimensions = {
		        width: 0,
		        height: 0
		    };

		    each(tickPositions, function (pos) {
		        var tick = ticks[pos],
		            tickHeight = 0,
		            tickWidth = 0,
		            label;

		        if (isObject(tick)) {
		            label = isObject(tick.label) ? tick.label : {};

		            // Find width and height of tick
		            tickHeight = label.getBBox ? label.getBBox().height : 0;
		            tickWidth = isNumber(label.textPxLength) ? label.textPxLength : 0;

		            // Update the result if width and/or height are larger
		            dimensions.height = Math.max(tickHeight, dimensions.height);
		            dimensions.width = Math.max(tickWidth, dimensions.width);
		        }
		    });

		    return dimensions;
		};

		/**
		 * Add custom date formats
		 */
		H.dateFormats = {
		    // Week number
		    W: function (timestamp) {
		        var d = new Date(timestamp),
		            yearStart,
		            weekNo;
		        d.setHours(0, 0, 0, 0);
		        d.setDate(d.getDate() - (d.getDay() || 7));
		        yearStart = new Date(d.getFullYear(), 0, 1);
		        weekNo = Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
		        return weekNo;
		    },
		    // First letter of the day of the week, e.g. 'M' for 'Monday'.
		    E: function (timestamp) {
		        return dateFormat('%a', timestamp, true).charAt(0);
		    }
		};

		/**
		 * If chart is stockChart, always return 'left' to avoid labels being placed
		 * inside chart. Stock charts place yAxis labels inside by default.
		 * @param {function} proceed - the original function
		 * @return {string} 'left' if stockChart, or auto calculated alignment
		 */
		wrap(Axis.prototype, 'autoLabelAlign', function (proceed) {
		    var axis = this,
		        retVal;
		    if (axis.chart.isStock) {
		        retVal = 'left';
		    } else {
		        retVal = proceed.apply(axis, argsToArray(arguments));
		    }
		    return retVal;
		});

		/**
		 * Center tick labels in cells.
		 *
		 * @param {function} proceed - the original function
		 *
		 * @return {object} object - an object containing x and y positions
		 *                           for the tick
		 */
		wrap(Tick.prototype, 'getLabelPosition', function (proceed, x, y, label, horiz,
		            labelOpts, tickmarkOffset, index) {
		    var tick = this,
		        axis = tick.axis,
		        reversed = axis.reversed,
		        chart = axis.chart,
		        options = axis.options,
		        gridOptions = (options && isObject(options.grid)) ? options.grid : {},
		        align = labelOpts.align,
		        // verticalAlign is currently not supported for axis.labels.
		        verticalAlign = 'middle', // labelOpts.verticalAlign,
		        side = axisSide[axis.side],
		        tickPositions = axis.tickPositions,
		        tickPos = tick.pos - tickmarkOffset,
		        nextTickPos = (
		            isNumber(tickPositions[index + 1]) ?
		            tickPositions[index + 1] - tickmarkOffset :
		            axis.max + tickmarkOffset
		        ),
		        tickSize = axis.tickSize('tick', true),
		        tickWidth = isArray(tickSize) ? tickSize[0] : 0,
		        crispCorr = tickSize && tickSize[1] / 2,
		        labelHeight,
		        lblMetrics,
		        lines,
		        result,
		        bottom,
		        top,
		        left,
		        right;

		    // Only center tick labels in grid axes
		    if (gridOptions.enabled === true) {
		        /**
		         * Calculate top and bottom positions of the cell.
		         */
		        if (side === 'top') {
		            bottom = axis.top + axis.offset;
		            top = bottom - tickWidth;
		        } else if (side === 'bottom') {
		            top = chart.chartHeight - axis.bottom + axis.offset;
		            bottom = top + tickWidth;
		        } else {
		            bottom = axis.top + axis.len - axis.translate(
		                reversed ? nextTickPos : tickPos
		            );
		            top = axis.top + axis.len - axis.translate(
		                reversed ? tickPos : nextTickPos
		            );
		        }

		        /**
		         * Calculate left and right positions of the cell.
		         */
		        if (side === 'right') {
		            left = chart.chartWidth - axis.right + axis.offset;
		            right = left + tickWidth;
		        } else if (side === 'left') {
		            right = axis.left + axis.offset;
		            left = right - tickWidth;
		        } else {
		            left = Math.round(axis.left + axis.translate(
		                reversed ? nextTickPos : tickPos
		            )) - crispCorr;
		            right = Math.round(axis.left + axis.translate(
		                reversed ? tickPos : nextTickPos
		            )) - crispCorr;
		        }

		        tick.slotWidth = right - left;

		        /**
		         * Calculate the positioning of the label based on alignment.
		         */
		        result = {
		            x: (
		                align === 'left' ?
		                left :
		                align === 'right' ?
		                right :
		                left + ((right - left) / 2) // default to center
		            ),
		            y: (
		                verticalAlign === 'top' ?
		                top :
		                verticalAlign === 'bottom' ?
		                bottom :
		                top + ((bottom - top) / 2) // default to middle
		            )
		        };

		        lblMetrics = chart.renderer.fontMetrics(
		            labelOpts.style.fontSize,
		            label.element
		        );
		        labelHeight = label.getBBox().height;

		        // Adjustment to y position to align the label correctly.
		        // Would be better to have a setter or similar for this.
		        if (!labelOpts.useHTML) {
		            lines = Math.round(labelHeight / lblMetrics.h);
		            result.y += (
		                // Center the label
		                // TODO: why does this actually center the label?
		                ((lblMetrics.b - (lblMetrics.h - lblMetrics.f)) / 2) +
		                // Adjust for height of additional lines.
		                -(((lines - 1) * lblMetrics.h) / 2)
		            );
		        } else {
		            result.y += (
		                // Readjust yCorr in htmlUpdateTransform
		                lblMetrics.b +
		                // Adjust for height of html label
		                -(labelHeight / 2)
		            );
		        }

		        result.x += (axis.horiz && labelOpts.x || 0);
		    } else {
		        result = proceed.apply(tick, argsToArray(arguments));
		    }
		    return result;
		});

		/**
		 * Draw vertical axis ticks extra long to create cell floors and roofs.
		 * Overrides the tickLength for vertical axes.
		 *
		 * @param {function} proceed - the original function
		 * @returns {array} retVal -
		 */
		wrap(Axis.prototype, 'tickSize', function (proceed) {
		    var axis = this,
		        dimensions = axis.maxLabelDimensions,
		        options = axis.options,
		        gridOptions = (options && isObject(options.grid)) ? options.grid : {},
		        retVal = proceed.apply(axis, argsToArray(arguments)),
		        labelPadding,
		        distance;

		    if (gridOptions.enabled === true) {
		        labelPadding = (Math.abs(axis.defaultLeftAxisOptions.labels.x) * 2);
		        distance = labelPadding +
		            (axis.horiz ? dimensions.height : dimensions.width);

		        if (isArray(retVal)) {
		            retVal[0] = distance;
		        } else {
		            retVal = [distance];
		        }
		    }
		    return retVal;
		});

		wrap(Axis.prototype, 'getTitlePosition', function (proceed) {
		    var axis = this,
		        options = axis.options,
		        gridOptions = (options && isObject(options.grid)) ? options.grid : {};

		    if (gridOptions.enabled === true) {
		        // compute anchor points for each of the title align options
		        var title = axis.axisTitle,
		            titleWidth = title && title.getBBox().width,
		            horiz = axis.horiz,
		            axisLeft = axis.left,
		            axisTop = axis.top,
		            axisWidth = axis.width,
		            axisHeight = axis.height,
		            axisTitleOptions = options.title,
		            opposite = axis.opposite,
		            offset = axis.offset,
		            tickSize = axis.tickSize() || [0],
		            xOption = axisTitleOptions.x || 0,
		            yOption = axisTitleOptions.y || 0,
		            titleMargin = pick(axisTitleOptions.margin, horiz ? 5 : 10),
		            titleFontSize = axis.chart.renderer.fontMetrics(
		                axisTitleOptions.style && axisTitleOptions.style.fontSize,
		                title
		            ).f,
		            // TODO account for alignment
		            // the position in the perpendicular direction of the axis
		            offAxis = (horiz ? axisTop + axisHeight : axisLeft) +
		                (horiz ? 1 : -1) * // horizontal axis reverses the margin
		                (opposite ? -1 : 1) * // so does opposite axes
		                (tickSize[0] / 2) +
		                (axis.side === axisSide.bottom ? titleFontSize : 0);

		        return {
		            x: horiz ?
		                axisLeft - titleWidth / 2 - titleMargin + xOption :
		                offAxis + (opposite ? axisWidth : 0) + offset + xOption,
		            y: horiz ?
		                (
		                    offAxis -
		                    (opposite ? axisHeight : 0) +
		                    (opposite ? titleFontSize : -titleFontSize) / 2 +
		                    offset +
		                    yOption
		                ) :
		                axisTop - titleMargin + yOption
		        };
		    }

		    return proceed.apply(this, argsToArray(arguments));
		});

		/**
		 * Avoid altering tickInterval when reserving space.
		 */
		wrap(Axis.prototype, 'unsquish', function (proceed) {
		    var axis = this,
		        options = axis.options,
		        gridOptions = (options && isObject(options.grid)) ? options.grid : {};

		    if (gridOptions.enabled === true && this.categories) {
		        return this.tickInterval;
		    }

		    return proceed.apply(this, argsToArray(arguments));
		});

		/**
		 * Creates a left and right wall on horizontal axes:
		 * - Places leftmost tick at the start of the axis, to create a left wall
		 * - Ensures that the rightmost tick is at the end of the axis, to create a
		 *    right wall.
		 *
		 * @param {function} proceed - the original function
		 * @param {object} options - the pure axis options as input by the user
		 */
		H.addEvent(Axis, 'afterSetOptions', function (e) {
		    var options = this.options,
		        userOptions = e.userOptions,
		        gridAxisOptions,
		        gridOptions = (options && isObject(options.grid)) ? options.grid : {};

		    if (gridOptions.enabled === true) {

		        // Merge the user options into default grid axis options so that when a
		        // user option is set, it takes presedence.
		        gridAxisOptions = merge(true, {

		            className: 'highcharts-grid-axis ' + (userOptions.className || ''),

		            dateTimeLabelFormats: {
		                hour: {
		                    list: ['%H:%M', '%H']
		                },
		                day: {
		                    list: ['%A, %e. %B', '%a, %e. %b', '%E']
		                },
		                week: {
		                    list: ['Week %W', 'W%W']
		                },
		                month: {
		                    list: ['%B', '%b', '%o']
		                }
		            },

		            grid: {
		                borderWidth: 1
		            },

		            labels: {
		                padding: 2,
		                style: {
		                    fontSize: '13px'
		                }
		            },

		            title: {
		                text: null,
		                reserveSpace: false,
		                rotation: 0
		            },

		            // In a grid axis, only allow one unit of certain types, for example
		            // we shouln't have one grid cell spanning two days.
		            units: [[
		                'millisecond', // unit name
		                [1, 10, 100]
		            ], [
		                'second',
		                [1, 10]
		            ], [
		                'minute',
		                [1, 5, 15]
		            ], [
		                'hour',
		                [1, 6]
		            ], [
		                'day',
		                [1]
		            ], [
		                'week',
		                [1]
		            ], [
		                'month',
		                [1]
		            ], [
		                'year',
		                null
		            ]]
		        }, userOptions);

		        // X-axis specific options
		        if (this.coll === 'xAxis') {

		            // For linked axes, tickPixelInterval is used only if the
		            // tickPositioner below doesn't run or returns undefined (like
		            // multiple years)
		            if (
		                defined(userOptions.linkedTo) &&
		                !defined(userOptions.tickPixelInterval)
		            ) {
		                gridAxisOptions.tickPixelInterval = 350;
		            }

		            // For the secondary grid axis, use the primary axis' tick intervals
		            // and return ticks one level higher.
		            if (
		                // Check for tick pixel interval in options
		                !defined(userOptions.tickPixelInterval) &&

		                // Only for linked axes
		                defined(userOptions.linkedTo) &&

		                !defined(userOptions.tickPositioner) &&
		                !defined(userOptions.tickInterval)
		            ) {
		                gridAxisOptions.tickPositioner = function (min, max) {

		                    var parentInfo = (
		                        this.linkedParent &&
		                        this.linkedParent.tickPositions &&
		                        this.linkedParent.tickPositions.info
		                    );

		                    if (parentInfo) {

		                        var unitIdx,
		                            count,
		                            unitName,
		                            i,
		                            units = gridAxisOptions.units,
		                            unitRange;

		                        for (i = 0; i < units.length; i++) {
		                            if (units[i][0] === parentInfo.unitName) {
		                                unitIdx = i;
		                                break;
		                            }
		                        }

		                        // Spanning multiple years, go default
		                        if (!units[unitIdx][1]) {
		                            return;
		                        }

		                        // Get the first allowed count on the next unit.
		                        if (units[unitIdx + 1]) {
		                            unitName = units[unitIdx + 1][0];
		                            count = (units[unitIdx + 1][1] || [1])[0];
		                        }

		                        unitRange = H.timeUnits[unitName];
		                        this.tickInterval = unitRange * count;
		                        return this.getTimeTicks(
		                            {
		                                unitRange: unitRange,
		                                count: count,
		                                unitName: unitName
		                            },
		                            min,
		                            max,
		                            this.options.startOfWeek
		                        );
		                    }
		                };
		            }

		        }

		        // Now merge the combined options into the axis options
		        merge(true, this.options, gridAxisOptions);

		        if (this.horiz) {
		            /**              _________________________
		             * Make this:    ___|_____|_____|_____|__|
		             *               ^                     ^
		             *               _________________________
		             * Into this:    |_____|_____|_____|_____|
		             *                  ^                 ^
		             */
		            options.minPadding = pick(userOptions.minPadding, 0);
		            options.maxPadding = pick(userOptions.maxPadding, 0);
		        }

		        // If borderWidth is set, then use its value for tick and line width.
		        if (isNumber(options.grid.borderWidth)) {
		            options.tickWidth = options.lineWidth = gridOptions.borderWidth;
		        }

		    }
		});

		/**
		 * Ensures a left wall on horizontal axes with series inheriting from column.
		 * ColumnSeries normally sets pointRange to null, resulting in Axis to select
		 * other values for point ranges. This enforces the above Axis.setOptions()
		 * override.
		 *                  _________________________
		 * Enforce this:    ___|_____|_____|_____|__|
		 *                  ^
		 *                  _________________________
		 * To be this:      |_____|_____|_____|_____|
		 *                  ^
		 *
		 * @param {function} proceed - the original function
		 * @param {object} options - the pure axis options as input by the user
		 */
		wrap(Axis.prototype, 'setAxisTranslation', function (proceed) {
		    var axis = this,
		        options = axis.options,
		        gridOptions = (options && isObject(options.grid)) ? options.grid : {},
		        tickInfo = this.tickPositions && this.tickPositions.info,
		        userLabels = this.userOptions.labels || {};

		    if (this.horiz) {
		        if (gridOptions.enabled === true) {
		            each(axis.series, function (series) {
		                series.options.pointRange = 0;
		            });
		        }

		        // Lower level time ticks, like hours or minutes, represent points in
		        // time and not ranges. These should be aligned left in the grid cell
		        // by default. The same applies to years of higher order.
		        if (
		            tickInfo &&
		            (
		                options.dateTimeLabelFormats[tickInfo.unitName]
		                    .range === false ||
		                tickInfo.count > 1 // years
		            ) &&
		            !defined(userLabels.align)
		        ) {
		            options.labels.align = 'left';

		            if (!defined(userLabels.x)) {
		                options.labels.x = 3;
		            }
		        }
		    }

		    proceed.apply(axis, argsToArray(arguments));
		});

		// TODO: Does this function do what the drawing says? Seems to affect ticks and
		//       not the labels directly?
		/**
		 * Makes tick labels which are usually ignored in a linked axis displayed if
		 * they are within range of linkedParent.min.
		 *                        _____________________________
		 *                        |   |       |       |       |
		 * Make this:             |   |   2   |   3   |   4   |
		 *                        |___|_______|_______|_______|
		 *                          ^
		 *                        _____________________________
		 *                        |   |       |       |       |
		 * Into this:             | 1 |   2   |   3   |   4   |
		 *                        |___|_______|_______|_______|
		 *                          ^
		 * @param {function} proceed - the original function
		 */
		wrap(Axis.prototype, 'trimTicks', function (proceed) {
		    var axis = this,
		        options = axis.options,
		        gridOptions = (options && isObject(options.grid)) ? options.grid : {},
		        categoryAxis = axis.categories,
		        tickPositions = axis.tickPositions,
		        firstPos = tickPositions[0],
		        lastPos = tickPositions[tickPositions.length - 1],
		        linkedMin = axis.linkedParent && axis.linkedParent.min,
		        linkedMax = axis.linkedParent && axis.linkedParent.max,
		        min = linkedMin || axis.min,
		        max = linkedMax || axis.max,
		        tickInterval = axis.tickInterval,
		        moreThanMin = firstPos > min,
		        lessThanMax = lastPos < max,
		        endMoreThanMin = firstPos < min && firstPos + tickInterval > min,
		        startLessThanMax = lastPos > max && lastPos - tickInterval < max;

		    if (
		        gridOptions.enabled === true &&
		        !categoryAxis &&
		        (axis.horiz || axis.isLinked)
		    ) {
		        if ((moreThanMin || endMoreThanMin) && !options.startOnTick) {
		            tickPositions[0] = min;
		        }

		        if ((lessThanMax || startLessThanMax) && !options.endOnTick) {
		            tickPositions[tickPositions.length - 1] = max;
		        }
		    }

		    proceed.apply(axis, argsToArray(arguments));
		});

		/**
		 * Draw an extra line on the far side of the outermost axis,
		 * creating floor/roof/wall of a grid. And some padding.
		 *
		 * Make this:
		 *             (axis.min) __________________________ (axis.max)
		 *                           |    |    |    |    |
		 * Into this:
		 *             (axis.min) __________________________ (axis.max)
		 *                        ___|____|____|____|____|__
		 *
		 * @param {function} proceed - the original function
		 */
		wrap(Axis.prototype, 'render', function (proceed) {
		    var axis = this,
		        options = axis.options,
		        gridOptions = (options && isObject(options.grid)) ? options.grid : {},
		        labelPadding,
		        distance,
		        lineWidth,
		        linePath,
		        yStartIndex,
		        yEndIndex,
		        xStartIndex,
		        xEndIndex,
		        renderer = axis.chart.renderer,
		        horiz = axis.horiz,
		        axisGroupBox;

		    if (gridOptions.enabled === true) {
		        // TODO acutual label padding (top, bottom, left, right)
		        // Label padding is needed to figure out where to draw the outer line.
		        labelPadding = (Math.abs(axis.defaultLeftAxisOptions.labels.x) * 2);
		        axis.maxLabelDimensions = axis.getMaxLabelDimensions(
		            axis.ticks,
		            axis.tickPositions
		        );
		        distance = axis.maxLabelDimensions.width + labelPadding;
		        lineWidth = options.lineWidth;

		        // Remove right wall before rendering if updating
		        if (axis.rightWall) {
		            axis.rightWall.destroy();
		        }

		        // Call original Axis.render() to obtain axis.axisLine and
		        // axis.axisGroup
		        proceed.apply(axis);

		        axisGroupBox = axis.axisGroup.getBBox();

		        /*
		         * Draw an extra axis line on outer axes
		         *             >
		         * Make this:    |______|______|______|___
		         *
		         *             > _________________________
		         * Into this:    |______|______|______|__|
		         *
		         */
		        if (axis.isOuterAxis() && axis.axisLine) {
		            if (horiz) {
		                // -1 to avoid adding distance each time the chart updates
		                distance = axisGroupBox.height - 1;
		            }

		            if (lineWidth) {
		                linePath = axis.getLinePath(lineWidth);
		                xStartIndex = linePath.indexOf('M') + 1;
		                xEndIndex = linePath.indexOf('L') + 1;
		                yStartIndex = linePath.indexOf('M') + 2;
		                yEndIndex = linePath.indexOf('L') + 2;

		                // Negate distance if top or left axis
		                if (axis.side === axisSide.top || axis.side === axisSide.left) {
		                    distance = -distance;
		                }

		                // If axis is horizontal, reposition line path vertically
		                if (horiz) {
		                    linePath[yStartIndex] = linePath[yStartIndex] + distance;
		                    linePath[yEndIndex] = linePath[yEndIndex] + distance;
		                } else {
		                    // If axis is vertical, reposition line path horizontally
		                    linePath[xStartIndex] = linePath[xStartIndex] + distance;
		                    linePath[xEndIndex] = linePath[xEndIndex] + distance;
		                }

		                if (!axis.axisLineExtra) {
		                    axis.axisLineExtra = renderer.path(linePath)
		                        .attr({

		                            zIndex: 7
		                        })
		                        .addClass('highcharts-axis-line')
		                        .add(axis.axisGroup);
		                } else {
		                    axis.axisLineExtra.animate({
		                        d: linePath
		                    });
		                }

		                // show or hide the line depending on options.showEmpty
		                axis.axisLine[axis.showAxis ? 'show' : 'hide'](true);
		            }
		        }

		    } else {
		        proceed.apply(axis);
		    }
		});

		/**
		 * Wraps axis init to draw cell walls on vertical axes.
		 *
		 * @param {function} proceed - the original function
		 */
		wrap(Axis.prototype, 'init', function (proceed, chart, userOptions) {
		    var axis = this,
		        gridOptions = (
		            (userOptions && isObject(userOptions.grid)) ?
		            userOptions.grid :
		            {}
		        ),
		        columnOptions,
		        column,
		        columnIndex,
		        i;
		    function applyGridOptions(axis) {
		        var options = axis.options,
		            // TODO: Consider using cell margins defined in % of font size?
		            // 25 is optimal height for default fontSize (11px)
		            // 25 / 11 ≈ 2.28
		            fontSizeToCellHeightRatio = 25 / 11,
		            fontSize = options.labels.style.fontSize,
		            fontMetrics = axis.chart.renderer.fontMetrics(fontSize);

		        // Center-align by default
		        if (!options.labels) {
		            options.labels = {};
		        }
		        options.labels.align = pick(options.labels.align, 'center');

		        // TODO: Check against tickLabelPlacement between/on etc
		        /**
		         * Prevents adding the last tick label if the axis is not a category
		         * axis.
		         *
		         * Since numeric labels are normally placed at starts and ends of a
		         * range of value, and this module makes the label point at the value,
		         * an "extra" label would appear.
		         */
		        if (!axis.categories) {
		            options.showLastLabel = false;
		        }

		        /**
		         * Make tick marks taller, creating cell walls of a grid.
		         * Use cellHeight axis option if set
		         */
		        if (axis.horiz) {
		            options.tickLength = gridOptions.cellHeight ||
		                    fontMetrics.h * fontSizeToCellHeightRatio;
		        }

		        /**
		         * Prevents rotation of labels when squished, as rotating them would not
		         * help.
		         */
		        axis.labelRotation = 0;
		        options.labels.rotation = 0;
		    }

		    if (gridOptions.enabled) {
		        if (defined(gridOptions.borderColor)) {
		            userOptions.tickColor =
		                userOptions.lineColor = gridOptions.borderColor;
		        }

		        // Handle columns, each column is a grid axis
		        if (isArray(gridOptions.columns)) {
		            columnIndex = 0;
		            i = gridOptions.columns.length;
		            while (i--) {
		                columnOptions = merge(
		                    userOptions,
		                    gridOptions.columns[i],
		                    {
		                        // Force to behave like category axis
		                        type: 'category'
		                    }
		                );

		                delete columnOptions.grid.columns; // Prevent recursion

		                column = new Axis(chart, columnOptions);
		                column.isColumn = true;
		                column.columnIndex = columnIndex;

		                wrap(column, 'labelFormatter', function (proceed) {
		                    var axis = this.axis,
		                        tickPos = axis.tickPositions,
		                        value = this.value,
		                        series = axis.series[0],
		                        isFirst = value === tickPos[0],
		                        isLast = value === tickPos[tickPos.length - 1],
		                        point = H.find(series.options.data, function (p) {
		                            return p[axis.isXAxis ? 'x' : 'y'] === value;
		                        });

		                    // Make additional properties available for the formatter
		                    this.isFirst = isFirst;
		                    this.isLast = isLast;
		                    this.point = point;

		                    // Call original labelFormatter
		                    return proceed.call(this);
		                });

		                columnIndex++;
		            }
		        } else {
		            // Call original Axis.init()
		            proceed.apply(axis, argsToArray(arguments));
		            applyGridOptions(axis);
		        }
		    } else {
		        // Call original Axis.init()
		        proceed.apply(axis, argsToArray(arguments));
		    }
		});

	}(Highcharts));
	var Tree = (function (H) {
		/**
		* (c) 2016 Highsoft AS
		* Authors: Jon Arild Nygard
		*
		* License: www.highcharts.com/license
		*/
		/* eslint no-console: 0 */
		var each = H.each,
		    extend = H.extend,
		    isNumber = H.isNumber,
		    keys = H.keys,
		    map = H.map,
		    pick = H.pick,
		    reduce = H.reduce,
		    isFunction = function (x) {
		        return typeof x === 'function';
		    };

		/**
		 * Creates an object map from parent id to childrens index.
		 * @param   {Array}  data          List of points set in options.
		 * @param   {string} data[].parent Parent id of point.
		 * @param   {Array}  ids           List of all point ids.
		 * @returns {Object}               Map from parent id to children index in data
		 */
		var getListOfParents = function (data, ids) {
		    var listOfParents = reduce(data, function (prev, curr) {
		            var parent = pick(curr.parent, '');
		            if (prev[parent] === undefined) {
		                prev[parent] = [];
		            }
		            prev[parent].push(curr);
		            return prev;
		        }, {}),
		        parents = keys(listOfParents);

		    // If parent does not exist, hoist parent to root of tree.
		    each(parents, function (parent, list) {
		        var children = listOfParents[parent];
		        if ((parent !== '') && (H.inArray(parent, ids) === -1)) {
		            each(children, function (child) {
		                list[''].push(child);
		            });
		            delete list[parent];
		        }
		    });
		    return listOfParents;
		};
		var getNode = function (id, parent, level, data, mapOfIdToChildren, options) {
		    var descendants = 0,
		        height = 0,
		        after = options && options.after,
		        before = options && options.before,
		        node = {
		            data: data,
		            depth: level - 1,
		            id: id,
		            level: level,
		            parent: parent
		        },
		        start,
		        end,
		        children;

		    // Allow custom logic before the children has been created.
		    if (isFunction(before)) {
		        before(node, options);
		    }

		    /**
		     * Call getNode recursively on the children. Calulate the height of the
		     * node, and the number of descendants.
		     */
		    children = map((mapOfIdToChildren[id] || []), function (child) {
		        var node = getNode(
		                child.id,
		                id,
		                (level + 1),
		                child,
		                mapOfIdToChildren,
		                options
		            ),
		            childStart = child.start,
		            childEnd = (
		                child.milestone === true ?
		                childStart :
		                child.end
		            );

		        // Start should be the lowest child.start.
		        start = (
		            (!isNumber(start) || childStart < start) ?
		            childStart :
		            start
		        );

		        // End should be the largest child.end.
		        // If child is milestone, then use start as end.
		        end = (
		            (!isNumber(end) || childEnd > end) ?
		            childEnd :
		            end
		        );

		        descendants = descendants + 1 + node.descendants;
		        height = Math.max(node.height + 1, height);
		        return node;
		    });

		    // Calculate start and end for point if it is not already explicitly set.
		    if (data) {
		        data.start = pick(data.start, start);
		        data.end = pick(data.end, end);
		    }

		    extend(node, {
		        children: children,
		        descendants: descendants,
		        height: height
		    });

		    // Allow custom logic after the children has been created.
		    if (isFunction(after)) {
		        after(node, options);
		    }

		    return node;
		};
		var getTree = function (data, options) {
		    var ids = map(data, function (d) {
		            return d.id;
		        }),
		        mapOfIdToChildren = getListOfParents(data, ids);
		    return getNode('', null, 1, null, mapOfIdToChildren, options);
		};

		var Tree = {
		    getListOfParents: getListOfParents,
		    getNode: getNode,
		    getTree: getTree
		};

		return Tree;
	}(Highcharts));
	var result = (function (H) {
		var each = H.each,
		    extend = H.extend,
		    isArray = H.isArray,
		    isBoolean = function (x) {
		        return typeof x === 'boolean';
		    },
		    isFn = function (x) {
		        return typeof x === 'function';
		    },
		    isObject = H.isObject,
		    isNumber = H.isNumber,
		    merge = H.merge,
		    pick = H.pick,
		    reduce = H.reduce;
		// TODO Combine buildTree and buildNode with setTreeValues
		// TODO Remove logic from Treemap and make it utilize this mixin.
		var setTreeValues = function setTreeValues(tree, options) {
		    var before = options.before,
		        idRoot = options.idRoot,
		        mapIdToNode = options.mapIdToNode,
		        nodeRoot = mapIdToNode[idRoot],
		        levelIsConstant = (
		            isBoolean(options.levelIsConstant) ?
		            options.levelIsConstant :
		            true
		        ),
		        points = options.points,
		        point = points[tree.i],
		        optionsPoint = point && point.options || {},
		        childrenTotal = 0,
		        children = [],
		        value;
		    extend(tree, {
		        levelDynamic: tree.level - (levelIsConstant ? 0 : nodeRoot.level),
		        name: pick(point && point.name, ''),
		        visible: (
		            idRoot === tree.id ||
		            (isBoolean(options.visible) ? options.visible : false)
		        )
		    });
		    if (isFn(before)) {
		        tree = before(tree, options);
		    }
		    // First give the children some values
		    each(tree.children, function (child, i) {
		        var newOptions = extend({}, options);
		        extend(newOptions, {
		            index: i,
		            siblings: tree.children.length,
		            visible: tree.visible
		        });
		        child = setTreeValues(child, newOptions);
		        children.push(child);
		        if (child.visible) {
		            childrenTotal += child.val;
		        }
		    });
		    tree.visible = childrenTotal > 0 || tree.visible;
		    // Set the values
		    value = pick(optionsPoint.value, childrenTotal);
		    extend(tree, {
		        children: children,
		        childrenTotal: childrenTotal,
		        isLeaf: tree.visible && !childrenTotal,
		        val: value
		    });
		    return tree;
		};

		var getColor = function getColor(node, options) {
		    var index = options.index,
		        mapOptionsToLevel = options.mapOptionsToLevel,
		        parentColor = options.parentColor,
		        parentColorIndex = options.parentColorIndex,
		        series = options.series,
		        colors = options.colors,
		        siblings = options.siblings,
		        points = series.points,
		        getColorByPoint,
		        point,
		        level,
		        colorByPoint,
		        colorIndexByPoint,
		        color,
		        colorIndex;
		    function variation(color) {
		        var colorVariation = level && level.colorVariation;
		        if (colorVariation) {
		            if (colorVariation.key === 'brightness') {
		                return H.color(color).brighten(
		                    colorVariation.to * (index / siblings)
		                ).get();
		            }
		        }

		        return color;
		    }

		    if (node) {
		        point = points[node.i];
		        level = mapOptionsToLevel[node.level] || {};
		        getColorByPoint = point && level.colorByPoint;

		        if (getColorByPoint) {
		            colorIndexByPoint = point.index % (colors ?
		                colors.length :
		                series.chart.options.chart.colorCount
		            );
		            colorByPoint = colors && colors[colorIndexByPoint];
		        }

		        colorIndex = pick(
		            point && point.options.colorIndex,
		            level && level.colorIndex,
		            colorIndexByPoint,
		            parentColorIndex,
		            options.colorIndex
		        );
		    }
		    return {
		        color: color,
		        colorIndex: colorIndex
		    };
		};

		/**
		 * getLevelOptions - Creates a map from level number to its given options.
		 * @param {Object} params Object containing parameters.
		 * @param {Object} params.defaults Object containing default options. The
		 * default options are merged with the userOptions to get the final options for
		 * a specific level.
		 * @param {Number} params.from The lowest level number.
		 * @param {Array} params.levels User options from series.levels.
		 * @param {Number} params.to The highest level number.
		 * @return {null|Object} Returns a map from level number to its given options.
		 * Returns null if invalid input parameters.
		 */
		var getLevelOptions = function getLevelOptions(params) {
		    var result = null,
		        defaults,
		        converted,
		        i,
		        from,
		        to,
		        levels;
		    if (isObject(params)) {
		        result = {};
		        from = isNumber(params.from) ? params.from : 1;
		        levels = params.levels;
		        converted = {};
		        defaults = isObject(params.defaults) ? params.defaults : {};
		        if (isArray(levels)) {
		            converted = reduce(levels, function (obj, item) {
		                var level,
		                    levelIsConstant,
		                    options;
		                if (isObject(item) && isNumber(item.level)) {
		                    options = merge({}, item);
		                    levelIsConstant = (
		                        isBoolean(options.levelIsConstant) ?
		                        options.levelIsConstant :
		                        defaults.levelIsConstant
		                    );
		                    // Delete redundant properties.
		                    delete options.levelIsConstant;
		                    delete options.level;
		                    // Calculate which level these options apply to.
		                    level = item.level + (levelIsConstant ? 0 : from - 1);
		                    if (isObject(obj[level])) {
		                        extend(obj[level], options);
		                    } else {
		                        obj[level] = options;
		                    }
		                }
		                return obj;
		            }, {});
		        }
		        to = isNumber(params.to) ? params.to : 1;
		        for (i = 0; i <= to; i++) {
		            result[i] = merge(
		                {},
		                defaults,
		                isObject(converted[i]) ? converted[i] : {}
		            );
		        }
		    }
		    return result;
		};

		/**
		 * Update the rootId property on the series. Also makes sure that it is
		 * accessible to exporting.
		 * @param {object} series The series to operate on.
		 * @returns Returns the resulting rootId after update.
		 */
		var updateRootId = function (series) {
		    var rootId,
		        options;
		    if (isObject(series)) {
		        // Get the series options.
		        options = isObject(series.options) ? series.options : {};

		        // Calculate the rootId.
		        rootId = pick(series.rootNode, options.rootId, '');

		        // Set rootId on series.userOptions to pick it up in exporting.
		        if (isObject(series.userOptions)) {
		            series.userOptions.rootId = rootId;
		        }
		        // Set rootId on series to pick it up on next update.
		        series.rootNode = rootId;
		    }
		    return rootId;
		};

		var result = {
		    getColor: getColor,
		    getLevelOptions: getLevelOptions,
		    setTreeValues: setTreeValues,
		    updateRootId: updateRootId
		};

		return result;
	}(Highcharts));
	(function (H) {
		/**
		 * (c) 2009-2018 Torstein Honsi
		 *
		 * License: www.highcharts.com/license
		 */

		var addEvent = H.addEvent,
		    pick = H.pick,
		    wrap = H.wrap,
		    each = H.each,
		    extend = H.extend,
		    isArray = H.isArray,
		    fireEvent = H.fireEvent,
		    Axis = H.Axis,
		    Series = H.Series;

		function stripArguments() {
		    return Array.prototype.slice.call(arguments, 1);
		}

		extend(Axis.prototype, {
		    isInBreak: function (brk, val) {
		        var ret,
		            repeat = brk.repeat || Infinity,
		            from = brk.from,
		            length = brk.to - brk.from,
		            test = (
		                val >= from ?
		                    (val - from) % repeat :
		                    repeat - ((from - val) % repeat)
		            );

		        if (!brk.inclusive) {
		            ret = test < length && test !== 0;
		        } else {
		            ret = test <= length;
		        }
		        return ret;
		    },

		    isInAnyBreak: function (val, testKeep) {

		        var breaks = this.options.breaks,
		            i = breaks && breaks.length,
		            inbrk,
		            keep,
		            ret;

		        if (i) {

		            while (i--) {
		                if (this.isInBreak(breaks[i], val)) {
		                    inbrk = true;
		                    if (!keep) {
		                        keep = pick(
		                            breaks[i].showPoints,
		                            this.isXAxis ? false : true
		                        );
		                    }
		                }
		            }

		            if (inbrk && testKeep) {
		                ret = inbrk && !keep;
		            } else {
		                ret = inbrk;
		            }
		        }
		        return ret;
		    }
		});

		addEvent(Axis, 'afterInit', function () {
		    if (typeof this.setBreaks === 'function') {
		        this.setBreaks(this.options.breaks, false);
		    }
		});

		addEvent(Axis, 'afterSetTickPositions', function () {
		    if (this.isBroken) {
		        var axis = this,
		            tickPositions = this.tickPositions,
		            info = this.tickPositions.info,
		            newPositions = [],
		            i;

		        for (i = 0; i < tickPositions.length; i++) {
		            if (!axis.isInAnyBreak(tickPositions[i])) {
		                newPositions.push(tickPositions[i]);
		            }
		        }

		        this.tickPositions = newPositions;
		        this.tickPositions.info = info;
		    }
		});

		// Force Axis to be not-ordinal when breaks are defined
		addEvent(Axis, 'afterSetOptions', function () {
		    if (this.isBroken) {
		        this.options.ordinal = false;
		    }
		});

		/**
		 * Dynamically set or unset breaks in an axis. This function in lighter than
		 * usin Axis.update, and it also preserves animation.
		 * @param  {Array} [breaks]
		 *         The breaks to add. When `undefined` it removes existing breaks.
		 * @param  {Boolean} [redraw=true]
		 *         Whether to redraw the chart immediately.
		 */
		Axis.prototype.setBreaks = function (breaks, redraw) {
		    var axis = this,
		        isBroken = (isArray(breaks) && !!breaks.length);

		    function breakVal2Lin(val) {
		        var nval = val,
		            brk,
		            i;

		        for (i = 0; i < axis.breakArray.length; i++) {
		            brk = axis.breakArray[i];
		            if (brk.to <= val) {
		                nval -= brk.len;
		            } else if (brk.from >= val) {
		                break;
		            } else if (axis.isInBreak(brk, val)) {
		                nval -= (val - brk.from);
		                break;
		            }
		        }

		        return nval;
		    }

		    function breakLin2Val(val) {
		        var nval = val,
		            brk,
		            i;

		        for (i = 0; i < axis.breakArray.length; i++) {
		            brk = axis.breakArray[i];
		            if (brk.from >= nval) {
		                break;
		            } else if (brk.to < nval) {
		                nval += brk.len;
		            } else if (axis.isInBreak(brk, nval)) {
		                nval += brk.len;
		            }
		        }
		        return nval;
		    }

		    axis.isDirty = axis.isBroken !== isBroken;
		    axis.isBroken = isBroken;
		    axis.options.breaks = axis.userOptions.breaks = breaks;
		    axis.forceRedraw = true; // Force recalculation in setScale

		    if (!isBroken && axis.val2lin === breakVal2Lin) {
		        // Revert to prototype functions
		        delete axis.val2lin;
		        delete axis.lin2val;
		    }

		    if (isBroken) {
		        axis.userOptions.ordinal = false;
		        axis.val2lin = breakVal2Lin;
		        axis.lin2val = breakLin2Val;

		        axis.setExtremes = function (
		            newMin,
		            newMax,
		            redraw,
		            animation,
		            eventArguments
		        ) {
		            // If trying to set extremes inside a break, extend it to before and
		            // after the break ( #3857 )
		            if (this.isBroken) {
		                while (this.isInAnyBreak(newMin)) {
		                    newMin -= this.closestPointRange;
		                }
		                while (this.isInAnyBreak(newMax)) {
		                    newMax -= this.closestPointRange;
		                }
		            }
		            Axis.prototype.setExtremes.call(
		                this,
		                newMin,
		                newMax,
		                redraw,
		                animation,
		                eventArguments
		            );
		        };

		        axis.setAxisTranslation = function (saveOld) {
		            Axis.prototype.setAxisTranslation.call(this, saveOld);

		            this.unitLength = null;
		            if (this.isBroken) {
		                var breaks = axis.options.breaks,
		                    breakArrayT = [],    // Temporary one
		                    breakArray = [],
		                    length = 0,
		                    inBrk,
		                    repeat,
		                    min = axis.userMin || axis.min,
		                    max = axis.userMax || axis.max,
		                    pointRangePadding = pick(axis.pointRangePadding, 0),
		                    start,
		                    i;

		                // Min & max check (#4247)
		                each(breaks, function (brk) {
		                    repeat = brk.repeat || Infinity;
		                    if (axis.isInBreak(brk, min)) {
		                        min += (brk.to % repeat) - (min % repeat);
		                    }
		                    if (axis.isInBreak(brk, max)) {
		                        max -= (max % repeat) - (brk.from % repeat);
		                    }
		                });

		                // Construct an array holding all breaks in the axis
		                each(breaks, function (brk) {
		                    start = brk.from;
		                    repeat = brk.repeat || Infinity;

		                    while (start - repeat > min) {
		                        start -= repeat;
		                    }
		                    while (start < min) {
		                        start += repeat;
		                    }

		                    for (i = start; i < max; i += repeat) {
		                        breakArrayT.push({
		                            value: i,
		                            move: 'in'
		                        });
		                        breakArrayT.push({
		                            value: i + (brk.to - brk.from),
		                            move: 'out',
		                            size: brk.breakSize
		                        });
		                    }
		                });

		                breakArrayT.sort(function (a, b) {
		                    return (
		                        (a.value === b.value) ?
		                        (a.move === 'in' ? 0 : 1) - (b.move === 'in' ? 0 : 1) :
		                        a.value - b.value
		                    );
		                });

		                // Simplify the breaks
		                inBrk = 0;
		                start = min;

		                each(breakArrayT, function (brk) {
		                    inBrk += (brk.move === 'in' ? 1 : -1);

		                    if (inBrk === 1 && brk.move === 'in') {
		                        start = brk.value;
		                    }
		                    if (inBrk === 0) {
		                        breakArray.push({
		                            from: start,
		                            to: brk.value,
		                            len: brk.value - start - (brk.size || 0)
		                        });
		                        length += brk.value - start - (brk.size || 0);
		                    }
		                });

		                axis.breakArray = breakArray;

		                // Used with staticScale, and below, the actual axis length when
		                // breaks are substracted.
		                axis.unitLength = max - min - length + pointRangePadding;

		                fireEvent(axis, 'afterBreaks');

		                if (axis.staticScale) {
		                    axis.transA = axis.staticScale;
		                } else if (axis.unitLength) {
		                    axis.transA *= (max - axis.min + pointRangePadding) /
		                        axis.unitLength;
		                }

		                if (pointRangePadding) {
		                    axis.minPixelPadding = axis.transA * axis.minPointOffset;
		                }

		                axis.min = min;
		                axis.max = max;
		            }
		        };
		    }

		    if (pick(redraw, true)) {
		        this.chart.redraw();
		    }
		};

		wrap(Series.prototype, 'generatePoints', function (proceed) {

		    proceed.apply(this, stripArguments(arguments));

		    var series = this,
		        xAxis = series.xAxis,
		        yAxis = series.yAxis,
		        points = series.points,
		        point,
		        i = points.length,
		        connectNulls = series.options.connectNulls,
		        nullGap;

		    if (xAxis && yAxis && (xAxis.options.breaks || yAxis.options.breaks)) {
		        while (i--) {
		            point = points[i];

		            // Respect nulls inside the break (#4275)
		            nullGap = point.y === null && connectNulls === false;
		            if (
		                !nullGap &&
		                (
		                    xAxis.isInAnyBreak(point.x, true) ||
		                    yAxis.isInAnyBreak(point.y, true)
		                )
		            ) {
		                points.splice(i, 1);
		                if (this.data[i]) {
		                    // Removes the graphics for this point if they exist
		                    this.data[i].destroyElements();
		                }
		            }
		        }
		    }

		});

		function drawPointsWrapped(proceed) {
		    proceed.apply(this);
		    this.drawBreaks(this.xAxis, ['x']);
		    this.drawBreaks(this.yAxis, pick(this.pointArrayMap, ['y']));
		}

		H.Series.prototype.drawBreaks = function (axis, keys) {
		    var series = this,
		        points = series.points,
		        breaks,
		        threshold,
		        eventName,
		        y;

		    if (!axis) {
		        return; // #5950
		    }

		    each(keys, function (key) {
		        breaks = axis.breakArray || [];
		        threshold = axis.isXAxis ?
		            axis.min :
		            pick(series.options.threshold, axis.min);
		        each(points, function (point) {
		            y = pick(point['stack' + key.toUpperCase()], point[key]);
		            each(breaks, function (brk) {
		                eventName = false;

		                if (
		                    (threshold < brk.from && y > brk.to) ||
		                    (threshold > brk.from && y < brk.from)
		                ) {
		                    eventName = 'pointBreak';

		                } else if (
		                    (threshold < brk.from && y > brk.from && y < brk.to) ||
		                    (threshold > brk.from && y > brk.to && y < brk.from)
		                ) {
		                    eventName = 'pointInBreak';
		                }
		                if (eventName) {
		                    fireEvent(axis, eventName, { point: point, brk: brk });
		                }
		            });
		        });
		    });
		};

		/**
		 * Extend getGraphPath by identifying gaps in the data so that we can draw a gap
		 * in the line or area. This was moved from ordinal axis module to broken axis
		 * module as of #5045.
		 */
		H.Series.prototype.gappedPath = function () {
		    var currentDataGrouping = this.currentDataGrouping,
		        groupingSize = currentDataGrouping && currentDataGrouping.totalRange,
		        gapSize = this.options.gapSize,
		        points = this.points.slice(),
		        i = points.length - 1,
		        yAxis = this.yAxis,
		        xRange,
		        stack;

		    /**
		     * Defines when to display a gap in the graph, together with the
		     * [gapUnit](plotOptions.series.gapUnit) option.
		     *
		     * In case when `dataGrouping` is enabled, points can be grouped into a
		     * larger time span. This can make the grouped points to have a greater
		     * distance than the absolute value of `gapSize` property, which will result
		     * in disappearing graph completely. To prevent this situation the mentioned
		     * distance between grouped points is used instead of previously defined
		     * `gapSize`.
		     *
		     * In practice, this option is most often used to visualize gaps in
		     * time series. In a stock chart, intraday data is available for daytime
		     * hours, while gaps will appear in nights and weekends.
		     *
		     * @type    {Number}
		     * @see     [gapUnit](plotOptions.series.gapUnit) and
		     *          [xAxis.breaks](#xAxis.breaks)
		     * @sample  {highstock} stock/plotoptions/series-gapsize/
		     *          Setting the gap size to 2 introduces gaps for weekends in daily
		     *          datasets.
		     * @default 0
		     * @product highstock
		     * @apioption plotOptions.series.gapSize
		     */

		    /**
		     * Together with [gapSize](plotOptions.series.gapSize), this option defines
		     * where to draw gaps in the graph.
		     *
		     * When the `gapUnit` is `relative` (default), a gap size of 5 means
		     * that if the distance between two points is greater than five times
		     * that of the two closest points, the graph will be broken.
		     *
		     * When the `gapUnit` is `value`, the gap is based on absolute axis values,
		     * which on a datetime axis is milliseconds. This also applies to the
		     * navigator series that inherits gap options from the base series.
		     *
		     * @type {String}
		     * @see [gapSize](plotOptions.series.gapSize)
		     * @default relative
		     * @validvalue ["relative", "value"]
		     * @since 5.0.13
		     * @product highstock
		     * @apioption plotOptions.series.gapUnit
		     */

		    if (gapSize && i > 0) { // #5008

		        // Gap unit is relative
		        if (this.options.gapUnit !== 'value') {
		            gapSize *= this.closestPointRange;
		        }

		        // Setting a new gapSize in case dataGrouping is enabled (#7686)
		        if (groupingSize && groupingSize > gapSize) {
		            gapSize = groupingSize;
		        }

		        // extension for ordinal breaks
		        while (i--) {
		            if (points[i + 1].x - points[i].x > gapSize) {
		                xRange = (points[i].x + points[i + 1].x) / 2;

		                points.splice( // insert after this one
		                    i + 1,
		                    0,
		                    {
		                        isNull: true,
		                        x: xRange
		                    }
		                );

		                // For stacked chart generate empty stack items, #6546
		                if (this.options.stacking) {
		                    stack = yAxis.stacks[this.stackKey][xRange] =
		                        new H.StackItem(
		                            yAxis,
		                            yAxis.options.stackLabels,
		                            false,
		                            xRange,
		                            this.stack
		                        );
		                    stack.total = 0;
		                }
		            }
		        }
		    }

		    // Call base method
		    return this.getGraphPath(points);
		};

		wrap(H.seriesTypes.column.prototype, 'drawPoints', drawPointsWrapped);
		wrap(H.Series.prototype, 'drawPoints', drawPointsWrapped);

	}(Highcharts));
	(function (H, Tree, mixinTreeSeries) {
		/**
		* (c) 2016 Highsoft AS
		* Authors: Jon Arild Nygard
		*
		* License: www.highcharts.com/license
		*/
		/* eslint no-console: 0 */
		var argsToArray = function (args) {
		        return Array.prototype.slice.call(args, 1);
		    },
		    defined = H.defined,
		    each = H.each,
		    extend = H.extend,
		    find = H.find,
		    fireEvent = H.fireEvent,
		    getLevelOptions = mixinTreeSeries.getLevelOptions,
		    map = H.map,
		    merge = H.merge,
		    inArray = H.inArray,
		    isBoolean = function (x) {
		        return typeof x === 'boolean';
		    },
		    isNumber = H.isNumber,
		    isObject = function (x) {
		        // Always use strict mode.
		        return H.isObject(x, true);
		    },
		    isString = H.isString,
		    keys = H.keys,
		    pick = H.pick,
		    reduce = H.reduce,
		    wrap = H.wrap,
		    GridAxis = H.Axis,
		    GridAxisTick = H.Tick;

		/**
		 * some - Equivalent of Array.prototype.some
		 *
		 * @param  {Array}    arr       Array to look for matching elements in.
		 * @param  {function} condition The condition to check against.
		 * @return {boolean}            Whether some elements pass the condition.
		 */
		var some = function (arr, condition) {
		    var result = false;
		    each(arr, function (element, index, array) {
		        if (!result) {
		            result = condition(element, index, array);
		        }
		    });
		    return result;
		};

		var override = function (obj, methods) {
		    var method,
		        func;
		    for (method in methods) {
		        if (methods.hasOwnProperty(method)) {
		            func = methods[method];
		            wrap(obj, method, func);
		        }
		    }
		};

		/**
		 * getCategoriesFromTree - getCategories based on a tree
		 *
		 * @param  {object} tree Root of tree to collect categories from
		 * @return {Array}       Array of categories
		 */
		var getCategoriesFromTree = function (tree) {
		    var categories = [];
		    if (tree.data) {
		        categories.push(tree.data.name);
		    }
		    each(tree.children, function (child) {
		        categories = categories.concat(getCategoriesFromTree(child));
		    });
		    return categories;
		};

		var mapTickPosToNode = function (node, categories) {
		    var map = {},
		        name = node.data && node.data.name,
		        pos = inArray(name, categories);
		    map[pos] = node;
		    each(node.children, function (child) {
		        extend(map, mapTickPosToNode(child, categories));
		    });
		    return map;
		};

		var getBreakFromNode = function (node, max) {
		    var from = node.collapseStart,
		        to = node.collapseEnd;

		    // In broken-axis, the axis.max is minimized until it is not within a break.
		    // Therefore, if break.to is larger than axis.max, the axis.to should not
		    // add the 0.5 axis.tickMarkOffset, to avoid adding a break larger than
		    // axis.max
		    // TODO consider simplifying broken-axis and this might solve itself
		    if (to >= max) {
		        from -= 0.5;
		    }

		    return {
		        from: from,
		        to: to,
		        showPoints: false
		    };
		};

		/**
		 * Creates a list of positions for the ticks on the axis. Filters out positions
		 * that are outside min and max, or is inside an axis break.
		 *
		 * @param {Object} axis The Axis to get the tick positions from.
		 * @param {number} axis.min The minimum value of the axis.
		 * @param {number} axis.max The maximum value of the axis.
		 * @param {function} axis.isInAnyBreak Function to determine if a position is
		 * inside any breaks on the axis.
		 * @returns {number[]} List of positions.
		 */
		var getTickPositions = function (axis) {
		    return reduce(
		        keys(axis.mapOfPosToGridNode),
		        function (arr, key) {
		            var pos = +key;
		            if (
		                axis.min <= pos &&
		                axis.max >= pos &&
		                !axis.isInAnyBreak(pos)
		            ) {
		                arr.push(pos);
		            }
		            return arr;
		        },
		        []
		    );
		};
		/**
		 * Check if a node is collapsed.
		 * @param {object} axis The axis to check against.
		 * @param {object} node The node to check if is collapsed.
		 * @param {number} pos The tick position to collapse.
		 * @returns {boolean} Returns true if collapsed, false if expanded.
		 */
		var isCollapsed = function (axis, node) {
		    var breaks = (axis.options.breaks || []),
		        obj = getBreakFromNode(node, axis.max);
		    return some(breaks, function (b) {
		        return b.from === obj.from && b.to === obj.to;
		    });
		};

		/**
		 * Calculates the new axis breaks to collapse a node.
		 * @param {object} axis The axis to check against.
		 * @param {object} node The node to collapse.
		 * @param {number} pos The tick position to collapse.
		 * @returns {array} Returns an array of the new breaks for the axis.
		 */
		var collapse = function (axis, node) {
		    var breaks = (axis.options.breaks || []),
		        obj = getBreakFromNode(node, axis.max);
		    breaks.push(obj);
		    return breaks;
		};

		/**
		 * Calculates the new axis breaks to expand a node.
		 * @param {object} axis The axis to check against.
		 * @param {object} node The node to expand.
		 * @param {number} pos The tick position to expand.
		 * @returns {array} Returns an array of the new breaks for the axis.
		 */
		var expand = function (axis, node) {
		    var breaks = (axis.options.breaks || []),
		        obj = getBreakFromNode(node, axis.max);
		    // Remove the break from the axis breaks array.
		    return reduce(breaks, function (arr, b) {
		        if (b.to !== obj.to || b.from !== obj.from) {
		            arr.push(b);
		        }
		        return arr;
		    }, []);
		};

		/**
		 * Calculates the new axis breaks after toggling the collapse/expand state of a
		 * node. If it is collapsed it will be expanded, and if it is exapended it will
		 * be collapsed.
		 * @param {object} axis The axis to check against.
		 * @param {object} node The node to toggle.
		 * @param {number} pos The tick position to toggle.
		 * @returns {array} Returns an array of the new breaks for the axis.
		 */
		var toggleCollapse = function (axis, node) {
		    return (
		        isCollapsed(axis, node) ?
		        expand(axis, node) :
		        collapse(axis, node)
		    );
		};
		var renderLabelIcon = function (tick, params) {
		    var icon = tick.labelIcon,
		        isNew = !icon,
		        renderer = params.renderer,
		        labelBox = params.xy,
		        options = params.options,
		        width = options.width,
		        height = options.height,
		        iconCenter = {
		            x: labelBox.x - (width / 2) - options.padding,
		            y: labelBox.y - (height / 2)
		        },
		        rotation = params.collapsed ? 90 : 180,
		        shouldRender = params.show && H.isNumber(iconCenter.y);

		    if (isNew) {
		        tick.labelIcon = icon = renderer.path(renderer.symbols[options.type](
		            options.x,
		            options.y,
		            width,
		            height
		        ))
		        .addClass('highcharts-label-icon')
		        .add(params.group);
		    }

		    // Set the new position, and show or hide
		    if (!shouldRender) {
		        icon.attr({ y: -9999 }); // #1338
		    }

		    // Update the icon positions
		    icon[isNew ? 'attr' : 'animate']({
		        translateX: iconCenter.x,
		        translateY: iconCenter.y,
		        rotation: rotation
		    });

		};
		var onTickHover = function (label) {
		    label.addClass('highcharts-treegrid-node-active');

		};
		var onTickHoverExit = function (label, options) {
		    var css = defined(options.style) ? options.style : {};
		    label.removeClass('highcharts-treegrid-node-active');

		};

		/**
		 * Creates a tree structure of the data, and the treegrid. Calculates
		 * categories, and y-values of points based on the tree.
		 * @param {Array} data All the data points to display in the axis.
		 * @param {boolean} uniqueNames Wether or not the data node with the same name
		 * should share grid cell. If true they do share cell. False by default.
		 * @returns {object} Returns an object containing categories, mapOfIdToNode,
		 * mapOfPosToGridNode, and tree.
		 * @todo There should be only one point per line.
		 * @todo It should be optional to have one category per point, or merge cells
		 * @todo Add unit-tests.
		 */
		var getTreeGridFromData = function (data, uniqueNames, numberOfSeries) {
		    var categories = [],
		        collapsedNodes = [],
		        mapOfIdToNode = {},
		        mapOfPosToGridNode = {},
		        posIterator = -1,
		        uniqueNamesEnabled = isBoolean(uniqueNames) ? uniqueNames : false,
		        tree,
		        treeParams,
		        updateYValuesAndTickPos;

		    // Build the tree from the series data.
		    treeParams = {
		        // After the children has been created.
		        after: function (node) {
		            var gridNode = mapOfPosToGridNode[node.pos],
		                height = 0,
		                descendants = 0;
		            each(gridNode.children, function (child) {
		                descendants += child.descendants + 1;
		                height = Math.max(child.height + 1, height);
		            });
		            gridNode.descendants = descendants;
		            gridNode.height = height;
		            if (gridNode.collapsed) {
		                collapsedNodes.push(gridNode);
		            }
		        },
		        // Before the children has been created.
		        before: function (node) {
		            var data = isObject(node.data) ? node.data : {},
		                name = isString(data.name) ? data.name : '',
		                parentNode = mapOfIdToNode[node.parent],
		                parentGridNode = (
		                    isObject(parentNode) ?
		                    mapOfPosToGridNode[parentNode.pos] :
		                    null
		                ),
		                hasSameName = function (x) {
		                    return x.name === name;
		                },
		                gridNode,
		                pos;

		            // If not unique names, look for a sibling node with the same name.
		            if (
		                uniqueNamesEnabled &&
		                isObject(parentGridNode) &&
		                !!(gridNode = find(parentGridNode.children, hasSameName))
		            ) {
		                // If if there is a gridNode with the same name, reuse position.
		                pos = gridNode.pos;
		                // Add data node to list of nodes in the grid node.
		                gridNode.nodes.push(node);
		            } else {
		                // If it is a new grid node, increment position.
		                pos = posIterator++;
		            }

		            // Add new grid node to map.
		            if (!mapOfPosToGridNode[pos]) {
		                mapOfPosToGridNode[pos] = gridNode = {
		                    depth: parentGridNode ? parentGridNode.depth + 1 : 0,
		                    name: name,
		                    nodes: [node],
		                    children: [],
		                    pos: pos
		                };

		                // If not root, then add name to categories.
		                if (pos !== -1) {
		                    categories.push(name);
		                }

		                // Add name to list of children.
		                if (isObject(parentGridNode)) {
		                    parentGridNode.children.push(gridNode);
		                }
		            }

		            // Add data node to map
		            if (isString(node.id)) {
		                mapOfIdToNode[node.id] = node;
		            }

		            // If one of the points are collapsed, then start the grid node in
		            // collapsed state.
		            if (data.collapsed === true) {
		                gridNode.collapsed = true;
		            }

		            // Assign pos to data node
		            node.pos = pos;
		        }
		    };

		    updateYValuesAndTickPos = function (map, numberOfSeries) {
		        var setValues = function (gridNode, start, result) {
		            var nodes = gridNode.nodes,
		                end = start + (start === -1 ? 0 : numberOfSeries - 1),
		                diff = (end - start) / 2,
		                padding = 0.5,
		                pos = start + diff;

		            each(nodes, function (node) {
		                var data = node.data;
		                if (isObject(data)) {
		                    // Update point
		                    data.y = start + data.seriesIndex;
		                    // Remove the property once used
		                    delete data.seriesIndex;
		                }
		                node.pos = pos;
		            });

		            result[pos] = gridNode;

		            gridNode.pos = pos;
		            gridNode.tickmarkOffset = diff + padding;
		            gridNode.collapseStart = end + padding;

		            each(gridNode.children, function (child) {
		                setValues(child, end + 1, result);
		                end = child.collapseEnd - padding;
		            });
		            // Set collapseEnd to the end of the last child node.
		            gridNode.collapseEnd = end + padding;

		            return result;
		        };

		        return setValues(map['-1'], -1, {});
		    };

		    // Create tree from data
		    tree = Tree.getTree(data, treeParams);

		    // Update y values of data, and set calculate tick positions.
		    mapOfPosToGridNode = updateYValuesAndTickPos(
		        mapOfPosToGridNode,
		        numberOfSeries
		    );

		    // Return the resulting data.
		    return {
		        categories: categories,
		        mapOfIdToNode: mapOfIdToNode,
		        mapOfPosToGridNode: mapOfPosToGridNode,
		        collapsedNodes: collapsedNodes,
		        tree: tree
		    };
		};

		override(GridAxis.prototype, {
		    init: function (proceed, chart, userOptions) {
		        var axis = this,
		            removeFoundExtremesEvent,
		            isTreeGrid = userOptions.type === 'treegrid';
		        // Set default and forced options for TreeGrid
		        if (isTreeGrid) {
		            userOptions = merge({
		                // Default options
		                grid: {
		                    enabled: true
		                },
		                // TODO: add support for align in treegrid.
		                labels: {
		                    align: 'left',

		                    /**
		                    * Set options on specific levels in a tree grid axis. Takes
		                    * precedence over labels options.
		                    *
		                    * @product gantt
		                    * @sample {gantt} gantt/treegrid-axis/labels-levels
		                    *           Levels on TreeGrid Labels
		                    * @type {Array<Object>}
		                    * @apioption yAxis.labels.levels
		                    */
		                    levels: [{
		                        /**
		                        * Specify the level which the options within this object
		                        * applies to.
		                        *
		                        * @sample {gantt} gantt/treegrid-axis/labels-levels
		                        */
		                        level: undefined
		                    }, {
		                        level: 1,
		                        style: {
		                            fontWeight: 'bold'
		                        }
		                    }],

		                    /**
		                     * The symbol for the collapse and expand icon in a
		                     * treegrid.
		                     *
		                     * @product gantt
		                     * @optionparent yAxis.labels.symbol
		                     */
		                    symbol: {
		                        /**
		                         * The symbol type. Points to a definition function in
		                         * the `Highcharts.Renderer.symbols` collection.
		                         *
		                         * @validvalue ['arc', 'circle', 'diamond', 'square', 'triangle', 'triangle-down']
		                         */
		                        type: 'triangle',
		                        x: -5,
		                        y: -5,
		                        height: 10,
		                        width: 10,
		                        padding: 5
		                    }
		                },
		                uniqueNames: false

		            }, userOptions, { // User options
		                // Forced options
		                reversed: true,
		                // grid.columns is not supported in treegrid
		                grid: {
		                    columns: undefined
		                }
		            });
		        }

		        // Now apply the original function with the original arguments,
		        // which are sliced off this function's arguments
		        proceed.apply(axis, [chart, userOptions]);
		        if (isTreeGrid) {
		            H.addEvent(axis.chart, 'beforeRender', function () {
		                var labelOptions = axis.options && axis.options.labels;

		                // beforeRender is fired after all the series is initialized,
		                // which is an ideal time to update the axis.categories.
		                axis.updateYNames();

		                // Update yData now that we have calculated the y values
		                // TODO: it would be better to be able to calculate y values
		                // before Series.setData
		                each(axis.series, function (series) {
		                    series.yData = map(series.options.data, function (data) {
		                        return data.y;
		                    });
		                });

		                // Calculate the label options for each level in the tree.
		                axis.mapOptionsToLevel = getLevelOptions({
		                    defaults: labelOptions,
		                    from: 1,
		                    levels: labelOptions.levels,
		                    to: axis.tree.height
		                });

		                // Collapse all the nodes belonging to a point where collapsed
		                // equals true.
		                // Can be called from beforeRender, if getBreakFromNode removes
		                // its dependency on axis.max.
		                removeFoundExtremesEvent =
		                    H.addEvent(axis, 'foundExtremes', function () {
		                        each(axis.collapsedNodes, function (node) {
		                            var breaks = collapse(axis, node);
		                            axis.setBreaks(breaks, false);
		                        });
		                        removeFoundExtremesEvent();
		                    });
		            });
		            axis.hasNames = true;
		            axis.options.showLastLabel = true;
		        }
		    },
		    /**
		     * Override to add indentation to axis.maxLabelDimensions.
		     * @param  {Function}   proceed the original function
		     * @returns {undefined}
		     */
		    getMaxLabelDimensions: function (proceed) {
		        var axis = this,
		            options = axis.options,
		            labelOptions = options && options.labels,
		            indentation = (
		                labelOptions && isNumber(labelOptions.indentation) ?
		                options.labels.indentation :
		                0
		            ),
		            retVal = proceed.apply(axis, argsToArray(arguments)),
		            isTreeGrid = axis.options.type === 'treegrid',
		            treeDepth;

		        if (isTreeGrid) {
		            treeDepth = axis.mapOfPosToGridNode[-1].height;
		            retVal.width += indentation * (treeDepth - 1);
		        }

		        return retVal;
		    },
		    /**
		     * Generates a tick for initial positioning.
		     *
		     * @private
		     * @param {function} proceed The original generateTick function.
		     * @param {number} pos The tick position in axis values.
		     */
		    generateTick: function (proceed, pos) {
		        var axis = this,
		            mapOptionsToLevel = (
		                isObject(axis.mapOptionsToLevel) ? axis.mapOptionsToLevel : {}
		            ),
		            isTreeGrid = axis.options.type === 'treegrid',
		            ticks = axis.ticks,
		            tick = ticks[pos],
		            levelOptions,
		            options,
		            gridNode;

		        if (isTreeGrid) {
		            gridNode = axis.mapOfPosToGridNode[pos];
		            levelOptions = mapOptionsToLevel[gridNode.depth];

		            if (levelOptions) {
		                options = {
		                    labels: levelOptions
		                };
		            }

		            if (!tick) {
		                ticks[pos] = tick =
		                    new GridAxisTick(axis, pos, null, undefined, {
		                        category: gridNode.name,
		                        tickmarkOffset: gridNode.tickmarkOffset,
		                        options: options
		                    });
		            } else {
		                // update labels depending on tick interval
		                tick.parameters.category = gridNode.name;
		                tick.options = options;
		                tick.addLabel();
		            }
		        } else {
		            proceed.apply(axis, argsToArray(arguments));
		        }
		    },
		    /**
		     * Set the tick positions, tickInterval, axis min and max.
		     *
		     * @private
		     */
		    setTickInterval: function (proceed) {
		        var axis = this,
		            options = axis.options,
		            isTreeGrid = options.type === 'treegrid';

		        if (isTreeGrid) {
		            axis.min = pick(axis.userMin, options.min, axis.dataMin);
		            axis.max = pick(axis.userMax, options.max, axis.dataMax);

		            fireEvent(axis, 'foundExtremes');

		            // setAxisTranslation modifies the min and max according to
		            // axis breaks.
		            axis.setAxisTranslation(true);

		            axis.tickmarkOffset = 0.5;
		            axis.tickInterval = 1;
		            axis.tickPositions = getTickPositions(axis);
		        } else {
		            proceed.apply(axis, argsToArray(arguments));
		        }
		    }
		});
		override(GridAxisTick.prototype, {
		    getLabelPosition: function (
		        proceed,
		        x,
		        y,
		        label,
		        horiz,
		        labelOptions,
		        tickmarkOffset,
		        index,
		        step
		    ) {
		        var tick = this,
		            lbOptions = pick(
		                tick.options && tick.options.labels,
		                labelOptions
		            ),
		            pos = tick.pos,
		            axis = tick.axis,
		            options = axis.options,
		            isTreeGrid = options.type === 'treegrid',
		            result = proceed.apply(
		                tick,
		                [x, y, label, horiz, lbOptions, tickmarkOffset, index, step]
		            ),
		            symbolOptions,
		            indentation,
		            mapOfPosToGridNode,
		            node,
		            level;

		        if (isTreeGrid) {
		            symbolOptions = (
		                lbOptions && isObject(lbOptions.symbol) ?
		                lbOptions.symbol :
		                {}
		            );
		            indentation = (
		                lbOptions && isNumber(lbOptions.indentation) ?
		                lbOptions.indentation :
		                0
		            );
		            mapOfPosToGridNode = axis.mapOfPosToGridNode;
		            node = mapOfPosToGridNode && mapOfPosToGridNode[pos];
		            level = (node && node.depth) || 1;
		            result.x += (
		                // Add space for symbols
		                ((symbolOptions.width) + (symbolOptions.padding * 2)) +
		                // Apply indentation
		                ((level - 1) * indentation)
		            );
		        }

		        return result;
		    },
		    renderLabel: function (proceed) {
		        var tick = this,
		            pos = tick.pos,
		            axis = tick.axis,
		            label = tick.label,
		            mapOfPosToGridNode = axis.mapOfPosToGridNode,
		            options = axis.options,
		            labelOptions = pick(
		                tick.options && tick.options.labels,
		                options && options.labels
		            ),
		            symbolOptions = (
		                labelOptions && isObject(labelOptions.symbol) ?
		                labelOptions.symbol :
		                {}
		            ),
		            node = mapOfPosToGridNode && mapOfPosToGridNode[pos],
		            level = node && node.depth,
		            isTreeGrid = options.type === 'treegrid',
		            hasLabel = !!(label && label.element),
		            shouldRender = inArray(pos, axis.tickPositions) > -1,
		            prefixClassName = 'highcharts-treegrid-node-',
		            collapsed,
		            addClassName,
		            removeClassName;

		        if (isTreeGrid && node) {
		            // Add class name for hierarchical styling.
		            if (hasLabel) {
		                label.addClass(prefixClassName + 'level-' + level);
		            }
		        }

		        proceed.apply(tick, argsToArray(arguments));

		        if (isTreeGrid && node && hasLabel && node.descendants > 0) {
		            collapsed = isCollapsed(axis, node);

		            renderLabelIcon(
		                tick,
		                {

		                    collapsed: collapsed,
		                    group: label.parentGroup,
		                    options: symbolOptions,
		                    renderer: label.renderer,
		                    show: shouldRender,
		                    xy: label.xy
		                }
		            );

		            // Add class name for the node.
		            addClassName = prefixClassName +
		                (collapsed ? 'collapsed' : 'expanded');
		            removeClassName = prefixClassName +
		                (collapsed ? 'expanded' : 'collapsed');

		            label
		                .addClass(addClassName)
		                .removeClass(removeClassName);

		            // Add events to both label text and icon
		            each([label, tick.labelIcon], function (object) {
		                if (!object.attachedTreeGridEvents) {
		                    // On hover
		                    H.addEvent(object.element, 'mouseover', function () {
		                        onTickHover(label);
		                    });

		                    // On hover out
		                    H.addEvent(object.element, 'mouseout', function () {
		                        onTickHoverExit(label, labelOptions);
		                    });

		                    H.addEvent(object.element, 'click', function () {
		                        tick.toggleCollapse();
		                    });
		                    object.attachedTreeGridEvents = true;
		                }
		            });
		        }
		    }
		});

		extend(GridAxisTick.prototype, /** @lends Highcharts.Tick.prototype */{
		    /**
		     * Collapse the grid cell. Used when axis is of type treegrid.
		     * @param  {boolean} [redraw=true] Whether to redraw the chart or wait for
		     * an explicit call to {@link Highcharts.Chart#redraw}
		     * @sample {gantt} gantt/treegrid-axis/collapsed-dynamically/demo.js
		     * Dynamically collapse
		     */
		    collapse: function (redraw) {
		        var tick = this,
		            axis = tick.axis,
		            pos = tick.pos,
		            node = axis.mapOfPosToGridNode[pos],
		            breaks = collapse(axis, node);
		        axis.setBreaks(breaks, pick(redraw, true));
		    },
		    /**
		     * Expand the grid cell. Used when axis is of type treegrid.
		     *
		     * @param  {boolean} [redraw=true] Whether to redraw the chart or wait for
		     * an explicit call to {@link Highcharts.Chart#redraw}
		     * @sample {gantt} gantt/treegrid-axis/collapsed-dynamically/demo.js
		     * Dynamically collapse
		     */
		    expand: function (redraw) {
		        var tick = this,
		            axis = tick.axis,
		            pos = tick.pos,
		            node = axis.mapOfPosToGridNode[pos],
		            breaks = expand(axis, node);
		        axis.setBreaks(breaks, pick(redraw, true));
		    },
		    /**
		     * Toggle the collapse/expand state of the grid cell. Used when axis is of
		     * type treegrid.
		     *
		     * @param  {boolean} [redraw=true] Whether to redraw the chart or wait for
		     * an explicit call to {@link Highcharts.Chart#redraw}
		     * @sample {gantt} gantt/treegrid-axis/collapsed-dynamically/demo.js
		     * Dynamically collapse
		     */
		    toggleCollapse: function (redraw) {
		        var tick = this,
		            axis = tick.axis,
		            pos = tick.pos,
		            node = axis.mapOfPosToGridNode[pos],
		            breaks = toggleCollapse(axis, node);
		        axis.setBreaks(breaks, pick(redraw, true));
		    }
		});

		GridAxis.prototype.updateYNames = function () {
		    var axis = this,
		        options = axis.options,
		        isTreeGrid = options.type === 'treegrid',
		        uniqueNames = options.uniqueNames,
		        isYAxis = !axis.isXAxis,
		        series = axis.series,
		        numberOfSeries = 0,
		        treeGrid,
		        data;

		    if (isTreeGrid && isYAxis) {
		        // Concatenate data from all series assigned to this axis.
		        data = reduce(series, function (arr, s) {
		            if (s.visible) {
		                // Push all data to array
		                each(s.options.data, function (data) {
		                    if (isObject(data)) {
		                        // Set series index on data. Removed again after use.
		                        data.seriesIndex = numberOfSeries;
		                        arr.push(data);
		                    }
		                });

		                // Increment series index
		                if (uniqueNames === true) {
		                    numberOfSeries++;
		                }
		            }
		            return arr;
		        }, []);

		        // Calculate categories and the hierarchy for the grid.
		        treeGrid = getTreeGridFromData(
		            data,
		            uniqueNames,
		            (uniqueNames === true) ? numberOfSeries : 1
		        );

		        // Assign values to the axis.
		        axis.categories = treeGrid.categories;
		        axis.mapOfPosToGridNode = treeGrid.mapOfPosToGridNode;
		        // Used on init to start a node as collapsed
		        axis.collapsedNodes = treeGrid.collapsedNodes;
		        axis.hasNames = true;
		        axis.tree = treeGrid.tree;
		    }
		};

		// Make utility functions available for testing.
		GridAxis.prototype.utils = {
		    getNode: Tree.getNode
		};

	}(Highcharts, Tree, result));
	return (function () {

	}());
}));


text:
package org.apache.cassandra.net;

import java.nio.ByteBuffer;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import org.apache.cassandra.utils.memory.BufferPool;

import static org.apache.cassandra.net.FrameEncoderCrc.HEADER_LENGTH;
import static org.apache.cassandra.net.FrameEncoderCrc.writeHeader;

/**
 * A frame encoder that writes frames, just without any modification or payload protection.
 * This is non-standard, and useful for systems that have a trusted transport layer that want
 * to avoid incurring the (very low) cost of computing a CRC.
 *
 * Please see {@link FrameDecoderUnprotected} for description of the framing produced by this encoder.
 */
@ChannelHandler.Sharable
class FrameEncoderUnprotected extends FrameEncoder
{
    static final FrameEncoderUnprotected instance = new FrameEncoderUnprotected();
    static final PayloadAllocator allocator = (isSelfContained, capacity) ->
        new Payload(isSelfContained, capacity, HEADER_LENGTH, 0);

    PayloadAllocator allocator()
    {
        return allocator;
    }

    ByteBuf encode(boolean isSelfContained, ByteBuffer frame)
    {
        try
        {
            int frameLength = frame.remaining();
            int dataLength = frameLength - HEADER_LENGTH;
            if (dataLength >= 1 << 17)
                throw new IllegalArgumentException("Maximum uncompressed payload size is 128KiB");

            writeHeader(frame, isSelfContained, dataLength);
            return GlobalBufferPoolAllocator.wrap(frame);
        }
        catch (Throwable t)
        {
            BufferPool.put(frame);
            throw t;
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
Quick sort is like merge sort in that it's a divide and conquer recursive
algorithm. It differs however by where the work is being done. In merge
sort, we do the bulk of the work in the combine step, but with quick sort
the work is done in the divide step. In general, it will outperform merge
sort and it is done in place which is even better. As an example:

If we have a set: `[3, 7, 8, 5, 4]`

Using quick sort, we find the **pivot** or point which we will split the set
into two parts. In practice, we select the last item in the set. This is the
**partition** phase. In our set, our first pivot is `4`. We then take this
pivot and compare it with each other number in the set:

```
4 > 3, set is: [3, 7, 8, 5, [4]]
4 < 7, set is: [3, 8, 5, [4], 7]
4 < 8, set is: [3, 5, [4], 8, 7]
4 < 5, set is: [3, [4], 5, 8, 7]
```

Now that the data is partitioned as `[3]` and `[5, 8, 7]` we can break them
apart and do a quick sort on each smaller set like we did before. In this
case, we see that `[3]` is alone so this is already sorted. Our other set is
not though. On that side, the pivot value becomes `7`.

```
7 > 5, set is: [5, 8, [7]]
7 < 8, set is: [5, [7], 8]
```

This gives us single values on each side as well and now we have the following
values that need to bubble up:

```
[3] (Initial left single number)
[4] (Initial pivot value)
[5] (Smaller of right subset)
[7] (Second pivot value)
[8] (Larger of right subset)
```

Bubbling up, we get the sorted set of `[3, 4, 5, 7, 8]`.

## Time Complexity

| Case      | Complexity  |
| --------- |:-----------:|
| Worst     | `O(n^2)`    |
| Best      | `O(n lg n)` |
| Average   | `O(n lg n)` |