UNPKG

@progress/kendo-ui

Version:

This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.

7,334 lines 250 kB
import './kendo.dom.js';
import './kendo.data.js';
import './kendo.icons.js';
import './kendo.loader.js';
import './kendo.html.loadercontainer.js';
import './kendo.sortable.js';
import { fetchDiscover, fetchData, createDataState, PivotGridNavigation, headersReducer, toData, toTree, toColumns, toRows, sumAggregate, setSort, setFilter, rootFields, readData, parseResponse, minAggregate, mergeTrees, maxAggregate, discoverCommands, createTuples, createRequestBody, createLocalDataState, createFlatSchemaDimensions, createDiscoverBody, createDataTree, createAxisDescriptors, configuratorReducer, compareAxes, cloneDataTree, buildKPIMeasures, averageAggregate, addMultipleMeasures, addKPI, countAggregate } from '@progress/kendo-pivotgrid-common';
import { u as useLoaderContainer } from './loaderContainer-CKYFB4vJ.js';
import './kendo.core.js';
import './kendo.licensing.js';
import '@progress/kendo-licensing';
import './kendo.data.odata.js';
import './kendo.data.xml.js';
import './kendo.html.icon.js';
import './kendo.html.base.js';
import '@progress/kendo-svg-icons';
import './kendo.draganddrop.js';
import './kendo.userevents.js';

const __meta__ = {
    id: "pivotgrid",
    name: "PivotGrid",
    category: "web",
    description: "The PivotGrid widget is a data summarization tool.",
    depends: [ "dom", "data", "data.xml", "sortable", "icons", "loader", "html.loadercontainer" ],
    features: [{
        id: "pivotgrid-configurator",
        name: "Configurator",
        description: "The PivotConfigurator widget allows the user to select data slices displayed in PivotGrid",
        depends: [ "pivot.configurator" ]
    }, {
        id: "pivotgrid-filtering",
        name: "Filtering",
        description: "Support for filtering",
        depends: [ "pivot.fieldmenu" ]
    }, {
        id: "pivotgrid-excel-export",
        name: "Excel export",
        description: "Export pivot grid data as Excel spreadsheet",
        depends: [ "ooxml" ]
    }, {
        id: "pivotgrid-pdf-export",
        name: "PDF export",
        description: "Export pivot grid data as PDF",
        depends: [ "pdf", "drawing" ]
    }, {
        id: "mobile-scroller",
        name: "Mobile scroller",
        description: "Support for kinetic scrolling in mobile device",
        depends: [ "mobile.scroller" ]
    }]
};


(function($, undefined$1) {
    var kendo = window.kendo,
        ui = kendo.ui,
        encode = kendo.htmlEncode,
        Class = kendo.Class,
        Comparer = kendo.data.Comparer,
        Widget = ui.Widget,
        DataSource = kendo.data.DataSource,
        outerWidth = kendo._outerWidth,
        outerHeight = kendo._outerHeight,
        normalizeFilter = kendo.data.Query.normalizeFilter,
        normalizeSort = kendo.data.Query.normalizeSort,
        toString = {}.toString,
        identity = function(o) { return o; },
        map = $.map,
        extend = $.extend,
        keys = kendo.keys,
        isFunction = kendo.isFunction,
        RESIZE = "resize",
        READ = "read",
        CHANGE = "change",
        ERROR = "error",
        REQUESTSTART = "requestStart",
        PROGRESS = "progress",
        REQUESTEND = "requestEnd",
        MEASURES = "Measures",
        STATERESET = "stateReset",
        AUTO = "auto",
        DIV = "<div></div>",
        NS = ".kendoPivotGrid",
        ROW_TOTAL_KEY = "__row_total__",
        DATABINDING = "dataBinding",
        DATABOUND = "dataBound",
        EXPANDMEMBER = "expandMember",
        HEADERTEMPLATE = ({ id, key, headerClass, colspan, rowspan, expandable, iconClass, role, expanded }) => `<th id="${id}" role="${role}" ${expandable ? `aria-expanded="${expanded}"` : ''}  data-key="${encode(key)}" class="${encode(headerClass)}" ${colspan ? 'colspan="' + encode(colspan) + '"' : ''} ${rowspan ? 'rowspan="' + encode(rowspan) + '"' : ''}>` +
                                    `${expandable ? kendo.ui.icon($('<span role="presentation" class="k-pivotgrid-toggle"></span>'), { icon: `chevron-${encode(iconClass)}` }) : ''}` +
                                '</th>',
        COLLAPSEMEMBER = "collapseMember",
        STATE_EXPANDED_ICONNAME = "caret-alt-down",
        STATE_EXPANDED_SELECTOR = `.k-i-${STATE_EXPANDED_ICONNAME},.k-svg-i-${STATE_EXPANDED_ICONNAME}`,
        STATE_COLLAPSED_ICONNAME = "caret-alt-right",
        HEADER_TEMPLATE = ({ member }) => `<span>${encode(member.caption || member.name)}</span>`,
        PIVOTGRID_TREND_ICONS_MAP = {
            "kpi-trend-decrease": "caret-alt-down",
            "kpi-trend-increase": "caret-alt-up",
            "kpi-trend-equal": "minus",
        },
        KPISTATUS_TEMPLATE = ({ dataItem }) => kendo.ui.icon($(`<span title="${encode(dataItem.value)}"></span>`), { icon: `kpi-status-${dataItem.value > 0 ? "open" : dataItem.value < 0 ? "deny" : "hold"}` }),
        KPITREND_TEMPLATE = ({ dataItem }) => kendo.ui.icon($(`<span title="${encode(dataItem.value)}"></span>`), { icon: PIVOTGRID_TREND_ICONS_MAP[`kpi-trend-${dataItem.value > 0 ? "increase" : dataItem.value < 0 ? "decrease" : "equal"}`] }),
        DATACELL_TEMPLATE = ({ dataItem }) => (dataItem ? dataItem.fmtValue || dataItem.value ? `<span class="k-pivotgrid-content">${encode(dataItem.fmtValue || dataItem.value)}</span>` : "&nbsp;" : "&nbsp;"),
        LAYOUT_TABLE = '<table class="k-pivot-layout">' +
                            '<tr>' +
                                '<td>' +
                                    '<div class="k-pivot-rowheaders"></div>' +
                                '</td>' +
                                '<td>' +
                                    '<div class="k-pivot-table"></div>' +
                                '</td>' +
                            '</tr>' +
                        '</table>';
        var AXIS_ROWS = "rows";
        var AXIS_COLUMNS = "columns";

        var tableStyles = {
            tableRow: "k-table-row",
            header: "k-header k-table-th",
            headerTable: "k-grid-header-table k-table k-table-md",
            table: "k-table k-table-md",
            contentTable: "k-grid-table k-table k-table-md",
            tbody: "k-table-tbody",
            tableCell: "k-table-td"
        };

    function normalizeMeasures(measure) {
        var descriptor = typeof measure === "string" ? [{ name: measure }] : measure;
        var descriptors = toString.call(descriptor) === "[object Array]" ? descriptor : (descriptor !== undefined$1 ? [descriptor] : []);

        return map(descriptors, function(d) {
            if (typeof d === "string") {
                return { name: d };
            }
            return $.extend(true, d, { name: d.name, type: d.type });
        });
    }

    function normalizeMembers(member) {
        var descriptor = typeof member === "string" ? [{ name: [member], expand: false }] : member;
        var descriptors = toString.call(descriptor) === "[object Array]" ? descriptor : (descriptor !== undefined$1 ? [descriptor] : []);

        return map(descriptors, function(d) {
            if (typeof d === "string") {
                return { name: [d], expand: false };
            }
            return { name: (toString.call(d.name) === "[object Array]" ? d.name.slice() : [d.name]), expand: d.expand };
        });
    }

    function normalizeName(name) {
        if (name.indexOf(" ") !== -1) {
            name = '["' + name + '"]';
        }

        return name;
    }

    function accumulateMembers(accumulator, rootTuple, tuple, level) {
        var idx, length;
        var children;
        var member;

        if (!tuple) {
            tuple = rootTuple;
        }

        if (!level) {
            level = 0;
        }

        member = tuple.members[level];

        if (!member || member.measure) { //return if no member or measure
            return;
        }

        children = member.children;
        length = children.length;

        if (tuple === rootTuple) {
            accumulator[kendo.stringify([member.name])] = !!length;
        } else if (length) {
            accumulator[kendo.stringify(buildPath(tuple, level))] = true;
        }

        if (length) {
            for (idx = 0; idx < length; idx++) {
                accumulateMembers(accumulator, rootTuple, children[idx], level);
            }
        }

        accumulateMembers(accumulator, rootTuple, tuple, level + 1);
    }

    function descriptorsForAxes(tuples) {
        var result = {};

        if (tuples.length) {
            accumulateMembers(result, tuples[0]);
        }

        var descriptors = [];
        for (var k in result) {
            descriptors.push({ name: JSON.parse(k), expand: result[k] });
        }

        return descriptors;
    }

    function addMissingPathMembers(members, axis) {
        var tuples = axis.tuples || [];
        var firstTuple = tuples[0];

        if (firstTuple && members.length < firstTuple.members.length) {
            var tupleMembers = firstTuple.members;

            for (var idx = 0; idx < tupleMembers.length; idx++) {
                if (tupleMembers[idx].measure) {
                    continue;
                }

                var found = false;
                for (var j = 0; j < members.length; j++) {
                    if (getName(members[j]).indexOf(tupleMembers[idx].hierarchy) === 0) {
                        found = true;
                        break;
                    }
                }

                if (!found) {
                    members.push({ name: [tupleMembers[idx].name], expand: false }); //calling normalize here to make name from string to array
                }
            }
        }
    }

    function tupleToDescriptors(tuple) {
        var result = [];
        var members = tuple.members;

        for (var idx = 0; idx < members.length; idx++) {
            if (members[idx].measure) {
                continue;
            }

            //make tuple name an array
            result.push({ name: [members[idx].name], expand: members[idx].children.length > 0 });
        }

        return result;
    }

    function descriptorsForMembers(axis, members, measures) {
        axis = axis || {};

        addMissingPathMembers(members, axis);

        if (measures.length > 1) {
            members.push({
                name: MEASURES,
                measure: true,
                children: normalizeMembers(measures)
            });
        }

        var tupletoSearch = {
            members: members
        };

        if (axis.tuples) {
            var result = findExistingTuple(axis.tuples, tupletoSearch);
            if (result.tuple) {
                members = tupleToDescriptors(result.tuple);
            }
        }

        return members;
    }

    function createAggregateGetter(m) {
        var measureGetter = kendo.getter(m.field, true);
        return function(aggregatorContext, state) {
            return m.aggregate(measureGetter(aggregatorContext.dataItem), state, aggregatorContext);
        };
    }

    function isNumber(val) {
        return typeof val === "number" && !isNaN(val);
    }

    function isDate(val) {
        return val && val.getTime;
    }

    function getScollWidth() {
        var scrollbar = 0;
        var div;
        if (document && document.createElement) {
            div = document.createElement('div');

            div.style.cssText = 'overflow:scroll;overflow-x:hidden;zoom:1;clear:both;display:block';
            div.innerHTML = '&nbsp;';
            document.body.appendChild(div);

            scrollbar = div.offsetWidth - div.scrollWidth;

            document.body.removeChild(div);
        }

        return scrollbar;
    }

    function loadLocalData(data, params, deferred) {
        const that = this;
        const originalData = (that.reader.data(data) || []).slice(0);
        if (originalData && !that._pristineData) {
            that._pristineData = originalData;
        }
        const columnSettings = that._createSettings(params.columnAxes);
        const rowSettings = that._createSettings(params.rowAxes);
        const measures = that.measures();
        const dataTree = createDataTree(originalData, rowSettings, columnSettings, measures, { dataField: "aggregate", columnsData: "columns" }, that.filter() || []);

        const stateArgs = {
            dataTree: dataTree,
            columnSettings: columnSettings,
            rowSettings: rowSettings,
            columnAxes: params.columnAxes,
            rowAxes: params.rowAxes,
            measures: measures.map(function(item) { return item; }),
            fields: { dataField: "aggregate", columnsData: "columns" },
            sort: flattenSortDescriptors(params.sort || [])
        };

        that._saveState(createLocalDataState(stateArgs));
        that.trigger(CHANGE);
        deferred.resolve();
    }

    function flattenSortDescriptors(descriptors) {
        var result = [];
        for (var i = 0; i < descriptors.length; i++) {
            result.push({
                dir: descriptors[i].dir,
                field: descriptors[i].field.split(".").pop()
            });
        }
        return result;
    }

    function createLocalMeasure(field, key, format, aggregate) {
        var formatFunc = function(value) { return kendo.format(this.format, value); };
        var measureMap = {
            "sum": sumAggregate,
            "average": averageAggregate,
            "min": minAggregate,
            "max": maxAggregate,
            "count": countAggregate,
        };
        var valueFunc = function(item) { return item[this.field]; };
        var measure = {
                value: valueFunc.bind({ field: field }),
                aggregate: measureMap[aggregate],
                caption: key,
                uniqueName: key,
                type: 2,
                name: [key]
            };
        if (format) {
            measure.aggregate.format = formatFunc.bind({ format: format });
        }

        return measure;
    }

    function getIcons(sortIcon, options, pivotOptions) {
        var sortable = options.sortable,
            filterable = options.filterable,
            reorderable = pivotOptions.reorderable,
            result = "";

        if (sortable) {
            result += sortIcon ? `<span class="k-chip-action">${kendo.ui.icon(sortIcon + "-sm")}</span>` : '';
        }

        if (filterable || sortable) {
            result += `<span class="k-setting-fieldmenu k-chip-action">${kendo.ui.icon("more-vertical")}</span>`;
        }
        if (reorderable) {
            result += `<span class="k-setting-delete k-chip-action">${kendo.ui.icon("x")}</span>`;
        }

        return result;
    }

    var functions = {
        sum: function(value, state) {
            var accumulator = state.accumulator;

            if (!isNumber(accumulator)) {
                accumulator = value;
            } else if (isNumber(value)) {
                accumulator += value;
            }

            return accumulator;
        },
        count: function(value, state) {
            return (state.accumulator || 0) + 1;
        },
        average: {
            aggregate: function(value, state) {
                var accumulator = state.accumulator;

                if (state.count === undefined$1) {
                    state.count = 0;
                }

                if (!isNumber(accumulator)) {
                    accumulator = value;
                } else if (isNumber(value)) {
                    accumulator += value;
                }

                if (isNumber(value)) {
                    state.count++;
                }

                return accumulator;
            },
            result: function(state) {
                var accumulator = state.accumulator;

                if (isNumber(accumulator)) {
                    accumulator = accumulator / state.count;
                }

                return accumulator;
            }
        },
        max: function(value, state) {
            var accumulator = state.accumulator;

            if (!isNumber(accumulator) && !isDate(accumulator)) {
                accumulator = value;
            }

            if (accumulator < value && (isNumber(value) || isDate(value))) {
                accumulator = value;
            }
            return accumulator;
        },
        min: function(value, state) {
            var accumulator = state.accumulator;

            if (!isNumber(accumulator) && !isDate(accumulator)) {
                accumulator = value;
            }

            if (accumulator > value && (isNumber(value) || isDate(value))) {
                accumulator = value;
            }
            return accumulator;
        }
    };

    var PivotCubeBuilder = Class.extend({
        init: function(options) {
            this.options = extend({}, this.options, options);
            this.dimensions = this._normalizeDescriptors("field", this.options.dimensions);
            this.measures = this._normalizeDescriptors("name", this.options.measures);
        },

        _normalizeDescriptors: function(keyField, descriptors) {
            descriptors = descriptors || {};
            var fields = {};
            var field;

            if (toString.call(descriptors) === "[object Array]") {
                for (var idx = 0, length = descriptors.length; idx < length; idx++) {
                    field = descriptors[idx];
                    if (typeof field === "string") {
                        fields[field] = {};
                    } else if (field[keyField]) {
                        fields[field[keyField]] = field;
                    }
                }
                descriptors = fields;
            }

            return descriptors;
        },

        _rootTuples: function(rootNames, measureAggregators) {
            var aggregatorsLength = measureAggregators.length || 1;
            var dimensionsSchema = this.dimensions || [];
            var root, name, parts;
            var measureIdx = 0;
            var idx;

            var rootNamesLength = rootNames.length;
            var result = [];
            var keys = [];

            if (rootNamesLength || measureAggregators.length) {
                for (measureIdx = 0; measureIdx < aggregatorsLength; measureIdx++) {

                    root = { members: [] };

                    for (idx = 0; idx < rootNamesLength; idx++) {
                        name = rootNames[idx];
                        parts = name.split("&");

                        root.members[root.members.length] = {
                            children: [],
                            caption: (dimensionsSchema[name] || {}).caption || "All",
                            name: name,
                            levelName: name,
                            levelNum: "0",
                            hasChildren: true,
                            parentName: parts.length > 1 ? parts[0] : undefined$1,
                            hierarchy: name
                        };
                    }

                    if (aggregatorsLength > 1) {
                        root.members[root.members.length] = {
                            children: [],
                            caption: (measureAggregators[measureIdx]).caption,
                            name: measureAggregators[measureIdx].descriptor.name,
                            levelName: "MEASURES",
                            levelNum: "0",
                            hasChildren: false,
                            parentName: undefined$1,
                            hierarchy: "MEASURES"
                        };
                    }

                    result[result.length] = root;
                }

                keys.push(ROW_TOTAL_KEY);
            }

            return {
                keys: keys,
                tuples: result
            };
        },

        _sortMap: function(map, sortDescriptors) {
            var sortedMaps = [];
            var sortTree = [];
            var flattenTree = [];
            var mapItem;
            var key;

            for (key in map) {
                if (!map[key].directParentName) {
                    sortTree.push($.extend({}, { name: key, parentName: map[key].parentName }));
                }
            }

            //if there are no root this means that something is expanding
            //and we should only sort that part of the tree
            if (!sortTree.length) {
                for (key in map) {
                    sortTree.push($.extend({}, { name: key, parentName: map[key].parentName }));
                }
            }

            fillSortTree(sortTree, map);

            // fill tree recursive
            for (var i = 0; i < sortDescriptors.length; i++) {
                sortItemsTree(sortDescriptors[i].field.split(".").pop(), sortTree, Comparer.create({ field: "name", dir: sortDescriptors[i].dir }));
            }

            flattenTree = flatColumns(sortTree);

            //we need to flatten the structure so the tuples can build correctly
            for (var j = 0; j < flattenTree.length; j++) {
                mapItem = map[flattenTree[j].name];
                mapItem.index = j;
                sortedMaps[j] = mapItem;
            }

            return sortedMaps;
        },

        _expandedTuples: function(map, expanded, measureAggregators, sortDescriptors) {
            var aggregatorsLength = measureAggregators.length || 1;
            var dimensionsSchema = this.dimensions || [];
            var measureIdx;
            var tuple;

            var key;
            var mapItem;
            var current;
            var currentKeys;
            var accumulator = [];
            var accumulatorKeys = [];
            var memberInfo;

            var expandedNames;
            var parts;
            var name;
            var idx;

            if (sortDescriptors && sortDescriptors.length && !$.isEmptyObject(map)) {
                map = this._sortMap(map, sortDescriptors);
            }

            for (key in map) {
                mapItem = map[key];
                memberInfo = this._findExpandedMember(expanded, mapItem.uniquePath);

                current = accumulator[memberInfo.index] || [];
                currentKeys = accumulatorKeys[memberInfo.index] || [];

                expandedNames = memberInfo.member.names;

                for (measureIdx = 0; measureIdx < aggregatorsLength; measureIdx++) {
                    tuple = { members: [] };
                    for (idx = 0; idx < expandedNames.length; idx++) {
                        if (idx === memberInfo.member.expandedIdx) {
                            tuple.members[tuple.members.length] = {
                                children: [],
                                caption: mapItem.value,
                                name: mapItem.name,
                                hasChildren: false,
                                levelNum: 1,
                                levelName: mapItem.parentName + mapItem.name,
                                parentName: mapItem.parentName,
                                hierarchy: mapItem.parentName + mapItem.name
                            };

                            if (measureIdx === 0) {
                                currentKeys.push(buildPath(tuple, idx).join(""));
                            }
                        } else {
                            name = expandedNames[idx];
                            parts = name.split("&");
                            tuple.members[tuple.members.length] = {
                                children: [],
                                caption: (dimensionsSchema[name] || {}).caption || "All",
                                name: name,
                                levelName: name,
                                levelNum: "0",
                                hasChildren: true,
                                parentName: parts.length > 1 ? parts[0] : undefined$1,
                                hierarchy: name
                            };
                        }
                    }

                    if (aggregatorsLength > 1) {
                        tuple.members[tuple.members.length] = {
                            children: [],
                            caption: measureAggregators[measureIdx].caption,
                            name: measureAggregators[measureIdx].descriptor.name,
                            levelName: "MEASURES",
                            levelNum: "0",
                            hasChildren: true,
                            parentName: undefined$1,
                            hierarchy: "MEASURES"
                        };
                    }

                    current[current.length] = tuple;
                }

                accumulator[memberInfo.index] = current;
                accumulatorKeys[memberInfo.index] = currentKeys;
            }

            return {
                keys: accumulatorKeys,
                tuples: accumulator
            };
        },

        _findExpandedMember: function(members, parentName) {
            for (var idx = 0; idx < members.length; idx++) {
                if (members[idx].uniquePath === parentName) {
                    return {
                        member: members[idx],
                        index: idx
                    };
                }
            }
        },

        _asTuples: function(map, descriptor, measureAggregators, sortDescriptors) {
            measureAggregators = measureAggregators || [];

            var rootInfo = this._rootTuples(descriptor.root, measureAggregators);
            var expandedInfo = this._expandedTuples(map, descriptor.expanded, measureAggregators, sortDescriptors);

            return {
                keys: [].concat.apply(rootInfo.keys, expandedInfo.keys),
                tuples: [].concat.apply(rootInfo.tuples, expandedInfo.tuples)
            };
        },

        _measuresInfo: function(measures, rowAxis) {
            var idx = 0;
            var length = measures && measures.length;

            var aggregateNames = [];
            var resultFuncs = {};
            var formats = {};

            var descriptors = (this.measures || {});
            var measure;
            var name;

            for (; idx < length; idx++) {
                name = measures[idx].descriptor.name;
                measure = descriptors[name] || {};

                aggregateNames.push(name);

                if (measure.result) {
                    resultFuncs[name] = measure.result;
                }

                if (measure.format) {
                    formats[name] = measure.format;
                }
            }

            return {
                names: aggregateNames,
                formats: formats,
                resultFuncs: resultFuncs,
                rowAxis: rowAxis
            };
        },

        _toDataArray: function(map, measuresInfo, rowKeys, columnKeys) {
            var result = [];

            var aggregates;
            var name, i, j, k, n;
            var row, column, columnKey;

            var rowMeasureNamesLength = 1;
            var rowMeasureNames = [];
            var columnMeasureNames;

            var rowLength = rowKeys.length || 1;
            var columnLength = columnKeys.length || 1;

            if (measuresInfo.rowAxis) {
                rowMeasureNames = measuresInfo.names;
                rowMeasureNamesLength = rowMeasureNames.length;
            } else {
                columnMeasureNames = measuresInfo.names;
            }

            for (i = 0; i < rowLength; i++) {
                row = map[rowKeys[i] || ROW_TOTAL_KEY];

                for (n = 0; n < rowMeasureNamesLength; n++) {
                    if (measuresInfo.rowAxis) {
                        columnMeasureNames = [rowMeasureNames[n]];
                    }

                    for (j = 0; j < columnLength; j++) {
                        columnKey = columnKeys[j] || ROW_TOTAL_KEY;
                        column = row.items[columnKey];

                        if (columnKey === ROW_TOTAL_KEY) {
                            aggregates = row.aggregates;
                        } else {
                            aggregates = column ? column.aggregates : {};
                        }

                        for (k = 0; k < columnMeasureNames.length; k++) {
                            name = columnMeasureNames[k];
                            this._addData(result, aggregates[name], measuresInfo.formats[name], measuresInfo.resultFuncs[name]);
                        }
                    }
                }
            }

            return result;
        },

        _addData: function(result, value, format, resultFunc) {
            var fmtValue = "";
            var ordinal;

            if (value) {
                value = resultFunc ? resultFunc(value) : value.accumulator;
                fmtValue = format ? kendo.format(format, value) : value;
            }

            ordinal = result.length;

            result[ordinal] = {
                ordinal: ordinal,
                value: value || "",
                fmtValue: fmtValue
            };
        },

        _matchDescriptors: function(dataItem, descriptor, getters) {
            var parts;
            var parentField;
            var expectedValue;

            var names = descriptor.names;
            var idx = descriptor.expandedIdx;
            var value;

            while (idx > 0) {
                parts = names[--idx].split("&");
                if (parts.length > 1) {
                    parentField = parts[0];
                    expectedValue = parts[1];

                    value = getters[parentField](dataItem);
                    value = (value !== undefined$1 && value !== null) ? value.toString() : value;

                    if (value != expectedValue) {
                        return false;
                    }
                }
            }
            return true;
        },

        _calculateAggregate: function(measureAggregators, aggregatorContext, totalItem) {
            var result = {};
            var state;
            var name;

            for (var measureIdx = 0; measureIdx < measureAggregators.length; measureIdx++) {
                name = measureAggregators[measureIdx].descriptor.name;
                state = totalItem.aggregates[name] || { };
                state.accumulator = measureAggregators[measureIdx].aggregator(aggregatorContext, state);
                result[name] = state;
            }

            return result;
        },

        _processColumns: function(measureAggregators, descriptors, getters, columns, aggregatorContext, rowTotal, state, updateColumn) {
            var value;
            var descriptor;
            var column;
            var totalItem;
            var key, name, parentName, path;
            var dataItem = aggregatorContext.dataItem;
            var idx = 0;

            for (; idx < descriptors.length; idx++) {
                descriptor = descriptors[idx];

                //checks whether the dataItem is relevant to the descriptors
                if (!this._matchDescriptors(dataItem, descriptor, getters)) {
                    continue;
                }

                path = descriptor.names.slice(0, descriptor.expandedIdx).join("");
                name = descriptor.names[descriptor.expandedIdx];


                value = getters[name](dataItem);
                value = (value !== undefined$1 && value !== null) ? value.toString() : value;

                parentName = name;
                name = name + "&" + value;
                key = path + name;

                column = columns[key] || {
                    index: state.columnIndex,
                    parentName: parentName,
                    name: name,
                    directParentName: path.indexOf("&") !== -1 ? path : "",
                    uniquePath: path + parentName,
                    childrenMap: {},
                    value: value
                };

                if (path && columns[path] && !columns[path].childrenMap[path + parentName + "&" + value]) {
                    columns[path].childrenMap[path + parentName + "&" + value] = true;
                }

                totalItem = rowTotal.items[key] || {
                    aggregates: {}
                };

                rowTotal.items[key] = {
                    index: column.index,
                    aggregates: this._calculateAggregate(measureAggregators, aggregatorContext, totalItem)
                };

                if (updateColumn) {
                    if (!columns[key]) {
                        state.columnIndex++;
                    }
                    columns[key] = column;
                }
            }
        },

        _measureAggregators: function(options) {
            var measureDescriptors = options.measures || [];
            var measures = this.measures || {};
            var aggregators = [];
            var descriptor, measure, idx, length;
            var defaultAggregate, aggregate;

            if (measureDescriptors.length) {
                for (idx = 0, length = measureDescriptors.length; idx < length; idx++) {
                    descriptor = measureDescriptors[idx];
                    measure = measures[descriptor.name];
                    defaultAggregate = null;

                    if (measure) {
                        aggregate = measure.aggregate;
                        if (typeof aggregate === "string") {
                            defaultAggregate = functions[aggregate.toLowerCase()];

                            if (!defaultAggregate) {
                                throw new Error("There is no such aggregate function");
                            }

                            measure.aggregate = defaultAggregate.aggregate || defaultAggregate;
                            measure.result = defaultAggregate.result;
                        }


                        aggregators.push({
                            descriptor: descriptor,
                            caption: measure.caption,
                            result: measure.result,
                            aggregator: createAggregateGetter(measure)
                        });
                    }
                }
            } else {
                aggregators.push({
                    descriptor: { name: "default" },
                    caption: "default",
                    aggregator: function() { return 1; }
                });
            }

            return aggregators;
        },

        _buildGetters: function(names) {
            var result = {};
            var parts;
            var name;

            for (var idx = 0; idx < names.length; idx++) {
                name = names[idx];
                parts = name.split("&");

                if (parts.length > 1) {
                    result[parts[0]] = kendo.getter(parts[0], true);
                } else {
                    result[name] = kendo.getter(normalizeName(name), true);
                }
            }

            return result;
        },

        _parseDescriptors: function(descriptors) {
            var parsedDescriptors = parseDescriptors(descriptors);
            var rootNames = getRootNames(parsedDescriptors.root);
            var expanded = parsedDescriptors.expanded;
            var result = [];

            for (var idx = 0; idx < expanded.length; idx++) {
                result.push(mapNames(expanded[idx].name, rootNames));
            }

            return {
                root: rootNames,
                expanded: result
            };
        },

        _filter: function(data, filter) {
            if (!filter) {
                return data;
            }

            var expr;
            var idx = 0;
            var filters = filter.filters;

            for (; idx < filters.length; idx++) {
                expr = filters[idx];

                if (expr.operator === "in") {
                    filters[idx] = this._normalizeFilter(expr);
                }
            }

            return new kendo.data.Query(data).filter(filter).data;
        },

        _normalizeFilter: function(filter) {
            var value = filter.value.split(",");
            var result = [];

            if (!value.length) {
                return value;
            }

            for (var idx = 0; idx < value.length; idx++) {
                result.push({
                    field: filter.field,
                    operator: "eq",
                    value: value[idx]
                });
            }

            return {
                logic: "or",
                filters: result
            };
        },

        process: function(data, options) {
            data = data || [];
            options = options || {};

            data = this._filter(data, options.filter);

            var measures = options.measures || [];

            var measuresRowAxis = options.measuresAxis === "rows";

            var columnDescriptors = options.columns || [];
            var rowDescriptors = options.rows || [];

            if (!columnDescriptors.length && rowDescriptors.length && (!measures.length || (measures.length && measuresRowAxis))) {
                columnDescriptors = rowDescriptors;
                rowDescriptors = [];
                measuresRowAxis = false;
            }

            if (!columnDescriptors.length && !rowDescriptors.length) {
                measuresRowAxis = false;
            }

            if (!columnDescriptors.length && measures.length) {
                columnDescriptors = normalizeMembers(options.measures);
            }

            columnDescriptors = this._parseDescriptors(columnDescriptors);
            rowDescriptors = this._parseDescriptors(rowDescriptors);

            var aggregatedData = {};
            var columns = {};
            var rows = {};

            var rowValue;
            var state = { columnIndex: 0 };

            var measureAggregators = this._measureAggregators(options);

            var columnGetters = this._buildGetters(columnDescriptors.root);
            var rowGetters = this._buildGetters(rowDescriptors.root);

            var processed = false;

            var expandedColumns = columnDescriptors.expanded;
            var expandedRows = rowDescriptors.expanded;

            var dataItem;
            var aggregatorContext;
            var hasExpandedRows = expandedRows.length !== 0;

            var rowIdx, rowDescriptor, rowName, rowTotal;
            var key, path, parentName, value;
            var columnsInfo, rowsInfo;
            var length = data.length;
            var idx = 0;

            if (columnDescriptors.root.length || rowDescriptors.root.length) {
                processed = true;

                for (idx = 0; idx < length; idx++) {
                    dataItem = data[idx];

                    aggregatorContext = {
                        dataItem: dataItem,
                        index: idx
                    };

                    rowTotal = aggregatedData[ROW_TOTAL_KEY] || {
                        items: {},
                        aggregates: {}
                    };

                    this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, rowTotal, state, !hasExpandedRows);

                    rowTotal.aggregates = this._calculateAggregate(measureAggregators, aggregatorContext, rowTotal);
                    aggregatedData[ROW_TOTAL_KEY] = rowTotal;

                    for (rowIdx = 0; rowIdx < expandedRows.length; rowIdx++) {
                        rowDescriptor = expandedRows[rowIdx];

                        if (!this._matchDescriptors(dataItem, rowDescriptor, rowGetters)) {
                            this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, { items: {}, aggregates: {} }, state, true);
                            continue;
                        }

                        path = rowDescriptor.names.slice(0, rowDescriptor.expandedIdx).join("");
                        rowName = rowDescriptor.names[rowDescriptor.expandedIdx];

                        parentName = rowName;

                        rowValue = rowGetters[rowName](dataItem);
                        rowValue = rowValue !== undefined$1 ? rowValue.toString() : rowValue;

                        rowName = rowName + "&" + rowValue;
                        key = path + rowName;

                        rows[key] = {
                            uniquePath: path + parentName,
                            parentName: parentName,
                            name: rowName,
                            value: rowValue
                        };

                        value = aggregatedData[key] || {
                            items: {},
                            aggregates: {}
                        };

                        this._processColumns(measureAggregators, expandedColumns, columnGetters, columns, aggregatorContext, value, state, true);

                        value.aggregates = this._calculateAggregate(measureAggregators, aggregatorContext, value);
                        aggregatedData[key] = value;
                    }
                }
            }

            if (processed && length) {
                if (measureAggregators.length > 1 && (!options.columns || !options.columns.length)) {
                    columnDescriptors = {
                        root: [],
                        expanded: []
                    };
                }

                columnsInfo = this._asTuples(columns, columnDescriptors, measuresRowAxis ? [] : measureAggregators, options.sort ? options.sort : []);
                rowsInfo = this._asTuples(rows, rowDescriptors, measuresRowAxis ? measureAggregators : [], options.sort ? options.sort : []);

                columns = columnsInfo.tuples;
                rows = rowsInfo.tuples;

                aggregatedData = this._toDataArray(aggregatedData, this._measuresInfo(measureAggregators, measuresRowAxis), rowsInfo.keys, columnsInfo.keys);
            } else {
                aggregatedData = columns = rows = [];
            }

            return {
                axes: {
                    columns: { tuples: columns },
                    rows: { tuples: rows }
                },
                data: aggregatedData
            };
        }
    });

    var PivotTransport = Class.extend({
        init: function(options, transport) {
            this.transport = transport;
            this.options = transport.options || {};

            if (!this.transport.discover) {
                if (isFunction(options.discover)) {
                    this.discover = options.discover;
                }
            }
        },
        read: function(options) {
            return this.transport.read(options);
        },
        update: function(options) {
            return this.transport.update(options);
        },
        create: function(options) {
            return this.transport.create(options);
        },
        destroy: function(options) {
            return this.transport.destroy(options);
        },
        discover: function(options) {
            if (this.transport.discover) {
                return this.transport.discover(options);
            }
            options.success({});
        },
        catalog: function(val) {
            var options = this.options || {};

            if (val === undefined$1) {
                return (options.connection || {}).catalog;

            }

            var connection = options.connection || {};
            connection.catalog = val;

            this.options.connection = connection;
            $.extend(this.transport.options, { connection: connection });
        },
        cube: function(val) {
            var options = this.options || {};

            if (val === undefined$1) {
                return (options.connection || {}).cube;
            }

            var connection = options.connection || {};
            connection.cube = val;

            this.options.connection = connection;
            extend(true, this.transport.options, { connection: connection });
        }
    });

    var PivotDataSourceV2 = DataSource.extend({
        init: function(options) {

            var cube = ((options || {}).schema || {}).cube;

            var schema = {
                axes: identity,
                cubes: identity,
                catalogs: identity,
                measures: identity,
                dimensions: identity,
                hierarchies: identity,
                levels: identity,
                members: identity
            };

            if (cube) {
                this.cubeSchema = $.extend(schema, this._cubeSchema(cube));
            }

            DataSource.fn.init.call(this, extend(true, {}, {
                schema: this.cubeSchema
            }, options));

            var transportOptions = this.options.transport || {};

            if ((this.options.type || "xmla").toLowerCase() === "xmla") {
                this._online = true;
                this.transport = new XmlaTransportV2(transportOptions);
            } else {
                this.transport = new PivotTransport(this.options.transport || {}, this.transport);
            }

            this._columns = normalizeMembers(this.options.columns);
            this._rows = normalizeMembers(this.options.rows);

            var measures = this.cubeSchema ? this.cubeSchema.measures() : this.options.measures || [];

            if (toString.call(measures) === "[object Object]") {
                this._measuresAxis = measures.axis || "columns";
                measures = measures.values || [];
            }

            this._measures = normalizeMeasures(measures);
        },

        options: {
            serverSorting: true,
            serverPaging: true,
            serverFiltering: true,
            serverGrouping: true,
            serverAggregates: true
        },

        axes: function() {
            return {
                columns: normalizeAxis(this.columns()),
                rows: normalizeAxis(this.rows())
            };
        },

        catalog: function(val) {
            if (val === undefined$1) {
                return this.transport.catalog();
            }

            this.transport.catalog(val);
            this._mergeState({});// clears current state
            this.read();
        },

        cube: function(val) {
            if (val === undefined$1) {
                return this.transport.cube();
            }

            this.transport.cube(val);
            this._mergeState({});// clears current state
            this.read();
        },

        measuresAxis: function() {
            return this._measuresAxis || "columns";
        },

        fetch: function(callback) {
            var that = this;
            if (this._data === undefined$1 || this._data.length === 0) {
                var fn = function() {
                    if (isFunction(callback)) {
                        callback.call(that);
                    }
                };

                return this._query().done(fn);
            }
        },

        _createSettings: function(axes) {
            var settings = [];
            var key;
            var dimensions = this.cubeSchema.dimensionsSettings();
            var displayValueFunc = function(item) { return item[this.key]; };
            var sortValueFunc = function(value) { return value; };
            for (var i = 0; i < axes.length; i++) {
                key = axes[i].name[0];
                settings.push({
                    key: key,
                    displayValue: displayValueFunc.bind({ key: key }),
                    sortValue: sortValueFunc,
                    caption: (dimensions[key] || {}).caption || key
                });
            }
            return settings;
        },

        _cubeSchema: function(cube) {
            return {
                dimensionsSettings: function() {
                    return cube.dimensions;
                },
                dimensions: function() {
                    var result = [];
                    var dimensions = cube.dimensions;

                    for (var key in dimensions) {
                        result.push({
                            name: key,
                            caption: dimensions[key].caption || key,
                            uniqueName: key,
                            defaultHierarchy: key,
                            type: 1
                        });
                    }

                    if (cube.measures) {
                        result.push({
                            name: MEASURES,
                            caption: MEASURES,
                            uniqueName: MEASURES,
                            type: 2
                        });
                    }

                    return result;
                },
                restoreMeasure: function(measures, measure) {
                    for (var i = 0; i < measures.length; i++) {
                        if (!measures[i].aggregate) {
                            measures[i].aggregate = measure.aggregate;
                            measures[i].value = measure.value;
                            measures[i].caption = measure.caption;
                            measures[i].uniqueName = measure.uniqueName;
                            measures[i].type = 2;
                        }
                    }
                },
                measures: function() {
                    var result = [];
                    var measures = cube.measures;

                    for (var key in measures) {
                        result.push(createLocalMeasure(measures[key].field, key, measures[key].format, measures[key].aggregate));
                    }

                    return result;
                },
                memberType: function(name) {
                    var getter = kendo.getter(normalizeName(name), true);
                    var data = this.options.data || this._pristineData || [];
                    if (!data.length) {
                        return null;
                    }

                    return typeof getter(data[0]);
                }.bind(this),
                members: function(name) {
                    var data = this.options.data || this._pristineData || [];
                    var result = [];
                    var distinct = {};
                    var getter;
                    var value;
                    var idx = 0;

                    if (name.indexOf("[(ALL)]") !== -1) {
                        return [
                            {
                                caption: cube.dimensions[name.split(".")[0]].caption || name,
                                levelUniqueName: name,
                                name: name,
                                childrenCardinality: 1,
                                uniqueName: name
                            }
                        ];
                    }

                    getter = kendo.getter(normalizeName(name), true);

                    for (; idx < data.length; idx++) {
                        value = getter(data[idx]);
                        if ((value || value === 0 || value === false) && !distinct[value]) {
                            distinct[value] = true;

                            result.push({
                                caption: value + "",
                                name: value + "",
                                childrenCardinality: 0,
                                uniqueName: value
                            });
                        }
                    }

                    return result;
                }.bind(this)
            };
        },

        read: function(data) {
            const that = this;
            const isPrevented = that.trigger(REQUESTSTART, { type: READ });
            const params = that._params(data);
            const deferred = $.Deferred();
            if (!isPrevented) {
                that.trigger(PROGRESS);

                if (that.options.data) {
                    loadLocalData.call(that, that.options.data, params, deferred);
                } else if ((this.options.type || "xmla").toLowerCase() === "xmla") {
                    that.transport.read({
                        data: params,
                        success: function(newDataState) {
                            that._saveState(newDataState);
                            that.trigger(REQUESTEND, { response: newDataState, type: READ });
                            that.trigger(CHANGE);
                            if (that._preventRefresh) {
                                that._preventRefresh = false;
                            }
                            deferred.resolve();
                        },
                        error: function(err) {
                            that.trigger(ERROR, { error: err });
                        }
                    });
                } else {
                    that.transport.read({
                        success: function(data) {
                            loadLocalData.call(that, data, params, deferred);
                        },
                        error: function(err) {
                            that.trigger(ERROR, { error: err });
                        }
                    });
                }
            }
            return deferred.promise();
        },

        _params: function(data) {
            var that = this;
            var options = DataSource.fn._params.call(that, data);

            options = extend({
                columnAxes: JSON.parse(JSON.stringify(that._columns)),
                rowAxes: JSON.parse(JSON.stringify(that._rows)),
                measuresAxis: that.measuresAxis(),
                measureAxes: that._measures
            }, options);

            if ((this.options.type || "").toLowerCase() === "xmla") {
                options.connection = that.options.transport.connection;
            }

            if (options.filter) {
                options.filter = normalizeFilter(options.filter);
                options.filter = (options.filter || {}).filters;
            }

            if (options.sort) {
                options.sort = normalizeSort(options.sort);
            }

            return options;
        },

        discover: function(options) {
            const that = this;
            const transport = that.transport;
            const isOdata = that.options.type === "odata";

            const converters = {
                "schemaMeasures": that.reader.measures,
                "schemaKPIs": that.reader.kpis,
                "schemaDimensions": that.reader.dimensions,
                "schemaHierarchies": that.reader.hierarchies,
                "schemaLevels": that.reader.levels,
                "schemaCubes": that.reader.cubes,
                "schemaCatalogs": that.reader.catalogs,
                "schemaMembers": that.reader.members
            };

            if (transport.discover && !isOdata) {
                return transport.discover(options);
            }

            return $.Deferred(function(deferred) {
                transport.discover(extend({
                    success: function(response) {
                       response = that.reader.parse(response);

                        if (that._handleCustomErrors(response)) {
                            return;
                        }

                        if (converters[options.command]) {
                            response = converters[options.command](response);
                        }
                        deferred.resolve(response);
                    },
                    error: function(response, status, error) {
                        deferred.reject(response);
                        that.error(response, status, error);
                    }
                }, options));
            }).promise().done(function() {
                that.trigger("schemaChange");
            });
        },

        schemaMeasures: function() {
            const that = this;
            return that.discover(
                {
                    command: "schemaMeasures",
                    restrictions: {
                        catalogName: that.transport.catalog(),
                        cubeName: that.transport.cube()
                    }
                });
        },

        schemaKPIs: function() {
            const that = this;
            return that.discover(
                {
                    command: "schemaKPIs",
                    restrictions: {
                        catalogName: that.transport.catalog(),
                        cubeName: that.transport.cube()
                    }
                });
            },

        schemaDimensions: function() {
            const that = this;
            return that.discover(
                {
                    command: "schemaDimensions",
                    restrictions: {
                        catalogName: that.transport.catalog(),
                        cubeName: that.transport.cube()
                    }
                });
            },

        schemaHierarchies: function(dimensionName) {
            const that = this;
            return that.discover({
                command: "schemaHierarchies",
                restrictions: {
                    catalogName: that.transport.catalog(),
                    cubeName: that.transport.cube(),
                    dimensionUniqueName: dimensionName
                }
             });
         },

        schemaLevels: function(hierarchyName) {
            const that = this;
            return that.discover({
                command: "schemaLevels",
                restrictions: {
                    catalogName: that.transport.catalog(),
                    cubeName: that.transport.cube(),
                    hierarchyUniqueName: hierarchyName
                }
            });
        },

        schemaCubes: function() {
            const that = this;
            return that.discover({
                command: "schemaCubes",
                restrictions: {
                    catalogName: that.transport.catalog()
                }
            });
        },


        schemaCatalogs: function() {
            const that = this;
            return that.discover({
                command: "schemaCatalogs"
            });
        },


        schemaMembers: function(restrictions) {
            const that = this;
            return that.discover({
                command: "schemaMembers",
                restrictions: extend({
                   catalogName: that.transport.catalog(),
                   cubeName: that.transport.cube()
                }, restrictions)
            });
        },

        _saveState: function(state) {
            var that = this;

            that._columnTuples = state.columns;
            that._rowTuples = state.rows;
            that._view = that._data = state.data;
        },

        columns: function(val) {
            if (val === undefined$1) {
                return this._columns;
            }

            this._columns = normalizeMembers(val);
            this.read();
        },

        rows: function(val) {
            if (val === undefined$1) {
                return this._rows;
            }

            this._rows = normalizeMembers(val);

            this.read();
        },

        measures: function(val) {
            if (val === undefined$1) {
                return this._measures;
            }

            this._measures = normalizeMeasures(val);

            this.read();
        },

        _mergeState: function(options) {
            options = DataSource.fn._mergeState.call(this, options);

            return options;
        },

        _query: function(options) {
            var that = this;
            var params = extend({}, {
                sort: that.sort(),
                measuresAxis: that.measuresAxis(),
                filter: that.filter()
            }, options);
            this._mergeState(params);

            return this.read();
        },
    });

    var PivotDataSource = DataSource.extend({
        init: function(options) {
            var cube = ((options || {}).schema || {}).cube;
            var measuresAxis = "columns";
            var measures;

            var schema = {
                axes: identity,
                cubes: identity,
                catalogs: identity,
                measures: identity,
                dimensions: identity,
                hierarchies: identity,
                levels: identity,
                members: identity
            };

            if (cube) {
                schema = $.extend(schema, this._cubeSchema(cube));
                this.cubeBuilder = new PivotCubeBuilder(cube);
            }

            DataSource.fn.init.call(this, extend(true, {}, {
                schema: schema
            }, options));

            this.transport = new PivotTransport(this.options.transport || {}, this.transport);

            this._columns = normalizeMembers(this.options.columns);
            this._rows = normalizeMembers(this.options.rows);

            measures = this.options.measures || [];

            if (toString.call(measures) === "[object Object]") {
                measuresAxis = measures.axis || "columns";
                measures = measures.values || [];
            }

            this._measures = normalizeMeasures(measures);
            this._measuresAxis = measuresAxis;

            this._skipNormalize = 0;
            this._axes = {};
        },

        _cubeSchema: function(cube) {
            return {
                dimensions: function() {
                    var result = [];
                    var dimensions = cube.dimensions;

                    for (var key in dimensions) {
                        result.push({
                            name: key,
                            caption: dimensions[key].caption || key,
                            uniqueName: key,
                            defaultHierarchy: key,
                            type: 1
                        });
                    }

                    if (cube.measures) {
                        result.push({
                            name: MEASURES,
                            caption: MEASURES,
                            uniqueName: MEASURES,
                            type: 2
                        });
                    }

                    return result;
                },
                hierarchies: function() {
                    return [];
                },
                measures: function() {
                    var result = [];
                    var measures = cube.measures;

                    for (var key in measures) {
                        result.push({
                            name: key,
                            caption: key,
                            uniqueName: key,
                            aggregator: key
                        });
                    }

                    return result;
                },
                members: function(response, restrictions) {
                    var name = restrictions.levelUniqueName || restrictions.memberUniqueName;
                    var schemaData = this.options.schema.data;
                    var dataGetter = isFunction(schemaData) ? schemaData : kendo.getter(schemaData, true);
                    var data = (this.options.data && dataGetter(this.options.data)) || this._rawData || [];
                    var result = [];
                    var getter;
                    var value;
                    var idx = 0;
                    var distinct = {};

                    if (name) {
                        name = name.split(".")[0];
                    }

                    if (!restrictions.treeOp) {
                        result.push({
                            caption: cube.dimensions[name].caption || name,
                            childrenCardinality: "1",
                            dimensionUniqueName: name,
                            hierarchyUniqueName: name,
                            levelUniqueName: name,
                            name: name,
                            uniqueName: name
                        });

                        return result;
                    }

                    getter = kendo.getter(normalizeName(name), true);

                    for (; idx < data.length; idx++) {
                        value = getter(data[idx]);
                        if ((value || value === 0) && !distinct[value]) {
                            distinct[value] = true;

                            result.push({
                                caption: value,
                                childrenCardinality: "0",
                                dimensionUniqueName: name,
                                hierarchyUniqueName: name,
                                levelUniqueName: name,
                                name: value,
                                uniqueName: value
                            });
                        }
                    }

                    return result;
                }.bind(this)
            };
        },

        options: {
            serverSorting: true,
            serverPaging: true,
            serverFiltering: true,
            serverGrouping: true,
            serverAggregates: true
        },

        catalog: function(val) {
            if (val === undefined$1) {
                return this.transport.catalog();
            }

            this.transport.catalog(val);
            this._mergeState({});// clears current state
            this._axes = {};
            this.data([]);
        },

        cube: function(val) {
            if (val === undefined$1) {
                return this.transport.cube();
            }

            this.transport.cube(val);
            this._axes = {};
            this._mergeState({});// clears current state
            this.data([]);
        },

        axes: function() {
            return this._axes;
        },

        columns: function(val) {
            if (val === undefined$1) {
                return this._columns;
            }

            this._skipNormalize += 1;
            this._clearAxesData = true;

            this._columns = normalizeMembers(val);
            this.query({
                columns: val,
                rows: this.rowsAxisDescriptors(),
                measures: this.measures(),
                sort: this.sort(),
                filter: this.filter()
            });
        },

        rows: function(val) {
            if (val === undefined$1) {
                return this._rows;
            }

            this._skipNormalize += 1;
            this._clearAxesData = true;

            this._rows = normalizeMembers(val);

            this.query({
                columns: this.columnsAxisDescriptors(),
                rows: val,
                measures: this.measures(),
                sort: this.sort(),
                filter: this.filter()
            });
        },

        measures: function(val) {
            if (val === undefined$1) {
                return this._measures;
            }

            this._skipNormalize += 1;
            this._clearAxesData = true;

            this.query({
                columns: this.columnsAxisDescriptors(),
                rows: this.rowsAxisDescriptors(),
                measures: normalizeMeasures(val),
                sort: this.sort(),
                filter: this.filter()
            });
        },

        measuresAxis: function() {
            return this._measuresAxis || "columns";
        },

        _expandPath: function(path, axis) {
            var origin = axis === "columns" ? "columns" : "rows";
            var other = axis === "columns" ? "rows" : "columns";

            var members = normalizeMembers(path);
            var memberToExpand = getName(members[members.length - 1]);

            this._lastExpanded = origin;

            members = descriptorsForMembers(this.axes()[origin], members, this.measures());

            for (var idx = 0; idx < members.length; idx++) {
                var memberName = getName(members[idx]);

                if (memberName === memberToExpand) {
                    if (members[idx].expand) {
                        return;
                    }
                    members[idx].expand = true;
                } else {
                    members[idx].expand = false;
                }
            }

            var descriptors = {};
            descriptors[origin] = members;
            descriptors[other] = this._descriptorsForAxis(other);

            this._query(descriptors);
        },

        _descriptorsForAxis: function(axis) {
            var axes = this.axes();
            var descriptors = this[axis]() || [];

            if (axes && axes[axis] && axes[axis].tuples && axes[axis].tuples[0]) {
                descriptors = descriptorsForAxes(axes[axis].tuples || []);
            }
            return descriptors;
        },

        columnsAxisDescriptors: function() {
            return this._descriptorsForAxis("columns");
        },

        rowsAxisDescriptors: function() {
            return this._descriptorsForAxis("rows");
        },

        _process: function(data, e) {
            this._view = data;

            e = e || {};
            e.items = e.items || this._view;

            this.trigger(CHANGE, e);
        },

        _query: function(options) {
            var that = this;

            if (!options) {
                this._skipNormalize += 1;
                this._clearAxesData = true;
            }

            return that.query(extend({}, {
                page: that.page(),
                pageSize: that.pageSize(),
                sort: that.sort(),
                filter: that.filter(),
                group: that.group(),
                aggregate: that.aggregate(),
                columns: this.columnsAxisDescriptors(),
                rows: this.rowsAxisDescriptors(),
                measures: this.measures()
            }, options));
        },

        query: function(options) {
            var state = this._mergeState(options);

            if (this._data.length && this.cubeBuilder) {
                this._params(state);
                this._updateLocalData(this._pristineData);

                return $.Deferred().resolve().promise();
            }

            return this.read(state);
        },

        _mergeState: function(options) {
            options = DataSource.fn._mergeState.call(this, options);

            if (options !== undefined$1) {
                this._measures = normalizeMeasures(options.measures);

                if (options.columns) {
                    options.columns = normalizeMembers(options.columns);
                } else if (!options.columns) {
                    this._columns = [];
                }

                if (options.rows) {
                    options.rows = normalizeMembers(options.rows);
                } else if (!options.rows) {
                    this._rows = [];
                }
            }
            return options;
        },

        filter: function(val) {
            if (val === undefined$1) {
                return this._filter;
            }

            this._skipNormalize += 1;
            this._clearAxesData = true;
            this._query({ filter: val, page: 1 });
        },

        expandColumn: function(path) {
            this._expandPath(path, "columns");
        },

        expandRow: function(path) {
            this._expandPath(path, "rows");
        },

        success: function(data) {
            var originalData;
            if (this.cubeBuilder) {
                originalData = (this.reader.data(data) || []).slice(0);
            }
            DataSource.fn.success.call(this, data);
            if (originalData) {
                this._pristineData = originalData;
            }
        },

        _processResult: function(data, axes) {
            if (this.cubeBuilder) {
                var processedData = this.cubeBuilder.process(data, this._requestData);

                data = processedData.data;
                axes = processedData.axes;
            }

            var columnIndexes, rowIndexes;
            var tuples, resultAxis, measures, axisToSkip;
            var columnDescriptors = this.columns();
            var rowDescriptors = this.rows();
            var hasColumnTuples = axes.columns && axes.columns.tuples;

            if (!columnDescriptors.length && rowDescriptors.length && hasColumnTuples && (this._rowMeasures().length || !this.measures().length)) {
                axes = {
                    columns: {},
                    rows: axes.columns
                };
            }

            if (!columnDescriptors.length && !rowDescriptors.length && this.measuresAxis() === "rows" && hasColumnTuples) {
                axes = {
                    columns: {},
                    rows: axes.columns
                };
            }

            this._axes = {
                columns: normalizeAxis(this._axes.columns),
                rows: normalizeAxis(this._axes.rows)
            };

            axes = {
                columns: normalizeAxis(axes.columns),
                rows: normalizeAxis(axes.rows)
            };

            columnIndexes = this._normalizeTuples(axes.columns.tuples, this._axes.columns.tuples, columnDescriptors, this._columnMeasures());
            rowIndexes = this._normalizeTuples(axes.rows.tuples, this._axes.rows.tuples, rowDescriptors, this._rowMeasures());

            if (this._skipNormalize > 0) {
                this._skipNormalize -= 1;
            }

            if (!this.cubeBuilder) {
                data = this._normalizeData({
                    columnsLength: axes.columns.tuples.length,
                    rowsLength: axes.rows.tuples.length,
                    columnIndexes: columnIndexes,
                    rowIndexes: rowIndexes,
                    data: data
                });
            }

            if (this._lastExpanded == "rows") {
                tuples = axes.columns.tuples;
                measures = this._columnMeasures();
                resultAxis = validateAxis(axes.columns, this._axes.columns, measures);

                if (resultAxis) {
                    axisToSkip = "columns";
                    axes.columns = resultAxis;
                    adjustDataByColumn(tuples, resultAxis.tuples, axes.rows.tuples.length, measures, data);
                    if (!this.cubeBuilder) {
                        data = this._normalizeData({
                            columnsLength: membersCount(axes.columns.tuples, measures),
                            rowsLength: axes.rows.tuples.length,
                            data: data
                        });
                    }
                }
            } else if (this._lastExpanded == "columns") {
                tuples = axes.rows.tuples;
                measures = this._rowMeasures();
                resultAxis = validateAxis(axes.rows, this._axes.rows, measures);

                if (resultAxis) {
                    axisToSkip = "rows";
                    axes.rows = resultAxis;
                    adjustDataByRow(tuples, resultAxis.tuples, axes.columns.tuples.length, measures, data);

                    if (!this.cubeBuilder) {
                        data = this._normalizeData({
                            columnsLength: membersCount(axes.rows.tuples, measures),
                            rowsLength: axes.columns.tuples.length,
                            data: data
                        });
                    }
                }
            }

            this._lastExpanded = null;

            var result = this._mergeAxes(axes, data, axisToSkip);
            this._axes = result.axes;

            return result.data;
        },

        _readData: function(data) {
            var axes = this.reader.axes(data);
            var newData = this.reader.data(data);

            if (this.cubeBuilder) {
                this._rawData = newData;
            }

            return this._processResult(newData, axes);
        },

        _createTuple: function(tuple, measure, buildRoot) {
            var members = tuple.members;
            var length = members.length;
            var root = { members: [] };
            var levelName, levelNum;
            var name, parentName;
            var hasChildren;
            var hierarchy;
            var caption;
            var member;
            var idx = 0;

            if (measure) {
                length -= 1;
            }

            for (; idx < length; idx++) {
                member = members[idx];
                levelNum = Number(member.levelNum);

                name = member.name;
                parentName = member.parentName;
                caption = member.caption || name;
                hasChildren = member.hasChildren;
                hierarchy = member.hierarchy;
                levelName = member.levelName;

                if (buildRoot) {
                    caption = "All";
                    if (levelNum === 0) {
                        parentName = member.name;
                    } else {
                        levelNum -= 1;
                    }

                    hasChildren = true;
                    name = hierarchy = levelName = parentName;
                }

                root.members.push({
                    name: name,
                    children: [],
                    caption: caption,
                    levelName: levelName,
                    levelNum: levelNum.toString(),
                    hasChildren: hasChildren,
                    hierarchy: hierarchy,
                    parentName: !buildRoot ? parentName : ""
                });
            }

            if (measure) {
                root.members.push({
                    name: measure.name,
                    children: []
                });
            }

            return root;
        },

        _hasRoot: function(target, source, descriptors) {
            if (source.length) {
                return findExistingTuple(source, target).tuple;
            }

            var members = target.members;
            var member;
            var descriptor;

            var isRoot = true;
            var levelNum;

            for (var idx = 0, length = members.length; idx < length; idx++) {
                member = members[idx];
                levelNum = Number(member.levelNum) || 0;
                descriptor = descriptors[idx];

                if (!(levelNum === 0 || (descriptor && member.name === getName(descriptor)))) {
                    isRoot = false;
                    break;
                }
            }

            return isRoot;
        },

        _mergeAxes: function(sourceAxes, data, axisToSkip) {
            var columnMeasures = this._columnMeasures();
            var rowMeasures = this._rowMeasures();
            var axes = this.axes();
            var startIndex, tuples;

            var oldRowsLength = membersCount(axes.rows.tuples, rowMeasures);
            var newRowsLength = sourceAxes.rows.tuples.length;

            var oldColumnsLength = membersCount(axes.columns.tuples, columnMeasures);
            var newColumnsLength = sourceAxes.columns.tuples.length;

            if (axisToSkip == "columns") {
                newColumnsLength = oldColumnsLength;
                tuples = sourceAxes.columns.tuples;
            } else {
                tuples = parseSource(sourceAxes.columns.tuples, columnMeasures);
                data = prepareDataOnColumns(tuples, data);
            }

            var mergedColumns = mergeTuples(axes.columns.tuples, tuples, columnMeasures);

            if (axisToSkip == "rows") {
                newRowsLength = membersCount(sourceAxes.rows.tuples, rowMeasures);
                tuples = sourceAxes.rows.tuples;
            } else {
                tuples = parseSource(sourceAxes.rows.tuples, rowMeasures);
                data = prepareDataOnRows(tuples, data);
            }
            var mergedRows = mergeTuples(axes.rows.tuples, tuples, rowMeasures);

            axes.columns.tuples = mergedColumns.tuples;
            axes.rows.tuples = mergedRows.tuples;

            if (oldColumnsLength !== membersCount(axes.columns.tuples, columnMeasures)) {
                //columns are expanded
                startIndex = mergedColumns.index + findDataIndex(mergedColumns.parsedRoot, mergedColumns.memberIndex, columnMeasures);
                var offset = oldColumnsLength + newColumnsLength;
                data = this._mergeColumnData(data, startIndex, newRowsLength, newColumnsLength, offset);
            } else if (oldRowsLength !== membersCount(axes.rows.tuples, rowMeasures)) {
                //rows are expanded
                startIndex = mergedRows.index + findDataIndex(mergedRows.parsedRoot, mergedRows.memberIndex, rowMeasures);
                data = this._mergeRowData(data, startIndex, newRowsLength, newColumnsLength);
            }

            if (axes.columns.tuples.length === 0 && axes.rows.tuples.length === 0) {
                data = [];
            }

            return {
                axes: axes,
                data: data
            };
        },

        _mergeColumnData: function(newData, columnIndex, rowsLength, columnsLength, offset) {
            var data = this.data().toJSON();
            var rowIndex, index, drop = 0, toAdd;
            var columnMeasures = Math.max(this._columnMeasures().length, 1);

            rowsLength = Math.max(rowsLength, 1);

            if (data.length > 0) {
                //if there is already data, drop the first new data item
                drop = columnMeasures;
                offset -= columnMeasures;
            }

            for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) {
                index = columnIndex + (rowIndex * offset);
                toAdd = newData.splice(0, columnsLength);
                toAdd.splice(0, drop);
                [].splice.apply(data, [index, 0].concat(toAdd));
            }

            return data;
        },

        _mergeRowData: function(newData, rowIndex, rowsLength, columnsLength) {
            var data = this.data().toJSON();
            var idx, dataIndex, toAdd;
            var rowMeasures = Math.max(this._rowMeasures().length, 1);

            columnsLength = Math.max(columnsLength, 1);
            if (data.length > 0) {
                //if there is already data, drop the first new data item
                rowsLength -= rowMeasures;
                newData.splice(0, columnsLength * rowMeasures);
            }

            for (idx = 0; idx < rowsLength; idx++) {
                toAdd = newData.splice(0, columnsLength);
                dataIndex = (rowIndex * columnsLength) + (idx * columnsLength);
                [].splice.apply(data, [dataIndex, 0].concat(toAdd));
            }

            return data;
        },

        _columnMeasures: function() {
            var measures = this.measures();
            var columnMeasures = [];

            if (this.measuresAxis() === "columns") {
                if (this.columns().length === 0) {
                    columnMeasures = measures;
                } else if (measures.length > 1) {
                    columnMeasures = measures;
                }
            }

            return columnMeasures;
        },

        _rowMeasures: function() {
            var measures = this.measures();
            var rowMeasures = [];

            if (this.measuresAxis() === "rows") {
                if (this.rows().length === 0) {
                    rowMeasures = measures;
                } else if (measures.length > 1) {
                    rowMeasures = measures;
                }
            }

            return rowMeasures;
        },

        _updateLocalData: function(data, state) {
            if (this.cubeBuilder) {
                if (state) {
                    this._requestData = state;
                }
                data = this._processResult(data);
            }

            this._data = this._observe(data);

            this._ranges = [];
            this._addRange(this._data);

            this._total = this._data.length;
            this._pristineTotal = this._total;
            this._process(this._data);
        },

        data: function(value) {
            var that = this;
            if (value !== undefined$1) {
                this._pristineData = value.slice(0);
                this._updateLocalData(value, {
                        columns: this.columns(),
                        rows: this.rows(),
                        measures: this.measures()
                    });
            } else {
                return that._data;
            }
        },

        _normalizeTuples: function(tuples, source, descriptors, measures) {
            var length = measures.length || 1;
            var idx = 0;

            var roots = [];
            var indexes = {};
            var measureIdx = 0;
            var tuple, memberIdx, last;

            if (!tuples.length) {
                return;
            }

            if (this._skipNormalize <= 0 && !this._hasRoot(tuples[0], source, descriptors)) {
                this._skipNormalize = 0;
                for (; idx < length; idx++) {
                    roots.push(this._createTuple(tuples[0], measures[idx], true));
                    indexes[idx] = idx;
                }

                tuples.splice.apply(tuples, [0, tuples.length].concat(roots).concat(tuples));
                idx = length;
            }

            if (measures.length) {
                last = tuple = tuples[idx];
                memberIdx = tuple.members.length - 1;

                while (tuple) {
                    if (measureIdx >= length) {
                        measureIdx = 0;
                    }

                    if (tuple.members[memberIdx].name !== measures[measureIdx].name) {
                        tuples.splice(idx, 0, this._createTuple(tuple, measures[measureIdx]));
                        indexes[idx] = idx;
                    }

                    idx += 1;
                    measureIdx += 1;
                    tuple = tuples[idx];

                    if (length > measureIdx && (!tuple || tupleName(last, memberIdx - 1) !== tupleName(tuple, memberIdx - 1))) {
                        for (; measureIdx < length; measureIdx++) {
                            tuples.splice(idx, 0, this._createTuple(last, measures[measureIdx]));
                            indexes[idx] = idx;
                            idx += 1;
                        }
                        tuple = tuples[idx];
                    }
                    last = tuple;
                }
            }

            return indexes;
        },

        _addMissingDataItems: function(result, metadata) {
            while (metadata.rowIndexes[parseInt(result.length / metadata.columnsLength, 10)] !== undefined$1) {
                for (var idx = 0; idx < metadata.columnsLength; idx++) {
                    result = addEmptyDataItem(result);
                }
            }

            while (metadata.columnIndexes[result.length % metadata.columnsLength] !== undefined$1) {
                result = addEmptyDataItem(result);
            }

            return result;
        },

        _normalizeOrdinals: function(result, dataItem, metadata) {
            var lastOrdinal = metadata.lastOrdinal;

            if (!dataItem) {
                return addEmptyDataItem(result);
            }

            if ((dataItem.ordinal - lastOrdinal) > 1) {
                lastOrdinal += 1;

                while (lastOrdinal < dataItem.ordinal && result.length < metadata.length) {
                    result = this._addMissingDataItems(addEmptyDataItem(result), metadata);
                    lastOrdinal += 1;
                }
            }

            dataItem.ordinal = result.length;
            result[result.length] = dataItem;

            return result;
        },

        _normalizeData: function(options) {
            var data = options.data;
            var dataIdx = 0;
            var dataItem;
            var result = [];
            var lastOrdinal;
            var length;

            options.lastOrdinal = 0;
            options.columnIndexes = options.columnIndexes || {};
            options.rowIndexes = options.rowIndexes || {};
            options.columnsLength = options.columnsLength || 1;
            options.rowsLength = options.rowsLength || 1;
            options.length = options.columnsLength * options.rowsLength;
            length = options.length;

            if (data.length === length) {
                return data;
            }

            while (result.length < length) {
                dataItem = data[dataIdx++];
                if (dataItem) {
                    lastOrdinal = dataItem.ordinal;
                }

                result = this._normalizeOrdinals(this._addMissingDataItems(result, options), dataItem, options);

                options.lastOrdinal = lastOrdinal;
            }

            return result;
        },

        discover: function(options, converter) {
            var that = this,
                transport = that.transport;

            return $.Deferred(function(deferred) {
                transport.discover(extend({
                    success: function(response) {
                       response = that.reader.parse(response);

                        if (that._handleCustomErrors(response)) {
                            return;
                        }

                        if (converter) {
                            response = converter(response);
                        }
                        deferred.resolve(response);
                    },
                    error: function(response, status, error) {
                        deferred.reject(response);
                        that.error(response, status, error);
                    }
                }, options));
            }).promise().done(function() {
                that.trigger("schemaChange");
            });
        },

        schemaMeasures: function() {
            var that = this;

            return that.discover({
                data: {
                    command: "schemaMeasures",
                    restrictions: {
                        catalogName: that.transport.catalog(),
                        cubeName: that.transport.cube()
                    }
                }
            }, function(response) {
                return that.reader.measures(response);
            });
        },

        schemaKPIs: function() {
            var that = this;

            return that.discover({
                data: {
                    command: "schemaKPIs",
                    restrictions: {
                        catalogName: that.transport.catalog(),
                        cubeName: that.transport.cube()
                    }
                }
            }, function(response) {
                return that.reader.kpis(response);
            });
        },

        schemaDimensions: function() {
            var that = this;

            return that.discover({
                data: {
                    command: "schemaDimensions",
                    restrictions: {
                        catalogName: that.transport.catalog(),
                        cubeName: that.transport.cube()
                    }
                }
            }, function(response) {
                return that.reader.dimensions(response);
            });
        },

        schemaHierarchies: function(dimensionName) {
            var that = this;

            return that.discover({
                data: {
                    command: "schemaHierarchies",
                    restrictions: {
                        catalogName: that.transport.catalog(),
                        cubeName: that.transport.cube(),
                        dimensionUniqueName: dimensionName
                    }
                }
            }, function(response) {
                return that.reader.hierarchies(response);
            });
        },

        schemaLevels: function(hierarchyName) {
            var that = this;

            return that.discover({
                data: {
                    command: "schemaLevels",
                    restrictions: {
                        catalogName: that.transport.catalog(),
                        cubeName: that.transport.cube(),
                        hierarchyUniqueName: hierarchyName
                    }
                }
            }, function(response) {
                return that.reader.levels(response);
            });
        },

        schemaCubes: function() {
            var that = this;

            return that.discover({
                data: {
                    command: "schemaCubes",
                    restrictions: {
                        catalogName: that.transport.catalog()
                    }
                }
            }, function(response) {
                return that.reader.cubes(response);
            });
        },

        schemaCatalogs: function() {
            var that = this;

            return that.discover({
                data: {
                    command: "schemaCatalogs"
                }
            }, function(response) {
                return that.reader.catalogs(response);
            });
        },

        schemaMembers: function(restrictions) {
            var that = this;
            var success = (function(restrictions) {
                return function(response) {
                    return that.reader.members(response, restrictions);
                };
            }(restrictions));

            return that.discover({
                data: {
                    command: "schemaMembers",
                    restrictions: extend({
                       catalogName: that.transport.catalog(),
                       cubeName: that.transport.cube()
                   }, restrictions)
                }
            }, success);
        },

        _params: function(data) {
            if (this._clearAxesData) {
                this._axes = {};
                this._data = this._observe([]);
                this._clearAxesData = false;
                this.trigger(STATERESET);
            }

            var options = DataSource.fn._params.call(this, data);

            options = extend({
                measures: this.measures(),
                measuresAxis: this.measuresAxis(),
                columns: this.columns(),
                rows: this.rows()
            }, options);

            if (this.cubeBuilder) {
                this._requestData = options;
            }

            return options;
        }
    });

    function flatColumns(columns) {
        var result = [];
        for (var idx = 0; idx < columns.length; idx++) {
            result.push(columns[idx]);
            if (columns[idx].children) {
                result = result.concat(flatColumns(columns[idx].children));
            }
        }

        return result;
    }

    function sortItemsTree(field, items, sortFunction) {
        for (var i = 0; i < items.length; i++) {
            if (items[i].children && items[i].children.length) {
                sortItemsTree(field, items[i].children, sortFunction);
            }
        }
        if (items[0].parentName != field) {
            return;
        }
        items = items.sort(sortFunction);
    }

    function fillSortTree(items, map) {
        for (var i = 0; i < items.length; i++) {
            var currentItem = map[items[i].name];

            if (!$.isEmptyObject(currentItem.childrenMap)) {
                items[i].children = [];
                for (var name in currentItem.childrenMap) {
                    items[i].children.push($.extend({}, { name: name, parentName: map[name].parentName }));
                }

                fillSortTree(items[i].children, map);
            }
        }
    }

    function addEmptyDataItem(result) {
        result[result.length] = { value: "", fmtValue: "", ordinal: result.length };
        return result;
    }

    function validateAxis(newAxis, axis, measures) {
        if (newAxis.tuples.length < membersCount(axis.tuples, measures)) {

            return axis;
        }

        return;
    }

    function adjustDataByColumn(sourceTuples, targetTuples, rowsLength, measures, data) {
        var columnIdx, rowIdx, dataIdx;
        var columnsLength = sourceTuples.length;
        var targetColumnsLength = membersCount(targetTuples, measures);
        var measuresLength = measures.length || 1;

        for (rowIdx = 0; rowIdx < rowsLength; rowIdx++) {
            for (columnIdx = 0; columnIdx < columnsLength; columnIdx++) {
                dataIdx = tupleIndex(sourceTuples[columnIdx], targetTuples) * measuresLength;
                dataIdx += columnIdx % measuresLength;

                data[rowIdx * columnsLength + columnIdx].ordinal = rowIdx * targetColumnsLength + dataIdx;
            }
        }
    }

    function adjustDataByRow(sourceTuples, targetTuples, columnsLength, measures, data) {
        var columnIdx, rowIdx, dataIdx;
        var rowsLength = sourceTuples.length;
        var measuresLength = measures.length || 1;

        for (rowIdx = 0; rowIdx < rowsLength; rowIdx++) {
            dataIdx = tupleIndex(sourceTuples[rowIdx], targetTuples);
            dataIdx *= measuresLength;
            dataIdx += rowIdx % measuresLength;

            for (columnIdx = 0; columnIdx < columnsLength; columnIdx++) {
                data[rowIdx * columnsLength + columnIdx].ordinal = dataIdx * columnsLength + columnIdx;
            }
        }
    }

    function tupleIndex(tuple, collection) {
        return findExistingTuple(collection, tuple).index;
    }

    function membersCount(tuples, measures) {
        if (!tuples.length) {
            return 0;
        }

        var queue = tuples.slice();
        var current = queue.shift();
        var result = 1;

        while (current) {
            if (current.members) {
                [].push.apply(queue, current.members);
            } else if (current.children) {
                if (!current.measure) {
                    result += current.children.length;
                }
                [].push.apply(queue, current.children);
            }

            current = queue.shift();
        }

        if (measures.length) {
            result = result * measures.length;
        }

        return result;
    }

    function normalizeAxis(axis) {
        if (!axis) {
            axis = {
                tuples: []
            };
        }

        if (!axis.tuples) {
            axis.tuples = [];
        }

        return axis;
    }

    function findDataIndex(tuple, memberIndex, measures) {
        if (!tuple) {
            return 0;
        }

        var measuresLength = Math.max(measures.length, 1);
        var tuples = tuple.members.slice(0, memberIndex);
        var current = tuples.shift();

        //the initial value is equal to the total number of measures
        //as the measures member is not extracted from the members of the starting tuple
        //but should be calculated in the final result
        var counter = measuresLength;

        while (current) {
            if (current.name === MEASURES) {
                //subtract 1 as the measures member has been already counted as a single standard member
                //but we are interested in the total number of measures instead
                counter += (measuresLength - 1);
            } else if (current.children) {
                //is member
                [].push.apply(tuples, current.children);
            } else {
                //is tuple
                counter ++;
                [].push.apply(tuples, current.members);
            }

            current = tuples.shift();
        }

        return counter;
    }

    function mergeTuples(target, source, measures) {
        if (!source[0]) {
            return {
                parsedRoot: null,
                tuples: target,
                memberIndex: 0,
                index: 0
            };
        }

        var result = findExistingTuple(target, source[0]);

        if (!result.tuple) {
            return {
                parsedRoot: null,
                tuples: source,
                memberIndex: 0,
                index: 0
            };
        }

        var targetMembers = result.tuple.members;
        var sourceMembers = source[0].members;
        var memberIndex = -1;

        if (targetMembers.length !== sourceMembers.length) {
            return {
                parsedRoot: null,
                tuples: source,
                memberIndex: 0,
                index: 0
            };
        }

        for (var idx = 0, length = targetMembers.length; idx < length; idx++) {
            if (!targetMembers[idx].measure && sourceMembers[idx].children[0]) {
                if (memberIndex == -1 && sourceMembers[idx].children.length) {
                    memberIndex = idx;
                }

                targetMembers[idx].children = sourceMembers[idx].children;
            }
        }

        measures = Math.max(measures.length, 1);

        return {
            parsedRoot: result.tuple,
            index: result.index * measures,
            memberIndex: memberIndex,
            tuples: target
        };
    }

    function equalTuples(first, second) {
        var equal = true;
        var idx, length;

        first = first.members;
        second = second.members;

        for (idx = 0, length = first.length; idx < length; idx++) {
            if (first[idx].measure || second[idx].measure) {
                continue;
            }

            equal = equal && (getName(first[idx]) === getName(second[idx]));
        }

        return equal;
    }

    function findExistingTuple(tuples, toFind) {
        var idx, length, tuple, found, counter = 0;
        var memberIndex, membersLength, member;

        for (idx = 0, length = tuples.length; idx < length; idx++) {
            tuple = tuples[idx];
            if (equalTuples(tuple, toFind)) {
                return {
                    tuple: tuple,
                    index: counter
                };
            }

            counter ++;

            for (memberIndex = 0, membersLength = tuple.members.length; memberIndex < membersLength; memberIndex++) {
                member = tuple.members[memberIndex];
                if (member.measure) {
                    //counter += member.children.length;
                    continue;
                }
                found = findExistingTuple(member.children, toFind);
                counter += found.index;
                if (found.tuple) {
                    return {
                        tuple: found.tuple,
                        index: counter
                    };
                }
            }
        }

        return {
            index: counter
        };
    }

    function addMembers(members, map) {
        var member, i, len, path = "";
        for (i = 0, len = members.length; i < len; i++) {
            member = members[i];
            path += member.name;
            if (!map[path]) {
                map[path] = member;
            }
        }
    }


    function findParentMember(tuple, map) {
        var members = tuple.members;
        var i, len, member, path = "";
        var parentPath = "";
        var parentMember;

        for (i = 0, len = members.length; i < len; i++) {
            member = members[i];
            if (parentMember) {
                if (map[path + member.name]) {
                    path += member.name;
                    parentMember = map[path];
                    continue;
                } else if (map[path + member.parentName]) {
                    return map[path + member.parentName];
                } else if (map[parentPath + member.parentName]) {
                    return map[parentPath + member.parentName];
                } else {
                    return map[parentPath];
                }
            }

            path += member.name;
            parentMember = map[member.parentName];

            if (!parentMember) {
                parentMember = map[path];
                if (!parentMember) {
                    return null;
                }
            }

            if (parentMember) {
                parentPath += parentMember.name;
            }
        }

        return parentMember;
    }

    function measurePosition(tuple, measures) {
        if (measures.length === 0) {
            return -1;
        }

        var measure = measures[0];
        var members = tuple.members;
        for (var idx = 0, len = members.length; idx < len; idx ++) {
            if (members[idx].name == measure.name) {
                return idx;
            }
        }
    }

    function normalizeTupleMeasures(tuple, index) {
        if (index < 0) {
            return;
        }
        var member = {
            name: MEASURES,
            measure: true,
            children: [
                $.extend({ members: [], dataIndex: tuple.dataIndex }, tuple.members[index])
            ]
        };
        tuple.members.splice(index, 1, member);
        tuple.dataIndex = undefined$1;
    }

    function parseSource(tuples, measures) {
        if (tuples.length < 1) {
            return [];
        }
        var result = [];
        var map = { };
        var measureIndex = measurePosition(tuples[0], measures);

        for (var i = 0; i < tuples.length; i++) {
            var tuple = tuples[i];

            //keep the old data index of the tuple
            tuple.dataIndex = i;

            normalizeTupleMeasures(tuple, measureIndex);
            var parentMember = findParentMember(tuple, map);

            if (parentMember) {
                if (measureIndex < 0 || !parentMember.measure) {
                    parentMember.children.push(tuple);
                } else {
                    parentMember.children.push(tuple.members[measureIndex].children[0]);
                }
            } else {
                result.push(tuple);
            }

            addMembers(tuple.members, map);
        }

        return result;
    }

    function prepareDataOnRows(tuples, data) {
        if (!tuples || !tuples.length) {
            return data;
        }

        var result = [];
        var indices = buildDataIndices(tuples);
        var rowsLength = indices.length;
        var columnsLength = Math.max(data.length / rowsLength, 1);
        var rowIndex, columnIndex, targetIndex, sourceIndex;
        var calcIndex;

        for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) {
            targetIndex = columnsLength * rowIndex;
            sourceIndex = columnsLength * indices[rowIndex];
            for (columnIndex = 0; columnIndex < columnsLength; columnIndex++) {
                calcIndex = parseInt(sourceIndex + columnIndex, 10);
                result[parseInt(targetIndex + columnIndex, 10)] = data[calcIndex] || { value: "", fmtValue: "", ordinal: calcIndex };
            }
        }

        return result;
    }

    function prepareDataOnColumns(tuples, data) {
        if (!tuples || !tuples.length) {
            return data;
        }

        var result = [];
        var indices = buildDataIndices(tuples);
        var columnsLength = indices.length;
        var rowsLength = Math.max(data.length / columnsLength, 1);
        var columnIndex, rowIndex, dataIndex, calcIndex;

        for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) {
            dataIndex = columnsLength * rowIndex;
            for (columnIndex = 0; columnIndex < columnsLength; columnIndex++) {
                calcIndex = indices[columnIndex] + dataIndex;
                result[dataIndex + columnIndex] = data[calcIndex] || { value: "", fmtValue: "", ordinal: calcIndex };
            }
        }

        return result;
    }

    function buildDataIndices(tuples) {
        tuples = tuples.slice();
        var result = [];
        var tuple = tuples.shift();
        var idx, length, spliceIndex, children, member;

        while (tuple) {
            //required for multiple measures
            if (tuple.dataIndex !== undefined$1) {
                result.push(tuple.dataIndex);
            }

            spliceIndex = 0;
            for (idx = 0, length = tuple.members.length; idx < length; idx++) {
                member = tuple.members[idx];
                children = member.children;
                if (member.measure) {
                    [].splice.apply(tuples, [0, 0].concat(children));
                } else {
                    [].splice.apply(tuples, [spliceIndex, 0].concat(children));
                }
                spliceIndex += children.length;
            }

            tuple = tuples.shift();
        }

        return result;
    }

    PivotDataSourceV2.create = function(options) {
        options = options && options.push ? { data: options } : options;

        var dataSource = options || {},
            data = dataSource.data;

        dataSource.data = data;

        if (!(dataSource instanceof PivotDataSourceV2) && dataSource instanceof kendo.data.DataSource) {
            throw new Error("Incorrect DataSource type. Only PivotDataSource instances are supported");
        }

        return dataSource instanceof PivotDataSourceV2 ? dataSource : new PivotDataSourceV2(dataSource);
    };

    PivotDataSource.create = function(options) {
        options = options && options.push ? { data: options } : options;

        var dataSource = options || {},
            data = dataSource.data;

        dataSource.data = data;

        if (!(dataSource instanceof PivotDataSource) && dataSource instanceof kendo.data.DataSource) {
            throw new Error("Incorrect DataSource type. Only PivotDataSource instances are supported");
        }

        return dataSource instanceof PivotDataSource ? dataSource : new PivotDataSource(dataSource);
    };

    function baseHierarchyPath(memberName) {
        var parts = memberName.split(".");
        if (parts.length > 2) {
            return parts[0] + "." + parts[1];
        }
        return memberName;
    }

    function expandMemberDescriptor(names, sort) {
        var idx = names.length - 1;
        var name = names[idx];
        var sortDescriptor;

        sortDescriptor = sortDescriptorForMember(sort, name);

        if (sortDescriptor && sortDescriptor.dir) {
            name = "ORDER(" + name + ".Children," + sortDescriptor.field + ".CurrentMember.MEMBER_CAPTION," + sortDescriptor.dir + ")";
        } else {
            name += ".Children";
        }

        names[idx] = name;

        return names;
    }

    function sortDescriptorForMember(sort, member) {
        for (var idx = 0, length = sort.length; idx < length; idx++) {
            if (member.indexOf(sort[idx].field) === 0) {
                return sort[idx];
            }
        }
        return null;
    }

    function crossJoin(names) {
        var result = "CROSSJOIN({";
        var r;

        if (names.length > 2) {
            r = names.pop();
            result += crossJoin(names);
        } else {
            result += names.shift();
            r = names.pop();
        }

        result += "},{";
        result += r;
        result += "})";
        return result;
    }

    function crossJoinCommand(members, measures) {
        var tmp = members.slice(0);

        if (measures.length > 1) {
            tmp.push("{" + measureNames(measures).join(",") + "}");
        }

        return crossJoin(tmp);
    }

    function measureNames(measures) {
        var idx = 0;
        var length = measures.length;
        var result = [];
        var measure;

        for (; idx < length; idx++) {
            measure = measures[idx];
            result.push(measure.name !== undefined$1 ? measure.name : measure);
        }

        return result;
    }

    function indexOf(name, items) {
        var idx, length, index = -1;

        for (idx = 0, length = items.length; idx < length; idx++) {
            if (getName(items[idx]) === name) {
                index = idx;
                break;
            }
        }
        return index;
    }

    function getName(name) {
        name = name.name || name;

        if (toString.call(name) === "[object Array]") {
            name = name[name.length - 1];
        }

        return name;
    }

    function getRootNames(members) {
        var length = members.length;
        var names = [];
        var idx = 0;

        for (; idx < length; idx++) {
            names.push(members[idx].name[0]);
        }

        return names;
    }

    function mapNames(names, rootNames) {
        var name;
        var rootName;

        var j;
        var idx = 0;
        var length = names.length;
        var rootLength = rootNames.length;

        rootNames = rootNames.slice(0);

        for (; idx < length; idx++) {
            name = names[idx];

            for (j = 0; j < rootLength; j++) {
                rootName = baseHierarchyPath(rootNames[j]);

                if (name.indexOf(rootName) !== -1) {
                    rootNames[j] = name;
                    break;
                }
            }
        }

        return {
            names: rootNames,
            expandedIdx: j,
            uniquePath: rootNames.slice(0, j + 1).join("")
        };
    }

    function parseDescriptors(members) {
        var expanded = [];
        var child = [];
        var root = [];
        var member;

        var j, l;
        var idx = 0;
        var length = members.length;

        var name;
        var hierarchyName;

        var found;

        for (; idx < length; idx++) {
            member = members[idx];
            name = member.name;
            found = false;

            if (toString.call(name) !== "[object Array]") {
                member.name = name = [name];
            }

            if (name.length > 1) {
                child.push(member);
            } else {
                hierarchyName = baseHierarchyPath(name[0]);

                for (j = 0, l = root.length; j < l; j++) {
                    if (root[j].name[0].indexOf(hierarchyName) === 0) {
                        found = true;
                        break;
                    }
                }

                if (!found) {
                    root.push(member);
                }

                if (member.expand) {
                    expanded.push(member);
                }
            }
        }

        expanded = expanded.concat(child);

        return {
            root: root,
            expanded: expanded
        };
    }

    function serializeMembers(members, measures, sort) {
        var command = "";

        members = members || [];

        var expanded = parseDescriptors(members);
        var root = expanded.root;

        var rootNames = getRootNames(root);
        var crossJoinCommands = [];

        expanded = expanded.expanded;

        var length = expanded.length;
        var idx = 0;

        var memberName;
        var names = [];

        if (rootNames.length > 1 || measures.length > 1) {
            crossJoinCommands.push(crossJoinCommand(rootNames, measures));

            for (; idx < length; idx++) {
                memberName = expandMemberDescriptor(expanded[idx].name, sort);
                names = mapNames(memberName, rootNames).names;

                crossJoinCommands.push(crossJoinCommand(names, measures));
            }

            command += crossJoinCommands.join(",");
        } else {
            for (; idx < length; idx++) {
                memberName = expandMemberDescriptor(expanded[idx].name, sort);
                names.push(memberName[0]); //check if this is ok
            }

            command += rootNames.concat(names).join(",");
        }

        return command;
    }

    var filterFunctionFormats = {
        contains: ", InStr({0}.CurrentMember.MEMBER_CAPTION,\"{1}\") > 0",
        doesnotcontain: ", InStr({0}.CurrentMember.MEMBER_CAPTION,\"{1}\")",
        startswith: ", Left({0}.CurrentMember.MEMBER_CAPTION,Len(\"{1}\"))=\"{1}\"",
        endswith: ", Right({0}.CurrentMember.MEMBER_CAPTION,Len(\"{1}\"))=\"{1}\"",
        eq: ", {0}.CurrentMember.MEMBER_CAPTION = \"{1}\"",
        neq: ", {0}.CurrentMember.MEMBER_CAPTION = \"{1}\""
    };

    function serializeExpression(expression) {
        var command = "";
        var value = expression.value;
        var field = expression.field;
        var operator = expression.operator;

        if (operator == "in") {
            command += "{";
            command += value;
            command += "}";
        } else {
            command += operator == "neq" || operator == "doesnotcontain" ? "-" : "";
            command += "Filter(";
            command += field + ".MEMBERS";
            command += kendo.format(filterFunctionFormats[operator], field, value);
            command += ")";
        }

        return command;
    }

    function serializeFilters(filter, cube) {
        var command = "", current;
        var filters = filter.filters;
        var length = filters.length;
        var idx;

        for (idx = length - 1; idx >= 0; idx--) {

            current = "SELECT (";
            current += serializeExpression(filters[idx]);
            current += ") ON 0";

            if (idx == length - 1) {
                current += " FROM [" + cube + "]";
                command = current;
            } else {
                command = current + " FROM ( " + command + " )";
            }
        }

        return command;
    }

    function serializeOptions(parentTagName, options, capitalize) {
        var result = "";

        if (options) {
            result += "<" + parentTagName + ">";
            var value;
            for (var key in options) {
                value = options[key];
                let keyToUse = key;
                if (capitalize) {
                    keyToUse = keyToUse.replace(/([A-Z]+(?=$|[A-Z][a-z])|[A-Z]?[a-z]+)/g, "$1_").toUpperCase().replace(/_$/, "");
                }
                result += "<" + keyToUse + ">" + value + "</" + keyToUse + ">";
            }
            result += "</" + parentTagName + ">";
        } else {
            result += "<" + parentTagName + "/>";
        }
        return result;
    }

    var xmlaDiscoverCommands = {
        schemaCubes: "MDSCHEMA_CUBES",
        schemaCatalogs: "DBSCHEMA_CATALOGS",
        schemaMeasures: "MDSCHEMA_MEASURES",
        schemaDimensions: "MDSCHEMA_DIMENSIONS",
        schemaHierarchies: "MDSCHEMA_HIERARCHIES",
        schemaLevels: "MDSCHEMA_LEVELS",
        schemaMembers: "MDSCHEMA_MEMBERS",
        schemaKPIs: "MDSCHEMA_KPIS"
    };

    var convertersMap = {
        read: function(options) {
            var command = '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Header/><Body><Execute xmlns="urn:schemas-microsoft-com:xml-analysis"><Command><Statement>';

            command += "SELECT NON EMPTY {";

            var columns = options.columns || [];
            var rows = options.rows || [];

            var measures = options.measures || [];
            var measuresRowAxis = options.measuresAxis === "rows";
            var sort = options.sort || [];

            if (!columns.length && rows.length && (!measures.length || (measures.length && measuresRowAxis))) {
                columns = rows;
                rows = [];
                measuresRowAxis = false;
            }

            if (!columns.length && !rows.length) {
                measuresRowAxis = false;
            }

            if (columns.length) {
                command += serializeMembers(columns, !measuresRowAxis ? measures : [], sort);
            } else if (measures.length && !measuresRowAxis) {
                command += measureNames(measures).join(",");
            }

            command += "} DIMENSION PROPERTIES CHILDREN_CARDINALITY, PARENT_UNIQUE_NAME ON COLUMNS";

            if (rows.length || (measuresRowAxis && measures.length > 1)) {
                command += ", NON EMPTY {";

                if (rows.length) {
                    command += serializeMembers(rows, measuresRowAxis ? measures : [], sort);
                } else {
                    command += measureNames(measures).join(",");
                }

                command += "} DIMENSION PROPERTIES CHILDREN_CARDINALITY, PARENT_UNIQUE_NAME ON ROWS";
            }

            if (options.filter) {
                command += " FROM ";
                command += "(";
                command += serializeFilters(options.filter, options.connection.cube);
                command += ")";
            } else {
                command += " FROM [" + options.connection.cube + "]";
            }

            if (measures.length == 1 && columns.length) {
                command += " WHERE (" + measureNames(measures).join(",") + ")";
            }

            command += '</Statement></Command><Properties><PropertyList><Catalog>' + options.connection.catalog + '</Catalog><Format>Multidimensional</Format></PropertyList></Properties></Execute></Body></Envelope>';
            return command.replace(/\&/g, "&amp;");
        },
        discover: function(options) {
            options = options || {};

            var command = '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Header/><Body><Discover xmlns="urn:schemas-microsoft-com:xml-analysis">';
            command += "<RequestType>" + (xmlaDiscoverCommands[options.command] || options.command) + "</RequestType>";

            command += "<Restrictions>" + serializeOptions("RestrictionList", options.restrictions, true) + "</Restrictions>";

            if (options.connection && options.connection.catalog) {
                options.properties = $.extend({}, {
                    Catalog: options.connection.catalog
                }, options.properties);
            }

            command += "<Properties>" + serializeOptions("PropertyList", options.properties) + "</Properties>";

            command += '</Discover></Body></Envelope>';
            return command;
        }
    };

    var XmlaTransport = kendo.data.RemoteTransport.extend({
        init: function(options) {
            var originalOptions = options;

            options = this.options = extend(true, {}, this.options, options);

            kendo.data.RemoteTransport.call(this, options);

            if (isFunction(originalOptions.discover)) {
                this.discover = originalOptions.discover;
            } else if (typeof originalOptions.discover === "string") {
                this.options.discover = {
                    url: originalOptions.discover
                };
            } else if (!originalOptions.discover) {
                this.options.discover = this.options.read;
            }
        },
        setup: function(options, type) {
            options.data = options.data || {};
            $.extend(true, options.data, { connection: this.options.connection });

            return kendo.data.RemoteTransport.fn.setup.call(this, options, type);
        },
        options: {
            read: {
                dataType: "text",
                contentType: "text/xml",
                type: "POST"
            },
            discover: {
                dataType: "text",
                contentType: "text/xml",
                type: "POST"
            },
            parameterMap: function(options, type) {
                return convertersMap[type](options,type);
            }
        },

        discover: function(options) {
            return $.ajax(this.setup(options, "discover"));
        }
    });

    var XmlaTransportV2 = Class.extend({
        init: function(options) {
            options = this.options = extend(true, {}, this.options, options);
        },
        setup: function(options) {
            return $.extend(true, options || {}, { connection: this.options.connection });
        },
        read: function(options) {
            var that = this,
                success,
                error;

            var fetchOptions = that.setup(options.data, READ);

            success = options.success || $.noop;
            error = options.error || $.noop;

            if (options.parameterMap) {
                fetchOptions = that.parameterMap(fetchOptions, READ);
            }
            const requestOptions = typeof that.options.read === "object" && that.options.read.url ? that.options.read : { url: that.options.read };

            fetchData(requestOptions, fetchOptions)
            .then(createDataState)
            .then(function(newDataState) {
                success(newDataState);
            })
            .catch(function(err) { error(err); });
        },

        catalog: function(val) {
            var options = this.options || {};

            if (val === undefined$1) {
                return (options.connection || {}).catalog;

            }

            var connection = options.connection || {};
            connection.catalog = val;

            this.options.connection = connection;
            $.extend(this.transport.options, { connection: connection });
        },
        cube: function(val) {
            var options = this.options || {};

            if (val === undefined$1) {
                return (options.connection || {}).cube;
            }

            var connection = options.connection || {};
            connection.cube = val;

            this.options.connection = connection;
            extend(true, this.transport.options, { connection: connection });
        },

        discover: function(options) {
            return fetchDiscover({ url: this.options.read }, options);
        }
    });

    function asArray(object) {
        if (object == null) {
            return [];
        }

        var type = toString.call(object);
        if (type !== "[object Array]") {
            return [object];
        }

        return object;
    }

    function translateAxis(axis) {
        var result = { tuples: [] };
        var tuples = asArray(kendo.getter("Tuples.Tuple", true)(axis));
        var captionGetter = kendo.getter("Caption['#text']");
        var unameGetter = kendo.getter("UName['#text']");
        var levelNameGetter = kendo.getter("LName['#text']");
        var levelNumGetter = kendo.getter("LNum['#text']");
        var childrenGetter = kendo.getter("CHILDREN_CARDINALITY['#text']", true);
        var hierarchyGetter = kendo.getter("['@Hierarchy']");
        var parentNameGetter = kendo.getter("PARENT_UNIQUE_NAME['#text']", true);

        for (var idx = 0; idx < tuples.length; idx++) {
            var members = [];
            var member = asArray(tuples[idx].Member);
            for (var memberIdx = 0; memberIdx < member.length; memberIdx++) {
                members.push({
                    children: [],
                    caption: captionGetter(member[memberIdx]),
                    name: unameGetter(member[memberIdx]),
                    levelName: levelNameGetter(member[memberIdx]),
                    levelNum: levelNumGetter(member[memberIdx]),
                    hasChildren: parseInt(childrenGetter(member[memberIdx]), 10) > 0,
                    parentName: parentNameGetter(member[memberIdx]),
                    hierarchy: hierarchyGetter(member[memberIdx])
                });
            }

            result.tuples.push({ members: members });
        }
        return result;
    }

    var schemaDataReaderMap = {
        cubes: {
            name: kendo.getter("CUBE_NAME['#text']", true),
            caption: kendo.getter("CUBE_CAPTION['#text']", true),
            description: kendo.getter("DESCRIPTION['#text']", true),
            type: kendo.getter("CUBE_TYPE['#text']", true)
        },
        catalogs: {
            name: kendo.getter("CATALOG_NAME['#text']", true),
            description: kendo.getter("DESCRIPTION['#text']", true)
        },
        measures: {
            name: kendo.getter("MEASURE_NAME['#text']", true),
            caption: kendo.getter("MEASURE_CAPTION['#text']", true),
            uniqueName: kendo.getter("MEASURE_UNIQUE_NAME['#text']", true),
            description: kendo.getter("DESCRIPTION['#text']", true),
            aggregator: kendo.getter("MEASURE_AGGREGATOR['#text']", true),
            groupName: kendo.getter("MEASUREGROUP_NAME['#text']", true),
            displayFolder: kendo.getter("MEASURE_DISPLAY_FOLDER['#text']", true),
            defaultFormat: kendo.getter("DEFAULT_FORMAT_STRING['#text']", true)
        },
        kpis: {
            name: kendo.getter("KPI_NAME['#text']", true),
            caption: kendo.getter("KPI_CAPTION['#text']", true),
            value: kendo.getter("KPI_VALUE['#text']", true),
            goal: kendo.getter("KPI_GOAL['#text']", true),
            status: kendo.getter("KPI_STATUS['#text']", true),
            trend: kendo.getter("KPI_TREND['#text']", true),
            statusGraphic: kendo.getter("KPI_STATUS_GRAPHIC['#text']", true),
            trendGraphic: kendo.getter("KPI_TREND_GRAPHIC['#text']", true),
            description: kendo.getter("KPI_DESCRIPTION['#text']", true),
            groupName: kendo.getter("MEASUREGROUP_NAME['#text']", true)
        },
        dimensions: {
            name: kendo.getter("DIMENSION_NAME['#text']", true),
            caption: kendo.getter("DIMENSION_CAPTION['#text']", true),
            description: kendo.getter("DESCRIPTION['#text']", true),
            uniqueName: kendo.getter("DIMENSION_UNIQUE_NAME['#text']", true),
            defaultHierarchy: kendo.getter("DEFAULT_HIERARCHY['#text']", true),
            type: kendo.getter("DIMENSION_TYPE['#text']", true)
//unknown = 0; time = 1; measure = 2; other = 3; quantitative = 5; accounts = 6; customers = 7; products = 8; scenario = 9; utility = 10; currency = 11; rates = 12; channel = 13; promotion = 14; organization = 15; billOfMaterials = 16; geography = 17;

        },
        hierarchies: {
            name: kendo.getter("HIERARCHY_NAME['#text']", true),
            caption: kendo.getter("HIERARCHY_CAPTION['#text']", true),
            description: kendo.getter("DESCRIPTION['#text']", true),
            uniqueName: kendo.getter("HIERARCHY_UNIQUE_NAME['#text']", true),
            dimensionUniqueName: kendo.getter("DIMENSION_UNIQUE_NAME['#text']", true),
            displayFolder: kendo.getter("HIERARCHY_DISPLAY_FOLDER['#text']", true),
            origin: kendo.getter("HIERARCHY_ORIGIN['#text']", true),
            defaultMember: kendo.getter("DEFAULT_MEMBER['#text']", true)
        },
        levels: {
            name: kendo.getter("LEVEL_NAME['#text']", true),
            caption: kendo.getter("LEVEL_CAPTION['#text']", true),
            description: kendo.getter("DESCRIPTION['#text']", true),
            uniqueName: kendo.getter("LEVEL_UNIQUE_NAME['#text']", true),
            dimensionUniqueName: kendo.getter("DIMENSION_UNIQUE_NAME['#text']", true),
            displayFolder: kendo.getter("LEVEL_DISPLAY_FOLDER['#text']", true),
            orderingProperty: kendo.getter("LEVEL_ORDERING_PROPERTY['#text']", true),
            origin: kendo.getter("LEVEL_ORIGIN['#text']", true),
            hierarchyUniqueName: kendo.getter("HIERARCHY_UNIQUE_NAME['#text']", true)
        },
        members: {
            name: kendo.getter("MEMBER_NAME['#text']", true),
            caption: kendo.getter("MEMBER_CAPTION['#text']", true),
            uniqueName: kendo.getter("MEMBER_UNIQUE_NAME['#text']", true),
            dimensionUniqueName: kendo.getter("DIMENSION_UNIQUE_NAME['#text']", true),
            hierarchyUniqueName: kendo.getter("HIERARCHY_UNIQUE_NAME['#text']", true),
            levelUniqueName: kendo.getter("LEVEL_UNIQUE_NAME['#text']", true),
            childrenCardinality: kendo.getter("CHILDREN_CARDINALITY['#text']", true)
        }
    };

    var xmlaReaderMethods = ["axes", "catalogs", "cubes", "dimensions", "hierarchies", "levels", "measures"];

    var XmlaDataReader = kendo.data.XmlDataReader.extend({
        init: function(options) {
            kendo.data.XmlDataReader.call(this, options);

            this._extend(options);
        },
        _extend: function(options) {
            var idx = 0;
            var length = xmlaReaderMethods.length;
            var methodName;
            var option;

            for (; idx < length; idx++) {
                methodName = xmlaReaderMethods[idx];
                option = options[methodName];

                if (option && option !== identity) {
                    this[methodName] = option;
                }
            }
        },
        parse: function(xml) {
            var result = kendo.data.XmlDataReader.fn.parse(xml.replace(/<(\/?)(\w|-)+:/g, "<$1"));
            return kendo.getter("['Envelope']['Body']", true)(result);
        },
        errors: function(root) {
            var fault = kendo.getter("['Fault']", true)(root);
            if (fault) {
                return [{
                    faultstring: kendo.getter("faultstring['#text']", true)(fault),
                    faultcode: kendo.getter("faultcode['#text']", true)(fault)
                }];
            }
            return null;
        },
        axes: function(root) {
            root = kendo.getter("ExecuteResponse[\"return\"].root", true)(root);

            var axes = asArray(kendo.getter("Axes.Axis", true)(root));
            var axis;

            var result = {
                columns: {},
                rows: {}
            };

            for (var idx = 0; idx < axes.length; idx++) {
                axis = axes[idx];

                if (axis["@name"].toLowerCase() !== "sliceraxis") {
                    if (!result.columns.tuples) {
                        result.columns = translateAxis(axis);
                    } else {
                        result.rows = translateAxis(axis);
                    }
                }
            }

            return result;
        },
        data: function(root) {
            root = kendo.getter("ExecuteResponse[\"return\"].root", true)(root);

            var cells = asArray(kendo.getter("CellData.Cell", true)(root));

            var result = [];
            var ordinalGetter = kendo.getter("['@CellOrdinal']");
            var valueGetter = kendo.getter("Value['#text']");
            var fmtValueGetter = kendo.getter("FmtValue['#text']");

            for (var idx = 0; idx < cells.length; idx++) {
                result.push({
                    value: valueGetter(cells[idx]),
                    fmtValue: fmtValueGetter(cells[idx]),
                    ordinal: parseInt(ordinalGetter(cells[idx]), 10)
                });
            }

            return result;
        },
        _mapSchema: function(root, getters) {
            root = kendo.getter("DiscoverResponse[\"return\"].root", true)(root);
            var rows = asArray(kendo.getter("row", true)(root));

            var result = [];

            for (var idx = 0; idx < rows.length; idx++) {
                var obj = {};
                for (var key in getters) {
                    obj[key] = getters[key](rows[idx]);
                }
                result.push(obj);
            }

            return result;
        },
        measures: function(root) {
            return this._mapSchema(root, schemaDataReaderMap.measures);
        },
        kpis: function(root) {
            return this._mapSchema(root, schemaDataReaderMap.kpis);
        },
        hierarchies: function(root) {
            return this._mapSchema(root, schemaDataReaderMap.hierarchies);
        },
        levels: function(root) {
            return this._mapSchema(root, schemaDataReaderMap.levels);
        },
        dimensions: function(root) {
            return this._mapSchema(root, schemaDataReaderMap.dimensions);
        },
        cubes: function(root) {
            return this._mapSchema(root, schemaDataReaderMap.cubes);
        },
        catalogs: function(root) {
            return this._mapSchema(root, schemaDataReaderMap.catalogs);
        },
        members: function(root) {
            return this._mapSchema(root, schemaDataReaderMap.members);
        }
    });

    extend(true, kendo.data, {
       PivotDataSource: PivotDataSource,
       PivotDataSourceV2: PivotDataSourceV2,
       XmlaTransport: XmlaTransport,
       XmlaDataReader: XmlaDataReader,
       PivotCubeBuilder: PivotCubeBuilder,
       transports: {
           xmla: XmlaTransport
       },
       readers: {
           xmla: XmlaDataReader
       }
    });

    var sortExpr = function(expressions, name) {
        if (!expressions) {
            return null;
        }

        for (var idx = 0, length = expressions.length; idx < length; idx++) {
            if (expressions[idx].field === name) {
                return expressions[idx];
            }
        }

        return null;
    };

    var removeExpr = function(expressions, name) {
        var result = [];

        for (var idx = 0, length = expressions.length; idx < length; idx++) {
            if (expressions[idx].field !== name) {
                result.push(expressions[idx]);
            }
        }

        return result;
    };

    kendo.ui.PivotSettingTarget = Widget.extend({
        init: function(element, options) {
            var that = this;

            Widget.fn.init.call(that, element, options);

            that.element.addClass("k-pivot-setting");

            that.dataSource = kendo.data.PivotDataSource.create(options.dataSource);

            that._refreshHandler = that.refresh.bind(that);
            that.dataSource.first(CHANGE, that._refreshHandler);

            if (!options.template) {
                var actions = '';

                if (that.options.enabled) {
                    actions = `<span class="k-setting-delete k-chip-action">${kendo.ui.icon("x")}</span>`;
                }

                that.options.template = (data) => ''
                    + `<span class="k-chip k-chip-md k-rounded-md k-chip-solid k-chip-solid-base" data-${kendo.ns}name="${data.name || data}">`
                        + '<span class="k-chip-content">'
                            + `<span class="k-chip-text">${data.name || data}</span>`
                        + '</span>'
                        + '<span class="k-chip-actions">' + actions + '</span>'
                    + '</span>';
            }

            that.template = kendo.template(that.options.template);
            that.emptyTemplate = kendo.template(that.options.emptyTemplate);

            that._sortable();

            that.element.on("click" + NS, '.k-chip, .k-button' , function(e) {
                var target = $(e.target).closest(":not(path,svg)");
                var action = target.closest('.k-chip-action');
                var name = target.closest("[" + kendo.attr("name") + "]")
                                 .attr(kendo.attr("name"));

                if (!name) {
                    return;
                }

                if (action.hasClass("k-setting-delete")) {
                    that.remove(name);
                    return;
                }

                if (target.closest('.k-chip-actions').length > 0) {
                    return;
                }

                if (that.options.sortable) {
                    var sortDirection = $(e.currentTarget).closest(":not(path,svg)").find('.k-i-sort-asc-small,.k-svg-i-sort-asc-small').length ? 'desc' : 'asc';

                    that.sort({
                        field: name,
                        dir: sortDirection
                    });
                }
            });

            if (options.filterable || options.sortable) {
                that.fieldMenu = new ui.PivotFieldMenu(that.element, {
                    messages: that.options.messages.fieldMenu,
                    filter: ".k-setting-fieldmenu",
                    filterable: options.filterable,
                    sortable: options.sortable,
                    dataSource: that.dataSource
                });
            }

            that.refresh();
        },

        options: {
            name: "PivotSettingTarget",
            template: null,
            filterable: false,
            sortable: false,
            emptyTemplate: (data) => `<div class='k-empty'>${data}</div>`,
            setting: "columns",
            enabled: true,
            messages: {
                empty: "Drop Fields Here"
            }
        },
        setDataSource: function(dataSource) {
            this.dataSource.unbind(CHANGE, this._refreshHandler);
            this.dataSource = this.options.dataSource = dataSource;

            if (this.fieldMenu) {
                this.fieldMenu.setDataSource(dataSource);
            }
            dataSource.first(CHANGE, this._refreshHandler);

            this.refresh();
        },

        _sortable: function() {
            var that = this;

            if (that.options.enabled) {
                this.sortable = this.element.kendoSortable({
                    connectWith: this.options.connectWith,
                    hint: that.options.hint,
                    filter: ">*:not(.k-empty)",
                    cursor: "move",
                    start: function(e) {
                        e.item.trigger("focus").trigger("blur");
                    },
                    change: function(e) {
                        var name = e.item.attr(kendo.attr("name"));

                        if (e.action == "receive") {
                            that.add(name);
                        } else if (e.action == "remove") {
                            that.remove(name);
                        } else if (e.action == "sort") {
                            that.move(name, e.newIndex);
                        }
                    }
                }).data("kendoSortable");
            }
        },

        _isKPI: function(data) {
            return data.type === "kpi" || data.measure;
        },

        validate: function(data) {
            var isMeasure = (data.type == 2 || "aggregator" in data || this._isKPI(data));

            if (isMeasure) {
                return this.options.setting === "measures";
            }

            if (this.options.setting === "measures") {
                return isMeasure;
            }

            var items = this.dataSource[this.options.setting]();
            var name = data.defaultHierarchy || data.uniqueName;
            if (indexOf(name, items) > -1) {
                return false;
            }

            items = this.dataSource[this.options.setting === "columns" ? "rows" : "columns"]();
            if (indexOf(name, items) > -1) {
                return false;
            }

            return true;
        },

        add: function(name) {
            let items = this.dataSource[this.options.setting]();
            let i = 0;

            name = Array.isArray(name) ? name.slice(0) : [name];

            let l = name.length;

            while (i < l) {
                if (indexOf(name[i], items) !== -1) {
                    name.splice(i, 1);
                    i -= 1;
                    l -= 1;
                }
                i++;
            }

            if (name.length) {
                items = items.concat(name);
                this.dataSource[this.options.setting](items);
            }
        },

        move: function(name, index) {
            var items = this.dataSource[this.options.setting]();
            var idx = indexOf(name, items);

            if (idx > -1) {
                name = items.splice(idx, 1)[0];

                items.splice(index, 0, name);

                this.dataSource[this.options.setting](items);
            }
        },

        remove: function(name) {
            var items = this.dataSource[this.options.setting]();
            var idx = indexOf(name, items);
            var sortExpressions = this.dataSource.sort();
            var filter = this.dataSource.filter();

            if (idx > -1) {
                if (filter) {
                    filter.filters = removeExpr(filter.filters, name);
                    this.dataSource._filter.filters = filter.filters;
                    if (!filter.filters.length) {
                        this.dataSource._filter = null;
                    }
                }
                if (sortExpressions) {
                    sortExpressions = removeExpr(sortExpressions, name);
                    this.dataSource._sort = sortExpressions;
                }
                items.splice(idx, 1);
                this.dataSource[this.options.setting](items);
            }
        },

        sort: function(expr) {
            var sortable = this.options.sortable;
            var allowUnsort = sortable === true || sortable.allowUnsort;
            var skipExpr = allowUnsort && expr.dir === "asc";

            var expressions = (this.dataSource.sort() || []);
            var result = removeExpr(expressions, expr.field);

            if (skipExpr && expressions.length !== result.length) {
                expr = null;
            }

            if (expr) {
                result.push(expr);
            }

            this.dataSource.sort(result);
        },

        refresh: function() {
            var html = "";
            var items = this.dataSource[this.options.setting]();
            var length = items.length;
            var idx = 0;
            var item;

            if (length) {
                for (; idx < length; idx++) {
                    item = items[idx];
                    item = item.name === undefined$1 ? { name: item } : item;

                    html += this.template(extend({ sortIcon: this._sortIcon(item.name) }, item));
                }
            } else {
                html = this.emptyTemplate(this.options.messages.empty);
            }

            this.element.html(html);
        },

        destroy: function() {
            Widget.fn.destroy.call(this);

            this.dataSource.unbind(CHANGE, this._refreshHandler);
            this.element.off(NS);

            if (this.sortable) {
                this.sortable.destroy();
            }

            if (this.fieldMenu) {
                this.fieldMenu.destroy();
            }

            this.element = null;
            this._refreshHandler = null;
        },

        _sortIcon: function(name) {
            var expressions = this.dataSource.sort();
            var expr = sortExpr(expressions, getName(name));
            var icon = "";

            if (expr) {
                icon = "sort-" + expr.dir;
            }

            return icon;
        }
    });

    kendo.ui.PivotSettingTargetV2 = Widget.extend({
        init: function(element, options) {
            var that = this;

            Widget.fn.init.call(that, element, options);

            that.dataSource = kendo.data.PivotDataSourceV2.create(options.dataSource);

            that._refreshHandler = that.refresh.bind(that);
            that.dataSource.first(CHANGE, that._refreshHandler);

            that.template = kendo.template(that.options.template);

            that._sortable();

            that.element.on("click" + NS, ".k-i-x-circle,.k-svg-i-x-circle", function(e) {
                var target = $(e.target).closest(":not(path,svg)");
                var parent = target.closest(".k-chip");
                var name = parent.find(".k-chip-label").text();

                if (!name) {
                    return;
                }

                that.remove(name);
                parent.remove();
                that.trigger("remove", { name: name });
            });

            if (that.options.navigatable) {
                that.element.on("keydown" + NS, ".k-chip", function(ev) {
                    var chip = $(ev.target),
                        key = ev.keyCode,
                        name = chip.find(".k-chip-label").text();

                    if (key === keys.DELETE || key === keys.BACKSPACE) {
                        const targetIndex = that.options.configuratorNavigation ? that.options.configuratorNavigation.elements.indexOf(chip[0]) : -1;
                        chip.find(".k-i-x-circle,.k-svg-i-x-circle").trigger("click");
                        if (!that.options.configuratorNavigation) {
                            return;
                        }

                        that.options.configuratorNavigation.focusElement(
                            that.options.configuratorNavigation.elements[targetIndex - 1],
                        );
                    } else if (key === keys.DOWN && ev.altKey) {
                        chip.find(".k-i-more-vertical,.k-svg-i-more-vertical").trigger("click");
                    } else if (ev.ctrlKey && ev.shiftKey) {
                        if (key == keys.LEFT) {
                            that.move(name, Math.max(0, chip.index() - 1));

                            if (!that.options.configuratorNavigation) {
                                return;
                            }

                            that.options.configuratorNavigation.focusElement(
                                that.element.find(".k-chip .k-chip-label")
                                    .filter((ind, el) => $(el).text() == name)
                                    .closest(".k-chip")[0]
                            );
                        } else if (key == keys.RIGHT) {
                            that.move(name, Math.min(chip.index() + 1, chip.parent().find("> .k-chip").length - 1));

                            if (!that.options.configuratorNavigation) {
                                return;
                            }

                            that.options.configuratorNavigation.focusElement(
                                that.element.find(".k-chip .k-chip-label")
                                    .filter((ind, el) => $(el).text() == name)
                                    .closest(".k-chip")[0]
                            );
                        } else if ((key == keys.UP && that.options.setting == "rows") ||
                            (key == keys.DOWN && that.options.setting == "columns")) {

                            let otherTarget = that.sortable.options.connectWith.data("kendoPivotSettingTargetV2");
                            if (!otherTarget) {
                                return;
                            }

                            that.remove(name);
                            otherTarget.add(name);
                            if (!that.options.configuratorNavigation) {
                                return;
                            }

                            that.options.configuratorNavigation.focusElement(
                                otherTarget.element.find(".k-chip").last()[0]
                            );
                        }
                    }
                });
            }

            that.fieldMenu = new ui.PivotFieldMenuV2(that.element, {
                messages: that.options.messages.fieldMenu,
                filterable: options.filterable,
                filter: ".k-i-more-vertical,.k-svg-i-more-vertical",
                sortable: options.sortable,
                dataSource: that.dataSource,
                setting: options.setting
            });

            that.refresh();
        },

        events: ["remove"],

        options: {
            name: "PivotSettingTargetV2",
            template: null,
            filterable: false,
            sortable: false,
            setting: "columns",
            enabled: true,
            messages: {
                empty: "Drop Fields Here"
            }
        },
        setDataSource: function(dataSource) {
            this.dataSource.unbind(CHANGE, this._refreshHandler);
            this.dataSource = this.options.dataSource = dataSource;

            if (this.fieldMenu) {
                this.fieldMenu.setDataSource(dataSource);
            }
            dataSource.first(CHANGE, this._refreshHandler);

            this.refresh();
        },

        _applyState: function() {
            if (this._sortState !== undefined$1) {
                this.dataSource._sort = this._sortState;
                this._sortState = undefined$1;
            }

            if (this._stateFilter !== undefined$1) {
                this.dataSource._filter = this._stateFilter;
                this._stateFilter = undefined$1;
            }

            this.dataSource["_" + this.options.setting] = this.options.setting === "measures" ? normalizeMeasures(this._savedState) : normalizeMembers(this._savedState);
        },

        _cancelChanges: function() {
            this._sortState = undefined$1;
            this._stateFilter = undefined$1;
            this._savedState = kendo.deepExtend([], this._initialState);
            this._redraw();
        },

        _state: function(newState, modifyInit) {
            var that = this;

            if (!newState) {
                return that._savedState || [];
            } else {
                if (!that._savedState || modifyInit) {
                    that._initialState = kendo.deepExtend([], newState);
                }
                that._savedState = kendo.deepExtend([], newState);
            }
        },

        _sortable: function() {
            var that = this;

            this.sortable = this.element.kendoSortable({
                connectWith: this.options.connectWith,
                hint: that.options.hint,
                filter: ">*:not(.k-empty)",
                cursor: "move",
                start: function(e) {
                    e.item.trigger("focus").blur();
                },
                change: function(e) {
                    var name = e.item.find(".k-chip-label").text();

                    if (e.action == "receive") {
                        that.add(name);
                    } else if (e.action == "remove") {
                        that.remove(name);
                    } else if (e.action == "sort") {
                        that.move(name, e.newIndex);
                    }
                }
            }).data("kendoSortable");
        },

        add: function(name) {
            let items = this._state();
            let i = 0;

            name = Array.isArray(name) ? name.slice(0) : [name];

            let l = name.length;
            while (i < l) {
                if (indexOf(name[i], items) !== -1) {
                    name.splice(i, 1);
                    i -= 1;
                    l -= 1;
                }
                i++;
            }

            if (name.length) {
                items = items.concat(name);
                this._state(items);
                this._redraw();
            }
        },

        move: function(name, index) {
            var items = this._state();
            var idx = indexOf(name, items);

            if (idx > -1) {
                name = items.splice(idx, 1)[0];

                items.splice(index, 0, name);

                this._state(items);
                this._redraw();
            }
        },

        remove: function(name) {
            var items = this._state();
            var idx = indexOf(name, items);
            var sortExpressions = this.dataSource.sort();
            var filter = this.dataSource.filter();

            if (idx > -1) {
                if (filter) {
                    filter.filters = removeExpr(filter.filters, name);
                    this._savedFilter = this.dataSource._filter;
                    this._savedFilter.filters = filter.filters;
                    if (!filter.filters.length) {
                        this._savedFilter = null;
                    }
                }
                if (sortExpressions) {
                    sortExpressions = removeExpr(sortExpressions, name);
                    this._sortState = sortExpressions;
                }
                items.splice(idx, 1);
                this._state(items);
                this._redraw();
            }
        },

        _emptyState: function(enable) {
            var that = this;
            if (enable) {
                that.element.html(this.options.messages.empty)
                    .addClass("k-settings-description")
                    .removeClass("k-chip-list");
            } else {
                that.element
                    .removeClass("k-settings-description")
                    .addClass("k-chip-list");
            }
        },

        _redraw: function() {
            var items = this._state() || [];
            this._emptyState(!items.length);
            if (items.length) {
                this.element.html(this._targetsHTML(items));
            }
        },

        _targetsHTML: function(items) {
            var item;
            var html = "";
            var idx = 0;
            var enabled = true;

            if (items.length) {
                for (; idx < items.length; idx++) {
                    item = items[idx];
                    item = item.name === undefined$1 ? { name: item } : item;

                    html += this.template({ name: item.name, menuenabled: enabled });
                }
            }
            return html;
        },

        refresh: function() {
            if (this.dataSource._preventRefresh) {
                return;
            }
            var items = this.dataSource[this.options.setting]();
            this._state(items, true);
            this._emptyState(!this._state().length);
            if (items.length) {
                this.element.html(this._targetsHTML(items));
            }
        },

        destroy: function() {
            Widget.fn.destroy.call(this);

            this.dataSource.unbind(CHANGE, this._refreshHandler);
            this.element.off(NS);

            if (this.sortable) {
                this.sortable.destroy();
            }

            if (this.fieldMenu) {
                this.fieldMenu.destroy();
            }

            this.element = null;
            this._refreshHandler = null;
        }
    });

    var PivotConfiguratorButton = Widget.extend({
        init: function(element, options) {
            var that = this;
            Widget.fn.init.call(that, element, options);
            that.element = $(element);

            that._element();
            that._attachEvents();
        },

        options: {
            name: "PivotConfiguratorButton",
            text: "Change settings",
            configurator: ""
        },

        destroy: function() {
            this.element.off(NS);
        },

        setOptions: function(options) {
            var that = this;
            kendo.deepExtend(that.options, options);
            this.init(this.element, this.options);
        },

        toggle: function() {
            var attr = kendo.attr("role");
            var pivotEl = this.element
                .closest("[" + attr + "=pivotcontainer]")
                .find("[" + attr + "=pivotgridv2]");
            var pivot;

            $("#" + this.options.configurator).toggleClass("k-hidden");

            if (pivotEl.length) {
                pivot = pivotEl.getKendoPivotGridV2();
                pivot._setContentWidth();
                pivot._updateDimensions();
            }
        },

        _attachEvents: function() {
            this.element.on("click" + NS, this.toggle.bind(this));
        },

        _element: function() {
            var options = this.options;
            this.element.addClass("k-pivotgrid-configurator-button");
            this.element.html(kendo.format("<span>{0}{1}</span>",options.text, kendo.ui.icon('gear')));
        }
    });

    var PivotContainer = Widget.extend({
        init: function(element, options) {
            var that = this;
            Widget.fn.init.call(that, element, options);
            that.element = $(element);
            that.options = options;


            that._addClasses();
        },

        options: {
            name: "PivotContainer",
            configuratorPosition: "left"
        },

        setOptions: function(options) {
            var that = this;
            kendo.deepExtend(that.options, options);
            this.init(this.element, this.options);
        },

        _addClasses: function() {
            var options = this.options;
            var className;
            this.element.removeClass("k-flex-row k-flex-row-reverse k-flex-column k-flex-column-reverse");

            switch (options.configuratorPosition) {
                case "right":
                    className = "k-flex-row";
                    break;
                case "left":
                    className = "k-flex-row-reverse";
                    break;
                case "bottom":
                    className = "k-flex-column";
                    break;
                case "top":
                    className = "k-flex-column-reverse";
                    break;
                default:
                    className = "k-flex-row";
            }

            this.element
                .addClass("k-d-flex k-pos-relative")
                .addClass(className);
        }
    });

    var PivotGridV2 = Widget.extend({
        init: function(element, options) {
            var that = this;

            Widget.fn.init.call(that, element, options);

            that._dataSource();

            that._bindConfigurator();

            that._ariaId = that.element.attr("id") || kendo.guid();
            that._wrapper();

            that._columnHeadersWrapper = $('<div class="k-pivotgrid-column-headers"></div>');
            that._rowHeadersWrapper = $('<div class="k-pivotgrid-row-headers"></div>');
            that._contentWrapper = $('<div class="k-pivotgrid-values"></div>');

            that.wrapper.append(that._columnHeadersWrapper);
            that.wrapper.append(that._rowHeadersWrapper);
            that.wrapper.append(that._contentWrapper);

            that._columnBuilder = new ColumnRowBuilder( { template: this.options.columnHeaderTemplate, axes: "columns", ariaId: that._ariaId });
            that._rowBuilder = new ColumnRowBuilder( { template: this.options.rowHeaderTemplate, axes: "rows", ariaId: that._ariaId });
            that._contentBuilder = new ContentBuilderV2( {
                dataCellTemplate: this.options.dataCellTemplate || DATACELL_TEMPLATE,
                kpiStatusTemplate: this.options.kpiStatusTemplate || KPISTATUS_TEMPLATE,
                kpiTrendTemplate: this.options.kpiTrendTemplate || KPITREND_TEMPLATE,
                measures: this.dataSource._measures,
                ariaId: that._ariaId
            });

            that._scrollable();
            that._rowHeadersWrapper
                .add(that._columnHeadersWrapper)
                .on("click", "span.k-icon,span.k-svg-icon", function() {
                    var button = $(this);
                    var path = button.parent().attr(kendo.attr("key"));
                    var expanded = button.is(".k-i-chevron-up,.k-svg-i-chevron-up");
                    var isRow = button.closest(".k-pivotgrid-row-headers").length !== 0;
                    var paths = path.split(",");
                    var eventName = expanded ? COLLAPSEMEMBER : EXPANDMEMBER;

                    if (that.trigger(eventName, { path: paths, axis: isRow ? "rows" : "columns" })) {
                        return;
                    }

                    var reducerPayLoad = {
                        type: "HEADERS_ACTION_TOGGLE",
                        payload: paths,
                        tree: isRow ? that._rowBuilder.getTree() : that._columnBuilder.getTree()
                    };
                    var currentAxes = isRow ? that.dataSource._rows : that.dataSource._columns;
                    var newHeaders = headersReducer(currentAxes, reducerPayLoad);

                    that.dataSource._preventRefresh = true;
                    that._columnBuilder._exportData = {};
                    that._rowBuilder._exportData = {};

                    if (isRow) {
                        that.dataSource.rows(newHeaders);
                    } else {
                        that.dataSource.columns(newHeaders);
                    }
                 });

            if (that.options.autoBind) {
                that.dataSource.fetch();
            }

            that._aria();

            if (that.options.navigatable) {
                that._initPivotGridNavigation();
            }

            that._initLoader();

            kendo.notify(that);
        },

        events: [
            DATABINDING,
            DATABOUND,
            EXPANDMEMBER,
            COLLAPSEMEMBER
        ],

        options: {
            name: "PivotGridV2",
            autoBind: true,
            height: null,
            columnWidth: null,
            configurator: "",
            columnHeaderTemplate: null,
            rowHeaderTemplate: null,
            dataCellTemplate: null,
            kpiStatusTemplate: null,
            kpiTrendTemplate: null,
            messages: {
                emptyCellLabel: "PivotGrid Empty Cell"
            }
        },

        destroy: function() {
            var that = this;
            Widget.fn.destroy.call(that);

            if (that.loader) {
                that.loader.destroy();
            }

            if (that._windowResizeHandler) {
                $(window).off(RESIZE + NS, that._windowResizeHandler);
                that._windowResizeHandler = null;
            }
        },

        _aria: function() {
            var that = this;
            that.element.attr("role", "grid");
        },

        setDataSource: function(dataSource) {
            this.options.dataSource = dataSource;

            this._dataSource();

            this._bindConfigurator();

            if (this.options.autoBind) {
                dataSource.fetch();
            }
        },

        _initLoader: function(options) {
            var that = this,
                defaultOptions = {
                    size: 'medium',
                    messages: { exporting: 'Exporting...' }
            };
            defaultOptions = $.extend({}, defaultOptions, options);

            const loader = $("<div></div>").kendoLoader(defaultOptions).data("kendoLoader");

            that.loader = loader;
            that._loaderContainer = useLoaderContainer.bind(that);
        },


        _initPivotGridNavigation: function() {
            var that = this;

            that.navigation = new PivotGridNavigation({ tabIndex: 0 });
            that.navigation.keyboardEvents.keydown.o = function(_target, nav, _ev) {
                if (!nav.root) {
                    return;
                }
                // FIX: ADDED manually to fix an issue where depending on the order of the config element and button
                // you either can open the configurator with O, or you can close the configurator with ESC
                let next = nav.root.nextElementSibling;
                if (!(next && next instanceof HTMLElement)) {
                    return;
                }
                if (!next.matches('div.k-pivotgrid-configurator-button')) {
                    next = next.nextElementSibling;
                }
                if (next && next instanceof HTMLElement && next.matches('div.k-pivotgrid-configurator-button')) {
                    if (!nav.root.parentNode || nav.root.parentNode.querySelector(".k-pivotgrid-configurator.k-hidden")) {
                        next.click();
                    }
                    setTimeout(() => {
                        if (nav.root.parentNode) {
                            const confHeader = nav.root.parentNode.querySelector('.k-pivotgrid-configurator-content .k-form-field .k-fields-list-wrapper .k-treeview');
                            if (confHeader instanceof HTMLElement) {
                                confHeader.setAttribute('tabindex', String(nav.tabIndex));
                                confHeader.focus();
                            }
                        }
                    }, 0);
                }
            };
            that.navigation.start(that.element[0]);

            const firstCell = that.navigation.first;

            if (firstCell) {
                firstCell.setAttribute('tabindex', '0');
            }
        },

        _matchAriaAttributes: function(wrapper) {
            var that = this;
            const rowHeaderRows = wrapper.querySelectorAll(
                ".k-pivotgrid-row-headers .k-pivotgrid-row"
            );
            const rowHeaderCols = !rowHeaderRows[0] ? [] : Array.from(rowHeaderRows[0].children).reduce(
                (acc, curr) => (acc += curr.getAttribute("colspan") !== null ? +curr.getAttribute("colspan") : 1),
                0
            );
            const colHeaderRows = wrapper.querySelectorAll(
                ".k-pivotgrid-column-headers tr"
            );
            const colHeaderCells = wrapper.querySelectorAll(
                ".k-pivotgrid-column-headers th"
            );
            const valueTableCells = wrapper.querySelectorAll(".k-pivotgrid-values td");
            const emptyCell = wrapper.querySelector(".k-pivotgrid-empty-cell");

            emptyCell.setAttribute("aria-rowspan", colHeaderRows.length.toString());
            emptyCell.setAttribute("aria-colspan", rowHeaderCols.toString());

            const firstColHeadersRow = colHeaderRows[0];
            const firstColHeaderRowCellsIds = !firstColHeadersRow ? [] : Array.from(firstColHeadersRow.children)
                .map(el => el.getAttribute("id"))
                .join(" ");
            if (firstColHeadersRow) {
                firstColHeadersRow.setAttribute(
                    "aria-owns",
                    `${emptyCell.getAttribute("id")} ${firstColHeaderRowCellsIds}`
                );
            }

            rowHeaderRows.forEach((row, index) => {
                const valueCellsIds = that.filterAndMap(
                    Array.from(valueTableCells),
                    c => {
                        const idParts = c.getAttribute("id").split("-");
                        return idParts[idParts.length - 2] === (index + 1).toString();
                    },
                    c => c.getAttribute("id")
                );

                row.setAttribute("aria-owns", valueCellsIds.join(" "));
            });

            valueTableCells.forEach(cell => {
                const idParts = cell.getAttribute("id").split("-");
                const cellColIndex = +idParts[idParts.length - 1];
                const colHeaderCellsIds = that.filterAndMap(
                    Array.from(colHeaderCells),
                    c => {
                        const idParts = c.getAttribute("id").split("-");
                        const headerCellColIndex = +idParts[idParts.length - 1];
                        const headerCellColspan = +c.getAttribute("colspan");
                        const colIndexIsEqual = cellColIndex === headerCellColIndex;
                        const cellColIndexIsWithinHeaderCellRange =
                            headerCellColspan > 1 &&
                            headerCellColIndex < cellColIndex &&
                            headerCellColIndex + headerCellColspan - 1 >= cellColIndex;

                        return colIndexIsEqual || cellColIndexIsWithinHeaderCellRange;
                    },
                    c => c.getAttribute("id")
                );

                cell.setAttribute("aria-describedby", colHeaderCellsIds.join(" "));
            });
        },

        filterAndMap: function(arr, predicate, mapper) {
            return arr.reduce(
                (acc, curr) => (predicate(curr) ? [...acc, mapper(curr)] : acc),
                []
            );
        },

        _dataSource: function() {
            var that = this;
            var dataSource = that.options.dataSource;

            dataSource = Array.isArray(dataSource) ? { data: dataSource } : dataSource;

            if (that.dataSource && this._refreshHandler) {
                that.dataSource.unbind(CHANGE, that._refreshHandler)
                               .unbind(PROGRESS, that._progressHandler)
                               .unbind(ERROR, that._errorHandler);
            } else {
                that._refreshHandler = that.refresh.bind(that);
                that._progressHandler = that._requestStart.bind(that);
                that._errorHandler = that._error.bind(that);
            }

            that.dataSource = kendo.data.PivotDataSourceV2.create(dataSource)
                                   .bind(CHANGE, that._refreshHandler)
                                   .bind(PROGRESS, that._progressHandler)
                                   .bind(ERROR, that._errorHandler);
        },

        _resize: function() {
            var that = this;
            that.wrapper[0].style.setProperty('--kendo-scrollbar-width', kendo.format("{0}px", getScollWidth()));
        },

        _scrollable: function() {
            var that = this;
            var columnsHeader = that._columnHeadersWrapper;
            var rowsHeader = that._rowHeadersWrapper;

            that._resize();
            that._windowResizeHandler = that._resize.bind(that);

            that._contentWrapper.scroll(function() {
                kendo.scrollLeft(columnsHeader, this.scrollLeft);
                rowsHeader.scrollTop(this.scrollTop);
            });

            rowsHeader.bind("DOMMouseScroll" + NS + " mousewheel" + NS, that._wheelScroll.bind(that));
            $(window).on(RESIZE + NS, that._windowResizeHandler);
        },

        _wheelScroll: function(e) {
            if (e.ctrlKey) {
                return;
            }

            var delta = kendo.wheelDeltaY(e);
            var scrollTop = this._contentWrapper.scrollTop();

            if (delta) {
                e.preventDefault();
                $(e.currentTarget).one("wheel" + NS, false);

                this._rowHeadersWrapper.scrollTop(scrollTop + (-delta));
                this._contentWrapper.scrollTop(scrollTop + (-delta));
            }
        },

        _wrapper: function() {
            var height = this.options.height;

            this.wrapper = this.element.addClass("k-pivotgrid");
            var emptyCell = $(`<span class="k-pivotgrid-empty-cell" id="${this._ariaId}-empty-cell" role="columnheader"><span class="k-sr-only">${this.options.messages.emptyCellLabel}</span></span>`);
            this.wrapper.append(emptyCell);

            if (height) {
                this.wrapper.css("height", height);
            }
        },

        _progress: function(toggle) {
            if (this._isExport) {
                this._loaderContainer(toggle, { message: "Exporting..." });
            } else {
                kendo.ui.progress(this.wrapper, toggle);
            }
        },

        _error: function() {
            this._progress(false);
        },

        _requestStart: function() {
            this._progress(true);
        },

        _updateDimensions: function() {
            var that = this;
            that.wrapper.css({
                "grid-template-columns": kendo.format("{0}px 1fr", that._rowHeadersWrapper.find(".k-pivotgrid-table")[0].offsetWidth),
                "grid-template-rows": kendo.format("{0}px 1fr", that._columnHeadersWrapper.find(".k-pivotgrid-table")[0].offsetHeight),
            });
        },

        _setContentWidth: function() {
            if (!this.options.columnWidth) {
                return;
            }
            var contentTable = this._contentWrapper.find("table");
            var columnTable = this._columnHeadersWrapper.children("table");
            var rowTable = this._rowHeadersWrapper.children("table");

            contentTable.add(columnTable).add(rowTable).find("col").width(this.options.columnWidth);
        },

        _bindConfigurator: function() {
            var configurator = this.options.configurator;
            if (configurator) {
                $(configurator).kendoPivotConfiguratorV2("setDataSource", this.dataSource);
            }
        },

        cellInfoByElement: function(element) {
            element = $(element);

            return this.cellInfo(element.index(), element.parent("tr").index());
        },

        cellInfo: function(columnIndex, rowIndex) {
            var contentBuilder = this._contentBuilder;
            var dataIndex;
            var dataItem;

            if (columnIndex >= contentBuilder.columnsCount || columnIndex < 0 ||
                rowIndex >= contentBuilder.rowsCount || rowIndex < 0) {
                return null;
            }

            dataIndex = rowIndex * contentBuilder.columnsCount + columnIndex;
            dataItem = contentBuilder.hash[dataIndex < 0 ? 0 : dataIndex];

            return {
                columnTuple: dataItem.columnTuple,
                rowTuple: dataItem.rowTuple,
                dataItem: dataItem.data
            };
        },

        refresh: function() {
            var that = this;

            var dataSource = that.dataSource;
            if (that.trigger(DATABINDING, { action: "rebind" } )) {
                return;
            }

            var lastFocusedCellID = kendo._activeElement() ? kendo._activeElement().id : null;
            var lastCellIdWithTabIndex = that.wrapper.find("[tabindex=0]").attr("id");
            that._columnBuilder.setTuples(dataSource._columnTuples);
            that._columnHeadersWrapper.html(that._columnBuilder.build());

            that._rowBuilder.setTuples(dataSource._rowTuples);
            that._rowHeadersWrapper.html(that._rowBuilder.build());

            that._contentBuilder.setRowColumnInfo({
                columnHeaderLeafs: that._columnBuilder.getHeaderLeafs(),
                rowHeaderLeafs: that._rowBuilder.getHeaderLeafs(),
                columnHeaderBreadth: that._columnBuilder.getBreadth(),
                rowHeaderDepth: that._rowBuilder.getBreadth(),
                data: dataSource._view
            });

            that._contentWrapper.html(that._contentBuilder.build());


            that._setContentWidth();
            that._updateDimensions();

            that._progress(false);

            that.trigger(DATABOUND);
            that._matchAriaAttributes(that.wrapper[0]);

            if (!that.navigation) {
                return;
            }

            if (lastCellIdWithTabIndex && that.element.find(`#${lastCellIdWithTabIndex}`).length > 0) {
                that.element.find(`#${lastCellIdWithTabIndex}`).attr('tabindex', '0');
            } else {
                const firstCell = that.navigation.first;

                if (firstCell) {
                    firstCell.setAttribute('tabindex', '0');
                }
            }

            if (lastFocusedCellID && lastFocusedCellID.indexOf(that._ariaId) == 0) {
                that.navigation.focusElement(that.element.find(`#${lastFocusedCellID}`)[0]);
            }
        }
    });

    ui.plugin(PivotConfiguratorButton);
    ui.plugin(PivotContainer);
    ui.plugin(PivotGridV2);

    var PivotGrid = Widget.extend({
        init: function(element, options) {
            var that = this;
            var columnBuilder;
            var rowBuilder;

            Widget.fn.init.call(that, element, options);

            STATE_COLLAPSED_ICONNAME = kendo.support.isRtl(that.element) ? "caret-alt-left" : "caret-alt-right";

            that._dataSource();

            that._bindConfigurator();

            that._wrapper();
            that._createLayout();

            that._columnBuilder = columnBuilder = new ColumnBuilder();
            that._rowBuilder = rowBuilder = new RowBuilder();
            that._contentBuilder = new ContentBuilder();

            that._templates();

            that.columnsHeader
                .add(that.rowsHeader)
                .on("click", "span.k-icon,span.k-svg-icon", function() {
                    var button = $(this);
                    var builder = columnBuilder;
                    var action = "expandColumn";
                    var eventName;
                    var path = button.attr(kendo.attr("path"));
                    var eventArgs = {
                        axis: "columns",
                        path: JSON.parse(path)
                    };

                    if (button.parent().is("td")) {
                        builder = rowBuilder;
                        action = "expandRow";
                        eventArgs.axis = "rows";
                    }

                    var expanded = button.is(STATE_EXPANDED_SELECTOR);
                    var metadata = builder.metadata[path];
                    var request = metadata.expanded === undefined$1;

                    eventName = expanded ? COLLAPSEMEMBER : EXPANDMEMBER;
                    eventArgs.childrenLoaded = metadata.maxChildren > metadata.children;

                    if (that.trigger(eventName, eventArgs)) {
                        return;
                    }

                    builder.metadata[path].expanded = !expanded;
                    kendo.ui.icon(button,{ icon: !expanded ? STATE_EXPANDED_ICONNAME : STATE_COLLAPSED_ICONNAME });

                    if (!expanded && request) {
                        that.dataSource[action](eventArgs.path);
                    } else {
                        that.refresh();
                    }
                });

            that._scrollable();

            if (that.options.autoBind) {
                that.dataSource.fetch();
            }

            kendo.notify(that);
        },

        events: [
            DATABINDING,
            DATABOUND,
            EXPANDMEMBER,
            COLLAPSEMEMBER
        ],

        options: {
            name: "PivotGrid",
            autoBind: true,
            reorderable: true,
            filterable: false,
            sortable: false,
            navigatable: false,
            height: null,
            columnWidth: 100,
            configurator: "",
            columnHeaderTemplate: null,
            rowHeaderTemplate: null,
            dataCellTemplate: null,
            kpiStatusTemplate: null,
            kpiTrendTemplate: null,
            messages: {
                measureFields: "Drop Data Fields Here",
                columnFields: "Drop Column Fields Here",
                rowFields: "Drop Rows Fields Here"
            }
        },

        _templates: function() {
            var columnTemplate = this.options.columnHeaderTemplate;
            var rowTemplate = this.options.rowHeaderTemplate;
            var dataTemplate = this.options.dataCellTemplate;
            var kpiStatusTemplate = this.options.kpiStatusTemplate;
            var kpiTrendTemplate = this.options.kpiTrendTemplate;

            this._columnBuilder.template = kendo.template(columnTemplate || HEADER_TEMPLATE, { useWithBlock: !!columnTemplate });
            this._contentBuilder.dataTemplate = kendo.template(dataTemplate || DATACELL_TEMPLATE, { useWithBlock: !!dataTemplate });
            this._contentBuilder.kpiStatusTemplate = kendo.template(kpiStatusTemplate || KPISTATUS_TEMPLATE, { useWithBlock: !!kpiStatusTemplate });
            this._contentBuilder.kpiTrendTemplate = kendo.template(kpiTrendTemplate || KPITREND_TEMPLATE, { useWithBlock: !!kpiTrendTemplate });
            this._rowBuilder.template = kendo.template(rowTemplate || HEADER_TEMPLATE, { useWithBlock: !!rowTemplate });
        },

        _bindConfigurator: function() {
            var configurator = this.options.configurator;
            if (configurator) {
                $(configurator).kendoPivotConfigurator("setDataSource", this.dataSource);
            }
        },

        cellInfoByElement: function(element) {
            element = $(element);

            return this.cellInfo(element.index(), element.parent("tr").index());
        },

        cellInfo: function(columnIndex, rowIndex) {
            var contentBuilder = this._contentBuilder;
            var columnInfo = contentBuilder.columnIndexes[columnIndex || 0];
            var rowInfo = contentBuilder.rowIndexes[rowIndex || 0];
            var dataIndex;

            if (!columnInfo || !rowInfo) {
                return null;
            }

            dataIndex = (rowInfo.index * contentBuilder.rowLength) + columnInfo.index;

            return {
                columnTuple: columnInfo.tuple,
                rowTuple: rowInfo.tuple,
                measure: columnInfo.measure || rowInfo.measure,
                dataItem: this.dataSource.view()[dataIndex]
            };
        },

        setDataSource: function(dataSource) {
            this.options.dataSource = dataSource;

            this._dataSource();

            if (this.measuresTarget) {
                this.measuresTarget.setDataSource(dataSource);
            }

            if (this.rowsTarget) {
                this.rowsTarget.setDataSource(dataSource);
            }

            if (this.columnsTarget) {
                this.columnsTarget.setDataSource(dataSource);
            }

            this._bindConfigurator();

            if (this.options.autoBind) {
                dataSource.fetch();
            }
        },

        setOptions: function(options) {
            Widget.fn.setOptions.call(this, options);

            this._templates();
        },

        destroy: function() {
            Widget.fn.destroy.call(this);

            clearTimeout(this._headerReflowTimeout);
        },

        _dataSource: function() {
            var that = this;
            var dataSource = that.options.dataSource;

            dataSource = Array.isArray(dataSource) ? { data: dataSource } : dataSource;

            if (that.dataSource && this._refreshHandler) {
                that.dataSource.unbind(CHANGE, that._refreshHandler)
                               .unbind(STATERESET, that._stateResetHandler)
                               .unbind(PROGRESS, that._progressHandler)
                               .unbind(ERROR, that._errorHandler);
            } else {
                that._refreshHandler = that.refresh.bind(that);
                that._progressHandler = that._requestStart.bind(that);
                that._stateResetHandler = that._stateReset.bind(that);
                that._errorHandler = that._error.bind(that);
            }

            that.dataSource = kendo.data.PivotDataSource.create(dataSource)
                                   .bind(CHANGE, that._refreshHandler)
                                   .bind(PROGRESS, that._progressHandler)
                                   .bind(STATERESET, that._stateResetHandler)
                                   .bind(ERROR, that._errorHandler);
        },

        _error: function() {
            this._progress(false);
        },

        _requestStart: function() {
            this._progress(true);
        },

        _stateReset: function() {
            this._columnBuilder.reset();
            this._rowBuilder.reset();
        },

        _wrapper: function() {
            var height = this.options.height;

            this.wrapper = this.element.addClass("k-pivot");

            if (height) {
                this.wrapper.css("height", height);
            }
        },

        _measureFields: function() {
            this.measureFields = $(DIV).addClass("k-pivot-toolbar k-toolbar k-toolbar-md k-settings-measures");

            this.measuresTarget = this._createSettingTarget(this.measureFields, {
                setting: "measures",
                messages: {
                    empty: this.options.messages.measureFields
                }
            });
        },

        _createSettingTarget: function(element, options) {
            var template,
                pivotOptions = this.options;

            template = ({ sortIcon, name }) => ''
                + `<span class="k-chip k-chip-md k-rounded-md k-chip-solid k-chip-solid-base" tabindex="0" data-${kendo.ns}name="${name}">`
                    + '<span class="k-chip-content">'
                        + `<span class="k-chip-text">${name}</span>`
                    + '</span>'
                    + '<span class="k-chip-actions k-field-actions">'
                        + getIcons(sortIcon, options, pivotOptions)
                    + '</span>'
                + '</span>';

            return new kendo.ui.PivotSettingTarget(element, $.extend({
                dataSource: this.dataSource,
                template: template,
                emptyTemplate: (data) => `<span class="k-empty">${data}</span>`,
                enabled: this.options.reorderable
            }, options));
        },

        _initSettingTargets: function() {
            this.columnsTarget = this._createSettingTarget(this.columnFields, {
                connectWith: this.rowFields,
                setting: "columns",
                filterable: this.options.filterable,
                sortable: this.options.sortable,
                messages: {
                    empty: this.options.messages.columnFields,
                    fieldMenu: this.options.messages.fieldMenu
                }
            });

            this.rowsTarget = this._createSettingTarget(this.rowFields, {
                connectWith: this.columnFields,
                setting: "rows",
                filterable: this.options.filterable,
                sortable: this.options.sortable,
                messages: {
                    empty: this.options.messages.rowFields,
                    fieldMenu: this.options.messages.fieldMenu
                }
            });
        },

        _createLayout: function() {
            var that = this;
            var layoutTable = $(LAYOUT_TABLE);
            var leftContainer = layoutTable.find(".k-pivot-rowheaders");
            var rightContainer = layoutTable.find(".k-pivot-table");
            var gridWrapper = $(DIV).addClass("k-grid");

            that._measureFields();
            that.columnFields = $(DIV).addClass("k-pivot-toolbar k-toolbar k-toolbar-md k-settings-columns");

            that.rowFields = $(DIV).addClass("k-pivot-toolbar k-toolbar k-toolbar-md k-settings-rows");
            that.columnsHeader = $('<div class="k-grid-header-wrap" />')
                                    .wrap('<div class="k-grid-header" />');

            that.columnsHeader.parent().css("padding-right", kendo.support.scrollbar());

            that.rowsHeader = $('<div class="k-grid k-alt"/>');
            that.content = $('<div class="k-grid-content" />');

            leftContainer.append(that.measureFields);
            leftContainer.append(that.rowFields);
            leftContainer.append(that.rowsHeader);

            gridWrapper.append(that.columnsHeader.parent());
            gridWrapper.append(that.content);

            rightContainer.append(that.columnFields);
            rightContainer.append(gridWrapper);

            that.wrapper.append(layoutTable);

            that.columnsHeaderTree = new kendo.dom.Tree(that.columnsHeader[0]);
            that.rowsHeaderTree = new kendo.dom.Tree(that.rowsHeader[0]);
            that.contentTree = new kendo.dom.Tree(that.content[0]);

            that._initSettingTargets();
        },

        _progress: function(toggle) {
            kendo.ui.progress(this.wrapper, toggle);
        },

        _resize: function() {
            if (this.content[0].firstChild) {
                this._setSectionsWidth();
                this._setSectionsHeight();
                this._setContentWidth();
                this._setContentHeight();
                this._columnHeaderReflow();
            }
        },

        _columnHeaderReflow: function() {
            var columnTable = this.columnsHeader.children("table");

            if (!kendo.support.browser.mozilla) {
                return;
            }

            clearTimeout(this._headerReflowTimeout);

            columnTable.css("table-layout", "auto");

            this._headerReflowTimeout = setTimeout(function() {
                columnTable.css("table-layout", "");
            });
        },

        _setSectionsWidth: function() {
            var rowsHeader = this.rowsHeader;
            var leftColumn = rowsHeader.parent(".k-pivot-rowheaders").width(AUTO);
            var width;

            width = Math.max(outerWidth(this.measureFields), outerWidth(this.rowFields));
            width = Math.max(rowsHeader.children("table").width(), width);

            leftColumn.width(width);
        },

        _setSectionsHeight: function() {
            var measureFieldsHeight = this.measureFields.height(AUTO).height();
            var columnFieldsHeight = this.columnFields.height(AUTO).height();
            var rowFieldsHeight = this.rowFields.height(AUTO).innerHeight();
            var columnsHeight = this.columnsHeader.height(AUTO).innerHeight();

            var padding = rowFieldsHeight - this.rowFields.height();

            var firstRowHeight = columnFieldsHeight > measureFieldsHeight ? columnFieldsHeight : measureFieldsHeight;
            var secondRowHeight = columnsHeight > rowFieldsHeight ? columnsHeight : rowFieldsHeight;

            this.measureFields.height(firstRowHeight);
            this.columnFields.height(firstRowHeight);
            this.rowFields.height(secondRowHeight - padding);
            this.columnsHeader.height(secondRowHeight);
        },

        _setContentWidth: function() {
            var contentTable = this.content.find("table");
            var columnTable = this.columnsHeader.children("table");

            var rowLength = contentTable.children("colgroup").children().length;

            var calculatedWidth = rowLength * this.options.columnWidth;
            var minWidth = Math.ceil((calculatedWidth / this.content.width()) * 100);

            if (minWidth < 100) {
                minWidth = 100;
            }

            contentTable.add(columnTable).css("width", minWidth + "%");

            this._resetColspan(columnTable);
        },

        _setContentHeight: function() {
            var that = this;
            var content = that.content;
            var rowsHeader = that.rowsHeader;
            var innerHeight = that.wrapper.innerHeight();
            var scrollbar = kendo.support.scrollbar();
            var skipScrollbar = content[0].offsetHeight === content[0].clientHeight;
            var height = that.options.height;

            if (that.wrapper.is(":visible")) {
                if (!innerHeight || !height) {
                    if (skipScrollbar) {
                        scrollbar = 0;
                    }

                    content.height("auto");
                    rowsHeader.height(content.height() - scrollbar);
                    return;
                }

                innerHeight -= outerHeight(that.columnFields);
                innerHeight -= outerHeight(that.columnsHeader.parent());

                if (innerHeight <= scrollbar * 2) { // do not set height if proper scrollbar cannot be displayed
                    innerHeight = scrollbar * 2 + 1;
                    if (!skipScrollbar) {
                        innerHeight += scrollbar;
                    }
                }

                content.height(innerHeight);

                if (skipScrollbar) {
                    scrollbar = 0;
                }

                rowsHeader.height(innerHeight - scrollbar);
            }
        },

        _resetColspan: function(columnTable) {
            var that = this;
            var cell = columnTable.children("tbody").children().first().children().first();

            if (that._colspan === undefined$1) {
                that._colspan = cell.attr("colspan");
            }

            cell.attr("colspan", 1);

            clearTimeout(that._layoutTimeout);

            that._layoutTimeout = setTimeout(function() {
                cell.attr("colspan", that._colspan);
                that._colspan = undefined$1;
            });
        },

        _axisMeasures: function(axis) {
            var result = [];
            var dataSource = this.dataSource;
            var measures = dataSource.measures();
            var hasMeasure = measures.length > 1 || (measures[0] && measures[0].type);

            if (dataSource.measuresAxis() === axis) {
                if (dataSource[axis]().length === 0 || hasMeasure) {
                    result = measures;
                }
            }

            return result;
        },

        items: function() {
            return [];
        },

        refresh: function() {
            var that = this;
            var dataSource = that.dataSource;

            var axes = dataSource.axes();
            var columns = (axes.columns || {}).tuples || [];
            var rows = (axes.rows || {}).tuples || [];

            var columnBuilder = that._columnBuilder;
            var rowBuilder = that._rowBuilder;

            var columnAxis = {};
            var rowAxis = {};

            if (that.trigger(DATABINDING, { action: "rebind" } )) {
                return;
            }

            columnBuilder.measures = that._axisMeasures(AXIS_COLUMNS);
            rowBuilder.measures = that._axisMeasures(AXIS_ROWS);

            that.columnsHeaderTree.render(columnBuilder.build(columns));
            that.rowsHeaderTree.render(rowBuilder.build(rows));

            columnAxis = {
                indexes: columnBuilder._indexes,
                measures: columnBuilder.measures,
                metadata: columnBuilder.metadata
            };

            rowAxis = {
                indexes: rowBuilder._indexes,
                measures: rowBuilder.measures,
                metadata: rowBuilder.metadata
            };

            that.contentTree.render(that._contentBuilder.build(dataSource.view(), columnAxis, rowAxis));

            that._resize();

            if (that.touchScroller) {
                that.touchScroller.contentResized();
            } else {
                var touchScroller = kendo.touchScroller(that.content);

                if (touchScroller && touchScroller.movable) {
                    that.touchScroller = touchScroller;

                    touchScroller.movable.bind("change", function(e) {
                        kendo.scrollLeft(that.columnsHeader, -e.sender.x);
                        that.rowsHeader.scrollTop(-e.sender.y);
                    });
                }
            }

            that._progress(false);

            that.trigger(DATABOUND);
        },

        _scrollable: function() {
            var that = this;
            var columnsHeader = that.columnsHeader;
            var rowsHeader = that.rowsHeader;

            that.content.on("scroll", function() {
                kendo.scrollLeft(columnsHeader, this.scrollLeft);
                rowsHeader.scrollTop(this.scrollTop);
            });

            rowsHeader.on("DOMMouseScroll" + NS + " mousewheel" + NS, that._wheelScroll.bind(that));
        },

        _wheelScroll: function(e) {
            if (e.ctrlKey) {
                return;
            }

            var delta = kendo.wheelDeltaY(e);
            var scrollTop = this.content.scrollTop();

            if (delta) {
                e.preventDefault();
                //In Firefox DOMMouseScroll event cannot be canceled
                $(e.currentTarget).closest(":not(path,svg)").one("wheel" + NS, false);

                this.rowsHeader.scrollTop(scrollTop + (-delta));
                this.content.scrollTop(scrollTop + (-delta));
            }
        }
    });

    var element = kendo.dom.element;
    var htmlNode = kendo.dom.html;

    var createMetadata = function(levelNum, memberIdx) {
       return {
            maxChildren: 0,
            children: 0,
            maxMembers: 0,
            members: 0,
            measures: 1,
            levelNum: levelNum,
            parentMember: memberIdx !== 0
        };
    };

    var buildPath = function(tuple, index) {
        var path = [];
        var idx = 0;

        for (; idx <= index; idx++) {
            path.push(tuple.members[idx].name);
        }

        return path;
    };

    var tupleName = function(tuple, index) {
        var name = "";
        var idx = 0;

        for (; idx <= index; idx++) {
            name += tuple.members[idx].name;
        }

        return name;
    };

    var ContentBuilderV2 = Class.extend({
        init: function(options) {
            this.dataCellTemplate = kendo.template(options.dataCellTemplate);
            this.kpiStatusTemplate = kendo.template(options.kpiStatusTemplate);
            this.kpiTrendTemplate = kendo.template(options.kpiTrendTemplate);
            this.measures = options.measures;
            this.ariaId = options.ariaId;
            this.hash = [];
        },

        setRowColumnInfo: function(options) {
            this.data = options.data;
            this.columnHeaderLeafs = options.columnHeaderLeafs;
            this.rowHeaderLeafs = options.rowHeaderLeafs;
            this.columnHeaderBreadth = options.columnHeaderBreadth;
            this.rowHeaderDepth = options.rowHeaderDepth;
            this.hash.length = 0;
        },

        addColElements: function(count) {
            var html = "";

            for (var index = 0; index < count; index++) {
                html += "<col>";
            }

            this.table.find("colgroup").append(html);
        },

        addRowElements: function(data) {
            var that = this;
            var body = that.table.find("tbody");
            var row;

            for (var index = 0; index < data.length; index++) {
                row = $(`<tr class="k-pivotgrid-row" role='presentation'></tr>`);
                body.append(row);
                that.addColumCell(row, data[index], index);
            }

            this.rowsCount = data.length;
        },

        _getTemplate: function(cell, options) {
            const that = this;
            let measureType;

            const cellMembers = cell.columnTuple.members;
            const cellMeasure = cellMembers[cellMembers.length - 1];
            const measure = that.measures && that.measures.find((measure) => measure.name === cellMeasure.name);
            const cellValue = cell.data !== null ? cell.data.value : cell.data;

            if (measure && measure.type) {
                measureType = measure.type;
            }

            let template = this.dataCellTemplate;
            if (this.measures && measureType && cellValue !== "") {
                if (!options.dataItem) {
                    options.dataItem = { value: isNaN(Number(cellValue)) ? cellValue : Number(cellValue) };
                }
                switch (measureType) {
                    case "status":
                      template = this.kpiStatusTemplate;
                      break;
                    case "trend":
                      template = this.kpiTrendTemplate;
                      break;
                  }
            }

            return template(options);

        },

        addColumCell: function(rowEl, rowItem, rowIndex) {
            var that = this;
            for (var index = 0; index < rowItem.cells.length; index++) {
                var cell = rowItem.cells[index];
                if (cell) {
                    var cellEl = $(`<td id="${that.ariaId}-cell-${rowIndex + 1}-${index + 1}" class="k-pivotgrid-cell" role="gridcell"></td>`);
                    if (this.rowHeaderLeafs[rowIndex].total || this.columnHeaderLeafs[index].total) {
                        cellEl.addClass("k-pivotgrid-total");
                    }

                    cellEl.append(that._getTemplate(cell, {
                        dataItem: cell.data,
                        rowTuple: cell.rowTuple,
                        columnTuple: cell.columnTuple
                    }));
                    this.hash.push(cell);
                    rowEl.append(cellEl);
                }
            }
        },

        build: function() {
            var data = toData((this.data || []).slice(), this.columnHeaderLeafs, this.rowHeaderLeafs, this.columnHeaderBreadth, this.rowHeaderDepth);
            var that = this;

            var table = $(`<table class='k-pivotgrid-table' role='presentation'><colgroup></colgroup><tbody class='k-pivotgrid-tbody' role='presentation'></tbody></table>`);

            that.table = table;
            that.addColElements(this.columnHeaderLeafs.length);
            that.addRowElements(data);
            this.rowsCount = data.length;
            this.columnsCount = this.columnHeaderLeafs.length;

            return that.table;
        }
    });

    var ColumnRowBuilder = Class.extend({
        init: function(options) {
            this.tuples = options.tuples;
            this.axes = options.axes;
            this.ariaId = options.ariaId;
            this.headerTemplate = kendo.template(HEADERTEMPLATE);
            this._exportData = {};
            if (options.template) {
                this.template = kendo.template(options.template);
            }
        },

        setTuples: function(tuples) {
            this.tuples = tuples;
        },

        addColElements: function(count) {
            var html = "";

            for (var index = 0; index < count; index++) {
                html += "<col>";
            }

            this.table.find("colgroup").append(html);
        },

        addRowElements: function(columnHeaderRows) {
            var that = this;
            var body = that.table.find("tbody");
            var row;

            for (var index = 0; index < columnHeaderRows.length; index++) {
                row = $('<tr class="k-pivotgrid-row" role="row"></tr>');
                body.append(row);
                that.addColumCell(row, columnHeaderRows[index], index);
            }
        },

        _getExportData: function(rowIndex, cell, rowElement) {
            const pattern = /\[\(All\)\]/;

            if (cell.levelName.match(pattern)) {
                cell.caption = cell.caption.toUpperCase();
            }

            if (!this._exportData[rowIndex]) {
                this._exportData[rowIndex] = { children: [cell], element: rowElement };
            } else {
                this._exportData[rowIndex].children.push(cell);
            }
        },

        addColumCell: function(rowEl, rowItem, rowIndex) {
            var that = this;
            var cellEl;
            var cell;

            for (var index = 0; index < rowItem.cells.length; index++) {
                cell = rowItem.cells[index];
                if (cell) {
                    this._getExportData(rowIndex, cell, rowEl);
                    const expanded = cell.children && cell.children.length > 0;
                    cellEl = $(that.headerTemplate({
                        id: `${that.ariaId}-${that.axes == "columns" ? "ch" : "rh"}-${rowIndex + 1}-${index + 1}`,
                        rowspan: cell.rowSpan,
                        colspan: cell.colSpan,
                        key: cell.path.join(",") + (cell.total ? '|[TOTAL]' : ''),
                        iconClass: (cell.children && cell.children.length) ? "up" : "down",
                        expandable: cell.hasChildren && !cell.total,
                        expanded: expanded ? "true" : "false",
                        headerClass: kendo.format("k-pivotgrid-cell{0}{1}", cell.total ? " k-pivotgrid-header-total" : "", cell.levelNum === 0 ? " k-pivotgrid-header-root" : ""),
                        role: that.axes == "columns" ? "columnheader" : "rowheader"
                    }));
                    if (expanded) {
                        cellEl.addClass("k-pivotgrid-expanded");
                    }

                    const defaultCellTemplate = `<span class="k-pivotgrid-header-title">${cell.caption}</span>`;

                    cellEl.append(that.template ? that.template({ member: cell }) : defaultCellTemplate);
                    rowEl.append(cellEl);
                }
            }
        },

        build: function() {
            var tree = toTree((this.tuples || []).slice());
            var treeData = this.axes == "columns" ? toColumns(tree) : toRows(tree);
            var headerRows = treeData[0];
            var headerLeafs = treeData[1];
            var breadth = treeData[2];
            var rowHeaderBreadth = treeData[3];
            var that = this;
            that._tree = tree;
            that._breadth = breadth;
            that._headerLeafs = headerLeafs;

            var table = $(`<table class='k-pivotgrid-table' role='presentation'><colgroup></colgroup><tbody class='k-pivotgrid-tbody' role='rowgroup'></tbody></table>`);

            that.table = table;
            that.addColElements(this.axes == "columns" ? headerLeafs.length : rowHeaderBreadth);
            that.addRowElements(headerRows);

            return that.table;
        },

        getTree: function() {
            return this._tree;
        },

        getBreadth: function() {
            return this._breadth;
        },

        getHeaderLeafs: function() {
            return this._headerLeafs;
        }
    });

    var ColumnBuilder = Class.extend({
        init: function() {
            this.measures = 1;
            this.metadata = {};
        },

        build: function(tuples) {
            var tbody = this._tbody(tuples);
            var colgroup = this._colGroup();

            return [
                element("table", { className: tableStyles.headerTable }, [colgroup, tbody])
            ];
        },

        reset: function() {
            this.metadata = {};
        },

        _colGroup: function() {
            var length = this._rowLength();
            var children = [];
            var idx = 0;

            for (; idx < length; idx++) {
                children.push(element("col", null));
            }

            return element("colgroup", null, children);
        },

        _tbody: function(tuples) {
            var root = tuples[0];

            this.map = {};
            this.rows = [];
            this.rootTuple = root;

            this._indexes = [];

            if (root) {
                this._buildRows(root, 0);
                this._normalize();
            } else {
                this.rows.push(element("tr", { className: tableStyles.tableRow }, [ element("th", { className: tableStyles.header } , [ htmlNode("&nbsp;") ]) ]));
            }

            return element("tbody", { className: tableStyles.tbody }, this.rows);
        },

        _normalize: function() {
            var rows = this.rows;
            var rowsLength = rows.length;
            var rowIdx = 0;
            var row;

            var cellsLength;
            var cellIdx;
            var cells;
            var cell;

            for (; rowIdx < rowsLength; rowIdx++) {
                row = rows[rowIdx];

                if (row.rowSpan === 1) {
                    continue;
                }

                cells = row.children;

                cellIdx = 0;
                cellsLength = cells.length;

                for (; cellIdx < cellsLength; cellIdx++) {
                    cell = cells[cellIdx];

                    if (cell.tupleAll) {
                        cell.attr.rowSpan = row.rowSpan;
                    }
                }
            }
        },

        _rowIndex: function(row) {
            var rows = this.rows;
            var length = rows.length;
            var idx = 0;

            for (; idx < length; idx++) {
                if (rows[idx] === row) {
                    break;
                }
            }

            return idx;
        },

        _rowLength: function() {
            var cells = this.rows[0] ? this.rows[0].children : [];
            var length = cells.length;
            var rowLength = 0;
            var idx = 0;

            if (length) {
                for (; idx < length; idx++) {
                    rowLength += cells[idx].attr.colSpan || 1;
                }
            }

            if (!rowLength) {
                rowLength = this.measures;
            }

            return rowLength;
        },

        _row: function(tuple, memberIdx, parentMember) {
            var rootName = this.rootTuple.members[memberIdx].name;
            var levelNum = tuple.members[memberIdx].levelNum;
            var rowKey = rootName + levelNum;
            var map = this.map;
            var parentRow;
            var children;

            var row = map[rowKey];

            if (!row) {
                row = element("tr", { className: tableStyles.tableRow }, []);

                row.parentMember = parentMember;
                row.collapsed = 0;
                row.colSpan = 0;
                row.rowSpan = 1;

                map[rowKey] = row;
                parentRow = map[rootName + (Number(levelNum) - 1)];

                if (parentRow) {
                    children = parentRow.children;

                    if (children[1] && children[1].attr.className.indexOf("k-alt") === -1) {
                        row.notFirst = true;
                    } else {
                        row.notFirst = parentRow.notFirst;
                    }
                }

                this.rows.splice(this._rowIndex(parentRow) + 1, 0, row);
            } else {
                row.notFirst = false;

                if (!row.parentMember || row.parentMember !== parentMember) {
                    row.parentMember = parentMember;
                    row.collapsed = 0;
                    row.colSpan = 0;
                }
            }

            return row;
        },

        _measures: function(measures, tuple, className) {
            var map = this.map;
            var row = map.measureRow;
            var measure;

            if (!row) {
                row = element("tr", { className: tableStyles.tableRow }, []);
                map.measureRow = row;
                this.rows.push(row);
            }

            for (var idx = 0, length = measures.length; idx < length; idx++) {
                measure = measures[idx];
                row.children.push(this._cell((className || ""), [this._content(measure, tuple)], measure));
            }

            return length;
        },

        _content: function(member, tuple) {
            return htmlNode(this.template({
                member: member,
                tuple: tuple
            }), true);
        },

        _cell: function(className, children, member) {
            var cell = element("th", { className: tableStyles.header + " " + className }, children);
            cell.value = member.caption || member.name;
            return cell;
        },

        _buildRows: function(tuple, memberIdx, parentMember) {
            var members = tuple.members;
            var member = members[memberIdx];
            var nextMember = members[memberIdx + 1];

            var row, childRow, children, childrenLength;
            var cell, allCell;
            var cellChildren = [];
            var path;

            var idx = 0;
            var metadata;

            var colSpan;
            var collapsed = 0;
            var memberCollapsed = 0;

            if (member.measure) {
                this._measures(member.children, tuple);
                return;
            }

            path = kendo.stringify(buildPath(tuple, memberIdx));
            row = this._row(tuple, memberIdx, parentMember);

            children = member.children;
            childrenLength = children.length;

            metadata = this.metadata[path];
            if (!metadata) {
                this.metadata[path] = metadata = createMetadata(Number(member.levelNum), memberIdx);
                metadata.rootLevelNum = Number(this.rootTuple.members[memberIdx].levelNum);
            }

            this._indexes.push({
                path: path,
                tuple: tuple
            });

            if (member.hasChildren) {
                if (metadata.expanded === false) {
                    collapsed = metadata.maxChildren;
                    row.collapsed += collapsed;

                    metadata.children = 0;
                    childrenLength = 0;
                }

                let cellIconEl = $("<span></span>");
                cellIconEl.attr(kendo.attr("path"), path);

                cellChildren.push(kendo.dom.html(kendo.ui.icon(cellIconEl, { icon: childrenLength ? STATE_EXPANDED_ICONNAME : STATE_COLLAPSED_ICONNAME }), true));
            }

            cellChildren.push(this._content(member, tuple));
            cell = this._cell((row.notFirst ? " k-first" : ""), cellChildren, member);

            row.children.push(cell);
            row.colSpan += 1;

            if (childrenLength) {
                allCell = this._cell(" k-alt", [this._content(member, tuple)], member);
                row.children.push(allCell);

                for (; idx < childrenLength; idx++) {
                    childRow = this._buildRows(children[idx], memberIdx, member);
                }

                colSpan = childRow.colSpan;
                collapsed = childRow.collapsed;

                cell.attr.colSpan = colSpan;

                metadata.children = colSpan;
                metadata.members = 1;

                row.colSpan += colSpan;
                row.collapsed += collapsed;
                row.rowSpan = childRow.rowSpan + 1;

                if (nextMember) {
                    if (nextMember.measure) {
                        colSpan = this._measures(nextMember.children, tuple, " k-alt");
                    } else {
                        childRow = this._buildRows(tuple, memberIdx + 1);
                        colSpan = childRow.colSpan;

                        row.collapsed += childRow.collapsed;
                        memberCollapsed = childRow.collapsed;
                    }

                    allCell.attr.colSpan = colSpan;
                    colSpan -= 1;

                    metadata.members += colSpan;
                    row.colSpan += colSpan;
                }
            } else if (nextMember) {
                if (nextMember.measure) {
                    colSpan = this._measures(nextMember.children, tuple);
                } else {
                    childRow = this._buildRows(tuple, memberIdx + 1);
                    colSpan = childRow.colSpan;

                    row.collapsed += childRow.collapsed;
                    memberCollapsed = childRow.collapsed;
                }

                metadata.members = colSpan;

                if (colSpan > 1) {
                    cell.attr.colSpan = colSpan;
                    row.colSpan += colSpan - 1;
                }
            }

            if (metadata.maxMembers < (metadata.members + memberCollapsed)) {
                metadata.maxMembers = metadata.members + memberCollapsed;
            }

            children = metadata.children + collapsed;

            if (metadata.maxChildren < children) {
                metadata.maxChildren = children;
            }

            (allCell || cell).tupleAll = true;

            return row;
        }
    });

    var RowBuilder = Class.extend({
        init: function() {
            this.metadata = {};
        },

        build: function(tuples) {
            var tbody = this._tbody(tuples);
            var colgroup = this._colGroup();

            return [
                element("table", { className: tableStyles.table }, [colgroup, tbody])
            ];
        },

        reset: function() {
            this.metadata = {};
        },

        _rowLength: function() {
            var children = this.rows[0].children;
            var length = 0;
            var idx = 0;

            var cell = children[idx];

            while (cell) {
                length += (cell.attr.colSpan || 1);
                cell = children[++idx];
            }

            return length;
        },

        _colGroup: function() {
            var length = this._rowLength();
            var children = [];
            var idx = 0;

            for (; idx < length; idx++) {
                children.push(element("col", null));
            }

            return element("colgroup", null, children);
        },

        _tbody: function(tuples) {
            var root = tuples[0];

            this.rootTuple = root;
            this.rows = [];
            this.map = {};

            this._indexes = [];

            if (root) {
                this._buildRows(root, 0);
                this._normalize();
            } else {
                this.rows.push(element("tr", { className: tableStyles.tableRow }, [ element("td", { className: tableStyles.tableCell }, [ htmlNode("&nbsp;") ]) ]));
            }

            return element("tbody", { className: tableStyles.tbody }, this.rows);
        },

        _normalize: function() {
            var rows = this.rows;
            var rowsLength = rows.length;
            var rowIdx = 0;

            var members = this.rootTuple.members;
            var firstMemberName = members[0].name;
            var membersLength = members.length;
            var memberIdx = 0;

            var row;
            var cell;
            var maxcolSpan;
            var map = this.map;
            var allRow;

            for (; rowIdx < rowsLength; rowIdx++) {
                row = rows[rowIdx];

                for (memberIdx = 0; memberIdx < membersLength; memberIdx++) {
                    maxcolSpan = this[members[memberIdx].name];
                    cell = row.colSpan["dim" + memberIdx];

                    if (cell && cell.colSpan < maxcolSpan) {
                        cell.attr.colSpan = (maxcolSpan - cell.colSpan) + 1;
                    }
                }
            }

            row = map[firstMemberName];
            allRow = map[firstMemberName + "all"];

            if (row) {
                row.children[0].attr.className = tableStyles.tableCell + " k-first";
            }

            if (allRow) {
                allRow.children[0].attr.className += " k-first " + tableStyles.tableCell;
            }
        },

        _row: function(children) {
            var row = element("tr", { className: tableStyles.tableRow }, children);
            row.rowSpan = 1;
            row.colSpan = {};

            this.rows.push(row);

            return row;
        },

        _content: function(member, tuple) {
            return htmlNode(this.template({
                member: member,
                tuple: tuple
            }), true);
        },

        _cell: function(className, children, member) {
            var cell = element("td", { className: tableStyles.tableCell + " " + className }, children);
            cell.value = member.caption || member.name;
            return cell;
        },

        _buildRows: function(tuple, memberIdx) {
            var map = this.map;
            var path;

            var members = tuple.members;
            var member = members[memberIdx];
            var nextMember = members[memberIdx + 1];

            var children = member.children;
            var childrenLength = children.length;

            var levelNum = Number(member.levelNum);
            var rootName = this.rootTuple.members[memberIdx].name;
            var tuplePath = buildPath(tuple, memberIdx - 1).join("");
            var rootLevelNum = Number(this.rootTuple.members[memberIdx].levelNum);
            var parentName = tuplePath + (rootLevelNum === levelNum ? "" : (member.parentName || ""));
            var row = map[parentName + "all"] || map[parentName];
            var colSpan = levelNum + 1;

            var cell, allCell;
            var childRow, allRow;
            var metadata;
            var className;
            var cellChildren = [];
            var idx;

            if (!row || row.hasChild) {
                row = this._row();
            } else {
                row.hasChild = true;
            }

            if (member.measure) {
                className = row.allCell ? "k-grid-footer" : "";
                row.children.push(this._cell(className, [ this._content(children[0], tuple) ], children[0]));

                row.rowSpan = childrenLength;

                for (idx = 1; idx < childrenLength; idx++) {
                    this._row([ this._cell(className, [ this._content(children[idx], tuple) ], children[idx]) ]);
                }

                return row;
            }

            map[tuplePath + member.name] = row;

            path = kendo.stringify(buildPath(tuple, memberIdx));

            metadata = this.metadata[path];
            if (!metadata) {
                this.metadata[path] = metadata = createMetadata(levelNum, memberIdx);
                metadata.rootLevelNum = rootLevelNum;
            }

            this._indexes.push({
                path: path,
                tuple: tuple
            });

            if (member.hasChildren) {
                if (metadata.expanded === false) {
                    childrenLength = 0;
                    metadata.children = 0;
                }

                let cellIconEl = $("<span></span>");
                cellIconEl.attr(kendo.attr("path"), path);

                cellChildren.push(kendo.dom.html(kendo.ui.icon(cellIconEl, { icon: childrenLength ? STATE_EXPANDED_ICONNAME : STATE_COLLAPSED_ICONNAME }), true));
            }

            cellChildren.push(this._content(member, tuple));

            className = row.allCell && !childrenLength ? "k-grid-footer" : "";
            cell = this._cell(className, cellChildren, member);
            cell.colSpan = colSpan;

            row.children.push(cell);
            row.colSpan["dim" + memberIdx] = cell;

            if (!this[rootName] || this[rootName] < colSpan) {
                this[rootName] = colSpan;
            }

            if (childrenLength) {
                row.allCell = false;
                row.hasChild = false;

                for (idx = 0; idx < childrenLength; idx++) {
                    childRow = this._buildRows(children[idx], memberIdx);

                    if (row !== childRow) {
                        row.rowSpan += childRow.rowSpan;
                    }
                }

                if (row.rowSpan > 1) {
                    cell.attr.rowSpan = row.rowSpan;
                }

                metadata.children = row.rowSpan;

                allCell = this._cell("k-grid-footer", [this._content(member, tuple)], member);
                allCell.colSpan = colSpan;

                allRow = this._row([ allCell ]);
                allRow.colSpan["dim" + memberIdx] = allCell;
                allRow.allCell = true;

                map[tuplePath + member.name + "all"] = allRow;

                if (nextMember) {
                    childRow = this._buildRows(tuple, memberIdx + 1);
                    allCell.attr.rowSpan = childRow.rowSpan;
                }

                row.rowSpan += allRow.rowSpan;

                metadata.members = allRow.rowSpan;

            } else if (nextMember) {
                row.hasChild = false;
                this._buildRows(tuple, memberIdx + 1);

                (allCell || cell).attr.rowSpan = row.rowSpan;

                metadata.members = row.rowSpan;
            }

            if (metadata.maxChildren < metadata.children) {
                metadata.maxChildren = metadata.children;
            }

            if (metadata.maxMembers < metadata.members) {
                metadata.maxMembers = metadata.members;
            }

            return row;
        }
    });

    var ContentBuilder = Class.extend({
        init: function() {
            this.columnAxis = {};
            this.rowAxis = {};
        },

        build: function(data, columnAxis, rowAxis) {
            var index = columnAxis.indexes[0];
            var metadata = columnAxis.metadata[index ? index.path : undefined$1];

            this.columnAxis = columnAxis;
            this.rowAxis = rowAxis;

            this.data = data;

            this.rowLength = metadata ? metadata.maxChildren + metadata.maxMembers : columnAxis.measures.length || 1;

            if (!this.rowLength) {
                this.rowLength = 1;
            }

            var tbody = this._tbody();
            var colgroup = this._colGroup();

            return [
                element("table", { className: tableStyles.contentTable }, [colgroup, tbody])
            ];
        },

        _colGroup: function() {
            var length = this.columnAxis.measures.length || 1;
            var children = [];
            var idx = 0;

            if (this.rows[0]) {
                length = this.rows[0].children.length;
            }

            for (; idx < length; idx++) {
                children.push(element("col", null));
            }

            return element("colgroup", null, children);
        },

        _tbody: function() {
            this.rows = [];

            if (this.data[0]) {
                this.columnIndexes = this._indexes(this.columnAxis, this.rowLength);
                this.rowIndexes = this._indexes(this.rowAxis, Math.ceil(this.data.length / this.rowLength));

                this._buildRows();
            } else {
                this.rows.push(element("tr", { className: tableStyles.tableRow }, [ element("td", { className: tableStyles.tableCell }, [ htmlNode("&nbsp;") ]) ]));
            }

            return element("tbody", { className: tableStyles.tbody }, this.rows);
        },

        _indexes: function(axisInfo, total) {
            var result = [];
            var axisInfoMember;
            var indexes = axisInfo.indexes;
            var metadata = axisInfo.metadata;
            var measures = axisInfo.measures;
            var measuresLength = measures.length || 1;

            var current;
            var dataIdx = 0;
            var firstEmpty = 0;

            var idx = 0;
            var length = indexes.length;
            var measureIdx;

            var children;
            var skipChildren;

            if (!length) {
                for (measureIdx = 0; measureIdx < measuresLength; measureIdx++) {
                    result[measureIdx] = {
                        index: measureIdx,
                        measure: measures[measureIdx],
                        tuple: null
                    };
                }

                return result;
            }

            for (; idx < length; idx++) {
                axisInfoMember = indexes[idx];
                current = metadata[axisInfoMember.path];
                children = current.children + current.members;
                skipChildren = 0;

                if (children) {
                    children -= measuresLength;
                }

                if (current.expanded === false && current.children !== current.maxChildren) {
                    skipChildren = current.maxChildren;
                }

                if (current.parentMember && current.levelNum === current.rootLevelNum) {
                    children = -1;
                }

                if (children > -1) {
                    for (measureIdx = 0; measureIdx < measuresLength; measureIdx++) {
                        if (!current.children) ;

                        result[children + firstEmpty + measureIdx] = {
                            children: children,
                            index: dataIdx,
                            measure: measures[measureIdx],
                            tuple: axisInfoMember.tuple
                        };
                        dataIdx += 1;
                    }

                    while (result[firstEmpty] !== undefined$1) {
                        firstEmpty += 1;
                    }
                }

                if (firstEmpty === total) {
                    break;
                }

                dataIdx += skipChildren;
            }

            return result;
        },

        _buildRows: function() {
            var rowIndexes = this.rowIndexes;
            var length = rowIndexes.length;
            var idx = 0;

            for (; idx < length; idx++) {
                var rowIndex = rowIndexes[idx];
                if (rowIndex) {
                    this.rows.push(this._buildRow(rowIndex));
                }
            }
        },

        _buildRow: function(rowInfo) {
            var startIdx = rowInfo.index * this.rowLength;
            var columnIndexes = this.columnIndexes;
            var length = columnIndexes.length;
            var columnInfo;
            var cells = [];
            var idx = 0;

            var templateInfo;
            var cell, cellContent;
            var attr, dataItem, measure;

            for (; idx < length; idx++) {
                columnInfo = columnIndexes[idx];

                if (columnInfo === undefined$1) {
                    continue;
                }

                attr = { className: tableStyles.tableCell };
                if (columnInfo.children) {
                    attr.className += " k-alt";
                }

                cellContent = "";
                dataItem = this.data[startIdx + columnInfo.index];
                measure = columnInfo.measure || rowInfo.measure;

                templateInfo = {
                    columnTuple: columnInfo.tuple,
                    rowTuple: rowInfo.tuple,
                    measure: measure,
                    dataItem: dataItem
                };

                if (dataItem.value !== "" && measure && measure.type) {
                    if (measure.type === "status") {
                        cellContent = this.kpiStatusTemplate(templateInfo);
                    } else if (measure.type === "trend") {
                        cellContent = this.kpiTrendTemplate(templateInfo);
                    }
                }

                if (!cellContent) {
                    cellContent = this.dataTemplate(templateInfo);
                }

                cell = element("td", attr, [ htmlNode(cellContent) ]);
                cell.value = dataItem.value;
                cells.push(cell);
            }

            attr = { className: tableStyles.tableRow };
            if (rowInfo.children) {
                attr.className += " k-grid-footer";
            }

            return element("tr", attr, cells);
        }
    });

    ui.plugin(PivotGrid);

    kendo.PivotExcelExporter = kendo.Class.extend({
        init: function(options) {
            this.options = options;

            this.widget = options.widget;
            this.dataSource = this.widget.dataSource;
        },

        _columns: function() {
            var columnHeaderTable = this.widget.columnsHeaderTree.children[0];
            var rowHeaderTable = this.widget.rowsHeaderTree.children[0];

            var columnHeaderLength = columnHeaderTable.children[0].children.length;
            var rowHeaderLength = rowHeaderTable.children[0].children.length;

            var width = this.widget.options.columnWidth;
            var result = [];
            var idx;

            if (rowHeaderLength && this.dataSource.data()[0]) {
                for (idx = 0; idx < rowHeaderLength; idx++) {
                    result.push({
                        autoWidth: true
                    });
                }
            }

            for (idx = 0; idx < columnHeaderLength; idx++) {
                result.push({
                    autoWidth: false,
                    width: width
                });
            }

            return result;
        },

        _cells: function(rows, type, callback) {
            var result = [];

            var i = 0;
            var length = rows.length;

            var cellsLength;
            var row, cells;
            var j, cell;

            for (; i < length; i++) {
                row = [];
                cells = rows[i].children;
                cellsLength = cells.length;

                for (j = 0; j < cellsLength; j++) {
                    cell = cells[j];

                    row.push({
                        background: "#7a7a7a",
                        color: "#fff",
                        value: cell.value,
                        colSpan: cell.attr.colSpan || 1,
                        rowSpan: cell.attr.rowSpan || 1
                    });
                }

                if (callback) {
                    callback(row, i);
                }

                result.push({
                    cells: row,
                    type: type
                });
            }

            return result;
        },

        _rows: function() {
            var columnHeaderTable = this.widget.columnsHeaderTree.children[0];
            var rowHeaderTable = this.widget.rowsHeaderTree.children[0];

            var columnHeaderLength = columnHeaderTable.children[0].children.length;
            var rowHeaderLength = rowHeaderTable.children[0].children.length;

            var columnHeaderRows = columnHeaderTable.children[1].children;
            var rowHeaderRows = rowHeaderTable.children[1].children;
            var contentRows = this.widget.contentTree.children[0].children[1].children;

            var columnRows = this._cells(columnHeaderRows, "header");

            if (rowHeaderLength) {
                columnRows[0].cells.splice(0, 0, {
                    background: "#7a7a7a",
                    color: "#fff",
                    value: "",
                    colSpan: rowHeaderLength,
                    rowSpan: columnHeaderRows.length
                });
            }

            var dataCallback = function(row, index) {
                var j = 0;
                var cell, value;
                var cells = contentRows[index].children;

                for (; j < columnHeaderLength; j++) {
                    cell = cells[j];
                    value = Number(cell.value);

                    if (isNaN(value)) {
                        value = cell.value;
                    }

                    row.push({
                        background: "#dfdfdf",
                        color: "#333",
                        value: value,
                        colSpan: 1,
                        rowSpan: 1
                    });
                }
            };

            var rowRows = this._cells(rowHeaderRows, "data", dataCallback);

            return columnRows.concat(rowRows);
        },

        _freezePane: function() {
            var columnHeaderTable = this.widget.columnsHeaderTree.children[0];
            var rowHeaderTable = this.widget.rowsHeaderTree.children[0];

            var rowHeaderLength = rowHeaderTable.children[0].children.length;
            var columnHeaderRows = columnHeaderTable.children[1].children;

            return {
                colSplit: rowHeaderLength,
                rowSplit: columnHeaderRows.length
            };
        },

        _columnsV2: function() {
            const columnHeaderTable = this.widget._columnBuilder.table[0];
            const rowHeaderTable = this.widget._rowBuilder.table[0];

            const columnHeaderLength = columnHeaderTable.children[0].children.length;
            const rowHeaderLength = rowHeaderTable.children[0].children.length;

            const width = this.widget.options.columnWidth;
            const result = [];

            if (rowHeaderLength && this.dataSource.data()[0]) {
                for (let idx = 0; idx < rowHeaderLength; idx++) {
                    result.push({
                        autoWidth: true
                    });
                }
            }

            for (let idx = 0; idx < columnHeaderLength; idx++) {
                result.push({
                    autoWidth: false,
                    width: width
                });
            }

            return result;
        },

        _cellsV2: function(rows, type, callback) {
            const result = [];

            const length = Object.keys(rows).length;

            for (let i = 0; i < length; i++) {
                const row = [];
                const cells = rows[i].children;
                const cellsLength = cells.length;

                for (let j = 0; j < cellsLength; j++) {
                    const cell = cells[j];

                    row.push({
                        background: "#7a7a7a",
                        color: "#fff",
                        value: cell.caption,
                        colSpan: cell.colSpan || 1,
                        rowSpan: cell.rowSpan || 1
                    });
                }

                if (callback) {
                    callback(row, i);
                }

                result.push({
                    cells: row,
                    type: type
                });
            }

            return result;
        },

        _rowsV2: function() {
            const columnHeaderTable = this.widget._columnBuilder.table[0];
            const rowHeaderTable = this.widget._rowBuilder.table[0];

            const columnHeaderLength = columnHeaderTable.children[0].children.length;
            const rowHeaderLength = rowHeaderTable.children[0].children.length;

            const columnHeaderRows = this.widget._columnBuilder._exportData;
            const rowHeaderRows = this.widget._rowBuilder._exportData;
            const contentCells = this.widget._contentBuilder.hash;

            const columnRows = this._cellsV2(columnHeaderRows, "header");

            if (rowHeaderLength) {
                columnRows[0].cells.splice(0, 0, {
                    background: "#7a7a7a",
                    color: "#fff",
                    value: "",
                    colSpan: rowHeaderLength,
                    rowSpan: Object.keys(columnHeaderRows).length
                });
            }

            const dataCallback = function(row, index) {
                const startingIndex = index * columnHeaderLength;
                const endIndex = (index + 1) * columnHeaderLength;

                for (let j = startingIndex; j < endIndex; j++) {
                    const cell = contentCells[j];

                    const cellValue = cell.data !== null ? cell.data.value : cell.data;
                    let value = Number(cellValue);

                    if (isNaN(value)) {
                        value = cellValue;
                    }

                    row.push({
                        background: "#dfdfdf",
                        color: "#333",
                        value: value,
                        colSpan: 1,
                        rowSpan: 1
                    });
                }
            };

            const rowRows = this._cellsV2(rowHeaderRows, "data", dataCallback);

            return columnRows.concat(rowRows);
        },


        _freezePaneV2: function() {
            const columnHeaderTable = this.widget._columnBuilder.table[0];
            const rowHeaderTable = this.widget._rowBuilder.table[0];

            const rowHeaderLength = rowHeaderTable.children[0].children.length;
            const columnHeaderRows = columnHeaderTable.children[1].children.length;

            return {
                colSplit: rowHeaderLength,
                rowSplit: columnHeaderRows
            };
        },

        _filterV2: function() {
            const that = this;

            if (!that.options.excel.filterable) {
                return null;
            }

            const columnHeaderTable = this.widget._columnBuilder.table[0];
            const rowHeaderTable = this.widget._rowBuilder.table[0];

            const rowHeaderLength = rowHeaderTable.children[0].children.length;
            const columnHeaderLength = columnHeaderTable.children[0].children.length;

            const additionalRows = rowHeaderLength - 1;

            return {
                from: rowHeaderLength,
                to: columnHeaderLength + additionalRows
            };
        },


        workbook: function() {
            var promise,
                resolveFn = function() {
                    if (this.widget.options.name === "PivotGridV2") {
                        return {
                            sheets: [ {
                                columns: this._columnsV2(),
                                rows: this._rowsV2(),
                                freezePane: this._freezePaneV2(),
                                filter: this._filterV2(),
                            } ]
                        };
                    }
                    return {
                        sheets: [ {
                            columns: this._columns(),
                            rows: this._rows(),
                            freezePane: this._freezePane(),
                            filter: null
                        } ]
                    };
                };

            if (this.dataSource.view()[0]) {
                promise = $.Deferred();
                promise.resolve();
            } else {
                promise = this.dataSource.fetch();
            }

            return promise.then(resolveFn.bind(this));
        }
    });

    var PivotExcelMixin = {
        extend: function(proto) {
           proto.events.push("excelExport");
           proto.options.excel = $.extend(proto.options.excel, this.options);
           proto.saveAsExcel = this.saveAsExcel;
        },
        options: {
            proxyURL: "",
            filterable: false,
            fileName: "Export.xlsx"
        },
        saveAsExcel: function() {
            var excel = this.options.excel || {};

            var exporter = new kendo.PivotExcelExporter({
                widget: this,
                excel
            });

            if (this._progress) {
                this._isExport = true;
                this._progress(true);
            }

            var resolveFn = function(book) {
                if (!this.trigger("excelExport", { workbook: book })) {
                    var workbook = new kendo.ooxml.Workbook(book);

                    workbook.toDataURLAsync().then(function(dataURI) {
                        kendo.saveAs({
                            dataURI: dataURI,
                            fileName: book.fileName || excel.fileName,
                            proxyURL: excel.proxyURL,
                            forceProxy: excel.forceProxy
                        });
                    }).always(() => {
                        if (this._progress) {
                            this._progress(false);
                            this._isExport = false;
                        }
                    });
                }
            };

            exporter.workbook().then(resolveFn.bind(this));
        }
    };

    kendo.PivotExcelMixin = PivotExcelMixin;

    if (kendo.ooxml && kendo.ooxml.Workbook) {
        PivotExcelMixin.extend(PivotGrid.prototype);
    }

    if (kendo.ooxml && kendo.ooxml.Workbook) {
        PivotExcelMixin.extend(PivotGridV2.prototype);
    }

    if (kendo.PDFMixin) {
        kendo.PDFMixin.extend(PivotGrid.prototype);

        PivotGrid.fn._drawPDF = function() {
            return this._drawPDFShadow({
                width: this.wrapper.width()
            }, {
                avoidLinks: this.options.pdf.avoidLinks
            });
        };
    }

    if (kendo.PDFMixin) {
        kendo.PDFMixin.extend(PivotGridV2.prototype);

        PivotGridV2.prototype._saveAsPDF = kendo.PDFMixin.saveAsPDF;

        PivotGridV2.fn.saveAsPDF = function() {
            if (this._progress) {
                this._isExport = true;
                this._progress(true);
            }
            this._saveAsPDF().always(() => {
                if (this._progress) {
                    this._progress(false);
                    this._isExport = false;
                }
            });
        };

        PivotGridV2.fn._drawPDF = function() {
            return this._drawPDFShadow({
                width: this.wrapper.width()
            }, {
                avoidLinks: this.options.pdf.avoidLinks
            });
        };
    }

    window.kendo.pivotgrid = window.kendo.pivotgrid || {};
    window.kendo.pivotgrid.common = {
        addKPI: addKPI,
        addMultipleMeasures: addMultipleMeasures,
        averageAggregate: averageAggregate,
        buildKPIMeasures: buildKPIMeasures,
        cloneDataTree: cloneDataTree,
        compareAxes: compareAxes,
        configuratorReducer: configuratorReducer,
        createAxisDescriptors: createAxisDescriptors,
        createDataState: createDataState,
        createDataTree: createDataTree,
        createDiscoverBody: createDiscoverBody,
        createFlatSchemaDimensions: createFlatSchemaDimensions,
        createLocalDataState: createLocalDataState,
        createRequestBody: createRequestBody,
        createTuples: createTuples,
        discoverCommands: discoverCommands,
        fetchData: fetchData,
        fetchDiscover: fetchDiscover,
        headersReducer: headersReducer,
        maxAggregate: maxAggregate,
        mergeTrees: mergeTrees,
        minAggregate: minAggregate,
        parseResponse: parseResponse,
        readData: readData,
        rootFields: rootFields,
        setFilter: setFilter,
        setSort: setSort,
        sumAggregate: sumAggregate,
        toColumns: toColumns,
        toData: toData,
        toRows: toRows,
        toTree: toTree,
    };

})(window.kendo.jQuery);
var kendo$1 = kendo;

export { __meta__, kendo$1 as default };