UNPKG

@progress/kendo-ui

Version:

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

1,570 lines (1,391 loc) 83.6 kB
module.exports = /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ({ /***/ 0: /***/ (function(module, exports, __webpack_require__) { __webpack_require__(1531); module.exports = __webpack_require__(1531); /***/ }), /***/ 3: /***/ (function(module, exports) { module.exports = function() { throw new Error("define cannot be used indirect"); }; /***/ }), /***/ 1485: /***/ (function(module, exports) { module.exports = require("./runtime"); /***/ }), /***/ 1522: /***/ (function(module, exports) { module.exports = require("../util/main"); /***/ }), /***/ 1531: /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// -*- fill-column: 100 -*- (function(f, define){ !(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(1485), __webpack_require__(1522) ], __WEBPACK_AMD_DEFINE_FACTORY__ = (f), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); })(function(){ "use strict"; if (kendo.support.browser.msie && kendo.support.browser.version < 9) { return; } // WARNING: removing the following jshint declaration and turning // == into === to make JSHint happy will break functionality. /* jshint eqnull:true, newcap:false, laxbreak:true, validthis:true */ /* jshint latedef:false */ var util = kendo.util; var spreadsheet = kendo.spreadsheet; var calc = spreadsheet.calc; var runtime = calc.runtime; var defineFunction = runtime.defineFunction; var defineAlias = runtime.defineAlias; var CalcError = runtime.CalcError; var RangeRef = spreadsheet.RangeRef; var CellRef = spreadsheet.CellRef; var UnionRef = spreadsheet.UnionRef; var Matrix = runtime.Matrix; var Ref = spreadsheet.Ref; var daysInMonth = runtime.daysInMonth; var packDate = runtime.packDate; var unpackDate = runtime.unpackDate; var daysInYear = runtime.daysInYear; /* -----[ Math functions ]----- */ [ "abs", "cos", "sin", "acos", "asin", "tan", "atan", "exp", "sqrt" ].forEach(function(name){ defineFunction(name, Math[name]).args([ [ "*n", "number" ] ]); }); defineFunction("ln", Math.log).args([ [ "*n", "number" ] ]); defineFunction("log", function(num, base){ return Math.log(num) / Math.log(base); }).args([ [ "*num", "number++" ], [ "*base", [ "or", "number++", [ "null", 10 ] ] ], [ "?", [ "assert", "$base != 1", "DIV/0" ] ] ]); defineFunction("log10", function(num){ return Math.log(num) / Math.log(10); }).args([ [ "*num", "number++" ] ]); defineFunction("pi", function(){ return Math.PI; }).args([]); defineFunction("sqrtpi", function(n){ return Math.sqrt(n * Math.PI); }).args([ [ "*num", "number+" ] ]); defineFunction("degrees", function(rad){ return ((180 * rad) / Math.PI) % 360; }).args([ [ "*radians", "number" ] ]); defineFunction("radians", function(deg){ return Math.PI * deg / 180; }).args([ [ "*degrees", "number" ] ]); function _cosh(n){ return (Math.exp(n) + Math.exp(-n)) / 2; } defineFunction("cosh", _cosh).args([ [ "*num", "number" ] ]); defineFunction("acosh", function(n){ return Math.log(n + Math.sqrt(n - 1) * Math.sqrt(n + 1)); }).args([ [ "*num", "number" ], [ "?", [ "assert", "$num >= 1" ] ] ]); function _sinh(n){ return (Math.exp(n) - Math.exp(-n)) / 2; } defineFunction("sinh", _sinh).args([ [ "*num", "number" ] ]); defineFunction("asinh", function(n){ return Math.log(n + Math.sqrt(n * n + 1)); }).args([ [ "*num", "number" ] ]); defineFunction("sec", function(n){ return 1 / Math.cos(n); }).args([ [ "*num", "number" ] ]); defineFunction("sech", function(n){ return 1 / _cosh(n); }).args([ [ "*num", "number" ] ]); defineFunction("csc", function(n){ return 1 / Math.sin(n); }).args([ [ "*num", "number" ] ]); defineFunction("csch", function(n){ return 1 / _sinh(n); }).args([ [ "*num", "number" ] ]); defineFunction("atan2", function(x, y){ return Math.atan(y / x); }).args([ [ "*x", "divisor" ], [ "*y", "number" ] ]); function _tanh(n) { return _sinh(n) / _cosh(n); } defineFunction("tanh", _tanh).args([ [ "*num", "number" ] ]); defineFunction("atanh", function(n){ return Math.log(Math.sqrt(1 - n*n) / (1 - n)); }).args([ [ "*num", [ "and", "number", [ "(between)", -1, 1 ] ] ] ]); defineFunction("cot", function(n){ return 1 / Math.tan(n); }).args([ [ "*num", "divisor" ] ]); defineFunction("coth", function(n){ return 1 / _tanh(n); }).args([ [ "*num", "divisor" ] ]); defineFunction("acot", function(n){ return Math.PI / 2 - Math.atan(n); }).args([ [ "*num", "number" ] ]); defineFunction("acoth", function(n){ return Math.log((n + 1) / (n - 1)) / 2; }).args([ [ "*num", "number" ], [ "?", [ "or", [ "assert", "$num < -1"], [ "assert", "$num > 1" ] ] ] ]); defineFunction("power", function(a, b){ return Math.pow(a, b); }).args([ [ "*a", "number" ], [ "*b", "number" ] ]); defineFunction("mod", function(a, b){ return a % b; }).args([ [ "*a", "number" ], [ "*b", "divisor" ] ]); defineFunction("quotient", function(a, b){ return Math.floor(a / b); }).args([ [ "*a", "number" ], [ "*b", "divisor" ] ]); defineFunction("ceiling", function(num, s){ return s ? s * Math.ceil(num / s) : 0; }).args([ [ "*number", "number" ], [ "*significance", "number" ], [ "?", [ "assert", "$significance >= 0 || $number < 0" ] ] ]); defineFunction("ceiling.precise", function(num, s){ s = Math.abs(s); return s ? s * Math.ceil(num / s) : 0; }).args([ [ "*number", "number" ], [ "*significance", [ "or", "number", [ "null", 1 ] ] ] ]); defineAlias("iso.ceiling", "ceiling.precise"); // XXX: how do we know if this function is correct? // // https://support.office.com/en-gb/article/CEILING-MATH-function-80f95d2f-b499-4eee-9f16-f795a8e306c8 // // “There are many combinations of Significance and Mode values that affect rounding of negative // numbers in different ways.” — right, thanks for the info. :-\ defineFunction("ceiling.math", function(num, s, mode){ if (!s || !num) { return 0; } if (num < 0 && ((!mode && s < 0) || (mode && s > 0))) { s = -s; } return s ? s * Math.ceil(num / s) : 0; }).args([ [ "*number", "number" ], [ "*significance", [ "or", "number", [ "null", "$number < 0 ? -1 : 1" ] ] ], [ "*mode", [ "or", "logical", [ "null", 0 ] ] ] ]); defineFunction("floor", function(num, s){ return s ? s * Math.floor(num / s) : 0; }).args([ [ "*number", "number" ], [ "*significance", "number" ], [ "?", [ "assert", "$significance >= 0 || $number < 0" ] ] ]); defineFunction("floor.precise", function(num, s){ s = Math.abs(s); return s ? s * Math.floor(num / s) : 0; }).args([ [ "*number", "number" ], [ "*significance", [ "or", "number", [ "null", 1 ] ] ] ]); // XXX: check this defineFunction("floor.math", function(num, s, mode){ if (!s || !num) { return 0; } if (num < 0 && ((!mode && s < 0) || (mode && s > 0))) { s = -s; } return s ? s * Math.floor(num / s) : 0; }).args([ [ "*number", "number" ], [ "*significance", [ "or", "number", [ "null", "$number < 0 ? -1 : 1" ] ] ], [ "*mode", [ "or", "logical", [ "null", 0 ] ] ] ]); defineFunction("int", Math.floor).args([ [ "*number", "number" ] ]); defineFunction("mround", function(num, mult){ return mult ? mult * Math.round(num / mult) : 0; }).args([ [ "*number", "number" ], [ "*multiple", "number" ] ]); defineFunction("round", function(num, digits){ var sign = num < 0 ? -1 : 1; if (sign < 0) { num = -num; } digits = Math.pow(10, digits); num *= digits; num = Math.round(num); return sign * num / digits; }).args([ [ "*number", "number" ], [ "*digits", "number" ] ]); defineFunction("roundup", function(num, digits){ digits = Math.pow(10, digits); num *= digits; num = num < 0 ? Math.floor(num) : Math.ceil(num); return num / digits; }).args([ [ "*number", "number" ], [ "*digits", "number" ] ]); defineFunction("rounddown", function(num, digits){ digits = Math.pow(10, digits); num *= digits; num = num < 0 ? Math.ceil(num) : Math.floor(num); return num / digits; }).args([ [ "*number", "number" ], [ "*digits", "number" ] ]); defineFunction("even", function(num){ var n = num < 0 ? Math.floor(num) : Math.ceil(num); return n % 2 ? n + (n < 0 ? -1 : 1) : n; }).args([ [ "*number", "number" ] ]); defineFunction("odd", function(num){ var n = num < 0 ? Math.floor(num) : Math.ceil(num); return n % 2 ? n : n + (n < 0 ? -1 : 1); }).args([ [ "*number", "number" ] ]); defineFunction("sign", function(num){ return num < 0 ? -1 : num > 0 ? 1 : 0; }).args([ [ "*number", "number" ] ]); function _gcd(a, b) { while (b) { var r = a % b; a = b; b = r; } return a; } function _lcm(a, b) { return Math.abs(a * b) / _gcd(a, b); } defineFunction("gcd", function(args){ var a = args[0]; for (var i = 1; i < args.length; ++i) { a = _gcd(a, args[i]); } return a; }).args([ [ "numbers", [ "collect", "number" ] ] ]); defineFunction("lcm", function(args){ var a = args[0]; for (var i = 1; i < args.length; ++i) { a = _lcm(a, args[i]); } return a; }).args([ [ "numbers", [ "collect", "number" ] ] ]); defineFunction("sum", function(numbers){ return numbers.reduce(function(sum, num){ return sum + num; }, 0); }).args([ [ "numbers", [ "collect", "number" ] ] ]); defineFunction("product", function(numbers){ return numbers.reduce(function(prod, num){ return prod * num; }, 1); }).args([ [ "numbers", [ "collect", "number" ] ] ]); defineFunction("sumproduct", function(first, rest) { var sum = 0; first.each(function(p, row, col){ if (typeof p == "number") { for (var i = 0; i < rest.length; ++i) { var v = rest[i].get(row, col); if (typeof v != "number") { return; } p *= v; } sum += p; } }); return sum; }).args([ [ "a1", "matrix" ], [ "+", [ "a2", [ "and", "matrix", [ "assert", "$a2.width == $a1.width" ], [ "assert", "$a2.height == $a1.height" ] ] ] ] ]); defineFunction("sumsq", function(numbers){ return numbers.reduce(function(sum, num){ return sum + num * num; }, 0); }).args([ [ "numbers", [ "collect", "number" ] ] ]); defineFunction("sumx2my2", function(a, b){ var sum = 0; a.each(function(x, row, col){ var y = b.get(row, col); if (typeof x == "number" && typeof y == "number") { sum += x*x - y*y; } }); return sum; }).args([ [ "a", "matrix" ], [ "b", [ "and", "matrix", [ "assert", "$b.width == $a.width" ], [ "assert", "$b.height == $a.height" ] ] ] ]); defineFunction("sumx2py2", function(a, b){ var sum = 0; a.each(function(x, row, col){ var y = b.get(row, col); if (typeof x == "number" && typeof y == "number") { sum += x*x + y*y; } }); return sum; }).args([ [ "a", "matrix" ], [ "b", [ "and", "matrix", [ "assert", "$b.width == $a.width" ], [ "assert", "$b.height == $a.height" ] ] ] ]); defineFunction("sumxmy2", function(a, b){ var sum = 0; a.each(function(x, row, col){ var y = b.get(row, col); if (typeof x == "number" && typeof y == "number") { sum += (x - y) * (x - y); } }); return sum; }).args([ [ "a", "matrix" ], [ "b", [ "and", "matrix", [ "assert", "$b.width == $a.width" ], [ "assert", "$b.height == $a.height" ] ] ] ]); defineFunction("seriessum", function(x, n, m, a){ var sum = 0; a.each(function(coef){ if (typeof coef != "number") { throw new CalcError("VALUE"); } sum += coef * Math.pow(x, n); n += m; }); return sum; }).args([ [ "x", "number" ], [ "y", "number" ], [ "m", "number" ], [ "a", "matrix" ] ]); defineFunction("min", function(numbers){ return numbers.length ? Math.min.apply(Math, numbers) : 0; }).args([ [ "numbers", [ "collect", "number" ] ] ]); defineFunction("max", function(numbers){ return numbers.length ? Math.max.apply(Math, numbers) : 0; }).args([ [ "numbers", [ "collect", "number" ] ] ]); defineFunction("counta", function(values){ return values.length; }).args([ [ "values", [ "#collect", "anyvalue" ] ] ]); defineFunction("count", function(numbers){ return numbers.length; }).args([ [ "numbers", [ "#collect", "number" ] ] ]); defineFunction("countunique", function(values){ var count = 0, seen = []; values.forEach(function(val){ if (seen.indexOf(val) < 0) { count++; seen.push(val); } }); return count; }).args([ [ "values", [ "#collect", "anyvalue" ] ] ]); defineFunction("countblank", function(a){ var count = 0; function add(val) { if (val == null || val === "") { count++; } } function loop(args){ for (var i = 0; i < args.length; ++i) { var x = args[i]; if (x instanceof Matrix) { x.each(add, true); } else { add(x); } } } loop(a); return count; }).args([ [ "+", [ "args", [ "or", "matrix", "anyvalue" ] ] ] ]); defineFunction("iseven", function(num){ return num % 2 === 0; }).args([ [ "*number", "number" ] ]); defineFunction("isodd", function(num){ return num % 2 !== 0; }).args([ [ "*number", "number" ] ]); defineFunction("n", function(val){ if (typeof val == "boolean") { return val ? 1 : 0; } if (typeof val == "number") { return val; } return 0; }).args([ [ "*value", "anyvalue" ] ]); defineFunction("na", function(){ return new CalcError("N/A"); }).args([]); /* -----[ the "*IFS" functions ]----- */ // helper function: take `args` like COUNTIFS (see Excel docs) and // calls `f` for each cell matching all criteria. `f` receives // `chunks` (parsed args containing matrix and predicate) and // row,col of matching cells. function forIFS(args, f) { var chunks = [], i = 0, matrix = args[0]; while (i < args.length) { chunks.push({ matrix: args[i++], pred: parseCriteria(args[i++]) }); } ROW: for (var row = 0; row < matrix.height; ++row) { COL: for (var col = 0; col < matrix.width; ++col) { for (i = 0; i < chunks.length; ++i) { var val = chunks[i].matrix.get(row, col); if (!chunks[i].pred(val == null || val === "" ? 0 : val)) { continue COL; } } f(row, col); } } } var ARGS_COUNTIFS = [ [ "m1", "matrix" ], [ "c1", "anyvalue" ], [ [ "m2", "matrix" ], [ "c2", "anyvalue" ] ] ]; defineFunction("countifs", function(m1, c1, rest){ var count = 0; rest.unshift(m1, c1); forIFS(rest, function(){ count++; }); return count; }).args(ARGS_COUNTIFS); var ARGS_SUMIFS = [ [ "range", "matrix" ] ].concat(ARGS_COUNTIFS); defineFunction("sumifs", function(range, m1, c1, args){ // hack: insert a predicate that filters out non-numeric // values; should also accept blank cells. it's safe to // modify args. args.unshift(range, numericPredicate, m1, c1); var sum = 0; forIFS(args, function(row, col){ var val = range.get(row, col); if (val) { sum += val; } }); return sum; }).args(ARGS_SUMIFS); // similar to sumifs, but compute average of matching cells defineFunction("averageifs", function(range, m1, c1, args){ args.unshift(range, numericPredicate, m1, c1); var sum = 0, count = 0; forIFS(args, function(row, col){ var val = range.get(row, col); if (val == null || val === "") { val = 0; } sum += val; count++; }); return count ? sum / count : new CalcError("DIV/0"); }).args(ARGS_SUMIFS); defineFunction("countif", function(matrix, criteria){ criteria = parseCriteria(criteria); var count = 0; matrix.each(function(val){ if (criteria(val)) { count++; } }); return count; }).args([ [ "range", "matrix" ], [ "*criteria", "anyvalue" ] ]); var ARGS_SUMIF = [ [ "range", "matrix" ], [ "*criteria", "anyvalue" ], [ "sumRange", [ "or", [ "and", "matrix", [ "assert", "$sumRange.width == $range.width" ], [ "assert", "$sumRange.height == $range.height" ] ], [ "null", "$range" ] ] ] ]; defineFunction("sumif", function(range, criteria, sumRange){ var sum = 0; criteria = parseCriteria(criteria); range.each(function(val, row, col){ if (criteria(val)) { var v = sumRange.get(row, col); if (numericPredicate(v)) { sum += v || 0; } } }); return sum; }).args(ARGS_SUMIF); defineFunction("averageif", function(range, criteria, sumRange){ var sum = 0, count = 0; criteria = parseCriteria(criteria); range.each(function(val, row, col){ if (criteria(val)) { var v = sumRange.get(row, col); if (numericPredicate(v)) { sum += v || 0; count++; } } }); return count ? sum / count : new CalcError("DIV/0"); }).args(ARGS_SUMIF); (function(def){ def("large", function(numbers, nth){ return numbers.sort(descending)[nth]; }); def("small", function(numbers, nth){ return numbers.sort(ascending)[nth]; }); })(function(name, handler){ defineFunction(name, function(matrix, nth){ var numbers = []; var error = matrix.each(function(val){ if (val instanceof CalcError) { return val; } if (typeof val == "number") { numbers.push(val); } }); if (error) { return error; } if (nth > numbers.length) { return new CalcError("NUM"); } return handler(numbers, nth - 1); }).args([ [ "array", "matrix" ], [ "*nth", "number++" ] ]); }); function _avg(numbers) { return numbers.reduce(function(sum, num){ return sum + num; }, 0) / numbers.length; } function _var_sp(numbers, divisor, avg) { if (avg == null) { avg = _avg(numbers); } return numbers.reduce(function(sum, num){ return sum + Math.pow(num - avg, 2); }, 0) / divisor; } function _stdev_sp(numbers, divisor) { return Math.sqrt(_var_sp(numbers, divisor)); } // https://support.office.com/en-sg/article/STDEV-S-function-7d69cf97-0c1f-4acf-be27-f3e83904cc23 defineFunction("stdev.s", function(numbers){ return _stdev_sp(numbers, numbers.length - 1); }).args([ [ "numbers", [ "collect", "number" ] ], [ "?", [ "assert", "$numbers.length >= 2", "NUM" ] ] ]); // https://support.office.com/en-sg/article/STDEV-P-function-6e917c05-31a0-496f-ade7-4f4e7462f285 defineFunction("stdev.p", function(numbers){ return _stdev_sp(numbers, numbers.length); }).args([ [ "numbers", [ "collect", "number" ] ], [ "?", [ "assert", "$numbers.length >= 2", "NUM" ] ] ]); defineFunction("var.s", function(numbers){ return _var_sp(numbers, numbers.length - 1); }).args([ [ "numbers", [ "collect", "number" ] ], [ "?", [ "assert", "$numbers.length >= 2", "NUM" ] ] ]); defineFunction("var.p", function(numbers){ return _var_sp(numbers, numbers.length); }).args([ [ "numbers", [ "collect", "number" ] ], [ "?", [ "assert", "$numbers.length >= 2", "NUM" ] ] ]); defineFunction("median", function(numbers){ var n = numbers.length; numbers.sort(ascending); if (n % 2) { // when length is odd, the median is the number in the middle return numbers[n >> 1]; } // that's the average of the two middle numbers, written in in a fancy way return (numbers[n >>= 1] + numbers[n - 1]) / 2; }).args([ [ "numbers", [ "collect", "number" ] ], [ "?", [ "assert", "$numbers.length > 0", "N/A" ] ] ]); defineFunction("mode.sngl", function(numbers){ numbers.sort(ascending); var prev = null, count = 0, max = 1, mode = null; for (var i = 0; i < numbers.length; ++i) { var n = numbers[i]; if (n != prev) { count = 1; prev = n; } else { count++; } if (count > max) { max = count; mode = n; } } return mode == null ? new CalcError("N/A") : mode; }).args([ [ "numbers", [ "collect", "number" ] ] ]); defineFunction("mode.mult", function(numbers){ var seen = Object.create(null), max = 2, res = []; numbers.forEach(function(num){ var s = seen[num] || 0; seen[num] = ++s; if (s == max) { res.push(num); } else if (s > max) { max = s; res = [ num ]; } }); var m = new Matrix(this); res.forEach(function(num, i){ m.set(i, 0, num); }); return m; }).args([ [ "numbers", [ "collect", "number" ] ] ]); defineFunction("geomean", function(numbers){ var n = numbers.length; var p = numbers.reduce(function(p, num){ if (num < 0) { throw new CalcError("NUM"); } return p * num; }, 1); return Math.pow(p, 1/n); }).args([ [ "numbers", [ "collect", "number" ] ], [ "?", [ "assert", "$numbers.length > 0", "NUM" ] ] ]); defineFunction("harmean", function(numbers){ var n = numbers.length; var s = numbers.reduce(function(s, num){ if (!num) { throw new CalcError("DIV/0"); } return s + 1 / num; }, 0); return n / s; }).args([ [ "numbers", [ "collect", "number" ] ], [ "?", [ "assert", "$numbers.length > 0", "NUM" ] ] ]); defineFunction("trimmean", function(numbers, p){ var n = numbers.length; numbers.sort(ascending); var discard = Math.floor(n * p); if (discard % 2) { --discard; } discard /= 2; var sum = 0; for (var i = discard; i < n-discard; ++i) { sum += numbers[i]; } return sum / (n - discard * 2); }).args([ [ "numbers", [ "collect", "number", 1 ] ], [ "percent", [ "and", "number", [ "[between)", 0, 1 ] ] ], [ "?", [ "assert", "$numbers.length > 0", "NUM" ] ] ]); defineFunction("frequency", function(data, bins){ // apparently this always returns a vertical matrix in Excel, so we collect all numbers in // bins instead of receiving it as a Matrix and try to mimic its shape. data.sort(ascending); bins.sort(ascending); var prev = -Infinity; var i = 0; function count(max) { var n = 0; while (i < data.length && data[i] > prev && data[i] <= max) { ++n; ++i; } return n; } var m = new Matrix(this); bins.forEach(function(val, i){ var n = count(val); prev = val; m.set(i, 0, n); }); m.set(m.height, 0, data.length - i); return m; }).args([ [ "data", [ "collect", "number", 1 ] ], [ "bins", [ "collect", "number", 1 ] ] ]); defineFunction("rank.eq", function(val, numbers, asc) { numbers.sort(asc ? ascending : descending); var pos = numbers.indexOf(val); return pos < 0 ? new CalcError("N/A") : pos + 1; }).args([ [ "value", "number" ], [ "numbers", [ "collect", "number" ] ], [ "order", [ "or", "logical", [ "null", false ] ] ] ]); defineAlias("rank", "rank.eq"); defineFunction("rank.avg", function(val, numbers, asc) { numbers.sort(asc ? ascending : descending); var pos = numbers.indexOf(val); if (pos < 0) { return new CalcError("N/A"); } for (var i = pos; numbers[i] == val; ++i){} return (pos + i + 1) / 2; }).args([ [ "value", "number" ], [ "numbers", [ "collect", "number" ] ], [ "order", [ "or", "logical", [ "null", false ] ] ] ]); // formula available at https://support.office.microsoft.com/en-us/article/KURT-function-cbbc2312-dfa6-4cc4-b5c0-1b3c59cc9377 defineFunction("kurt", function(numbers){ var n = numbers.length; var avg = _avg(numbers); var variance = _var_sp(numbers, n-1, avg); var stddev = Math.sqrt(variance); var sum = numbers.reduce(function(sum, num){ return sum + Math.pow((num - avg) / stddev, 4); }, 0); return n*(n+1)/((n-1)*(n-2)*(n-3)) * sum - 3*Math.pow(n-1, 2)/((n-2)*(n-3)); }).args([ [ "numbers", [ "collect", "number" ] ], [ "?", [ "assert", "$numbers.length >= 4", "NUM" ] ] ]); function _percentrank(numbers, x, exc) { var nlt = 0, ngt = 0, left = null, right = null, found = false; numbers.forEach(function(num){ if (num < x) { nlt++; left = left == null ? num : Math.max(left, num); } else if (num > x) { ngt++; right = right == null ? num : Math.min(right, num); } else { found = true; } }); if (!nlt && !ngt) { return new CalcError("N/A"); } if (found) { if (exc) { return (nlt + 1) / (numbers.length + 1); } return nlt / (nlt + ngt); } return ((right - x) * _percentrank(numbers, left, exc) + (x - left) * _percentrank(numbers, right, exc)) / (right - left); } var ARGS_PERCENTRANK = [ [ "array", [ "collect", "number", 1 ] ], [ "x", "number" ], [ "significance", [ "or", [ "null", 3 ], "integer++" ] ], [ "?", [ "assert", "$array.length > 0", "NUM" ] ] ]; defineFunction("percentrank.inc", function(numbers, x, significance) { var p = _percentrank(numbers, x, 0); p = p.toFixed(significance + 1); return parseFloat(p.substr(0, p.length - 1)); }).args(ARGS_PERCENTRANK); defineFunction("percentrank.exc", function(numbers, x, significance) { var p = _percentrank(numbers, x, 1); p = p.toFixed(significance + 1); return parseFloat(p.substr(0, p.length - 1)); }).args(ARGS_PERCENTRANK); defineAlias("percentrank", "percentrank.inc"); function _covariance(x, y, divisor) { var sum = 0; var ax = _avg(x); var ay = _avg(y); var n = x.length; for (var i = 0; i < n; ++i) { sum += (x[i] - ax) * (y[i] - ay); } return sum / divisor; } defineFunction("covariance.p", function(x, y){ return _covariance(x, y, x.length); }).args([ [ "array1", [ "collect", "number", 1 ] ], [ "array2", [ "collect", "number", 1 ] ], [ "?", [ "assert", "$array1.length == $array2.length", "N/A" ] ], [ "?", [ "assert", "$array1.length > 0", "DIV/0" ] ] ]); defineFunction("covariance.s", function(x, y){ return _covariance(x, y, x.length - 1); }).args([ [ "array1", [ "collect", "number", 1 ] ], [ "array2", [ "collect", "number", 1 ] ], [ "?", [ "assert", "$array1.length == $array2.length", "N/A" ] ], [ "?", [ "assert", "$array1.length > 1", "DIV/0" ] ] ]); defineAlias("covar", "covariance.p"); /* -----[ Factorials ]----- */ var _fact = util.memoize(function(n){ for (var i = 2, fact = 1; i <= n; ++i) { fact *= i; } return fact; }); defineFunction("fact", _fact).args([ [ "*n", "integer+" ] ]); defineFunction("factdouble", function(n){ for (var i = 2 + (n&1), fact = 1; i <= n; i += 2) { fact *= i; } return fact; }).args([ [ "*n", "integer+" ] ]); defineFunction("multinomial", function(numbers){ var div = 1, sum = 0; numbers.forEach(function(n){ if (n < 0) { throw new CalcError("NUM"); } sum += n; div *= _fact(n); }); return _fact(sum) / div; }).args([ [ "numbers", [ "collect", "number" ] ] ]); var _combinations = util.memoize(function (n, k){ for (var f1 = k + 1, f2 = 1, p1 = 1, p2 = 1; f2 <= n - k; ++f1, ++f2) { p1 *= f1; p2 *= f2; } return p1/p2; }); defineFunction("combin", _combinations).args([ [ "*n", "integer++" ], [ "*k", [ "and", "integer", [ "[between]", 0, "$n" ] ] ] ]); defineFunction("combina", function(n, k){ return _combinations(n + k - 1, n - 1); }).args([ [ "*n", "integer++" ], [ "*k", [ "and", "integer", [ "[between]", 1, "$n" ] ] ] ]); /* -----[ Statistical functions ]----- */ defineFunction("average", function(numbers){ var sum = numbers.reduce(function(sum, num){ return sum + num; }, 0); return sum / numbers.length; }).args([ // most numeric functions must treat booleans as numbers (1 for TRUE // and 0 for FALSE), but AVERAGE shouldn't. [ "numbers", [ "collect", "number!" ] ], [ "?", [ "assert", "$numbers.length > 0", "DIV/0" ] ] ]); defineFunction("averagea", function(values){ var sum = 0, count = 0; values.forEach(function(num){ if (typeof num != "string") { sum += num; } ++count; }); return count ? sum / count : new CalcError("DIV/0"); }).args([ [ "values", [ "collect", "anyvalue" ] ] ]); function _percentile(numbers, rank) { numbers.sort(ascending); var n = numbers.length; var k = rank | 0, d = rank - k; if (k === 0) { return numbers[0]; } if (k >= n) { return numbers[n - 1]; } --k; return numbers[k] + d * (numbers[k + 1] - numbers[k]); } function _percentile_inc(numbers, p){ // algorithm from https://en.wikipedia.org/wiki/Percentile#Microsoft_Excel_method var rank = p * (numbers.length - 1) + 1; return _percentile(numbers, rank); } function _percentile_exc(numbers, p){ // https://en.wikipedia.org/wiki/Percentile#NIST_method var rank = p * (numbers.length + 1); return _percentile(numbers, rank); } defineFunction("percentile.inc", _percentile_inc).args([ [ "numbers", [ "collect", "number", 1 ] ], [ "p", [ "and", "number", [ "[between]", 0, 1 ] ] ] ]); defineFunction("percentile.exc", _percentile_exc).args([ [ "numbers", [ "collect", "number", 1 ] ], [ "p", [ "and", "number", [ "(between)", 0, 1 ] ] ] ]); defineFunction("quartile.inc", function(numbers, quarter){ return _percentile_inc(numbers, quarter / 4); }).args([ [ "numbers", [ "collect", "number", 1 ] ], [ "quarter", [ "values", 0, 1, 2, 3, 4 ] ] ]); defineFunction("quartile.exc", function(numbers, quarter){ return _percentile_exc(numbers, quarter / 4); }).args([ [ "numbers", [ "collect", "number", 1 ] ], [ "quarter", [ "values", 0, 1, 2, 3, 4 ] ] ]); defineAlias("quartile", "quartile.inc"); defineAlias("percentile", "percentile.inc"); var AGGREGATE_FUNCS = [ "AVERAGE", "COUNT", "COUNTA", "MAX", "MIN", "PRODUCT", "STDEV.S", "STDEV.P", "SUM", "VAR.S", "VAR.P", "MEDIAN", "MODE.SNGL", "LARGE", "SMALL", "PERCENTILE.INC", "QUARTILE.INC", "PERCENTILE.EXC", "QUARTILE.EXC" ]; function fetchValuesForAggregate(self, args, options) { var values = []; var opt_ignore_hidden_rows = 1; var opt_ignore_errors = 2; var opt_use_aggregates = 4; (function fetchValues(args) { if (args instanceof Ref) { self.getRefCells(args, true).forEach(function(cell){ var value = cell.value; if ((options & opt_ignore_hidden_rows) && cell.hidden) { return; } if (cell.formula) { // XXX: formula.print is fast, but still, can't we do any better here? // perhaps access the input string directly somehow? var str = cell.formula.print(cell.row, cell.col); if (/^\s*(?:aggregate|subtotal)\s*\(/i.test(str)) { if (!(options & opt_use_aggregates)) { return; } } if ("value" in cell.formula) { value = cell.formula.value; } } if ((options & opt_ignore_errors) && value instanceof CalcError) { return; } if (typeof value == "number" || value instanceof CalcError) { values.push(value); } }); } else if (Array.isArray(args)) { for (var i = 0; i < args.length; ++i) { fetchValues(args[i]); } } else if (args instanceof Matrix) { args.each(fetchValues); } else if (typeof args == "number") { values.push(args); } else if (args instanceof CalcError && !(options & opt_ignore_errors)) { values.push(args); } })(args); return values; } // AGGREGATE function // // https://support.office.com/en-SG/article/aggregate-function-c8caed56-07df-4aeb-9741-23693ffbe525 // // we can only partially type-check this function. also, we need to use the async version in // order to resolve references and delegate values to the function to aggregate. defineFunction("aggregate", function(callback, funcId, options, args){ // options is a bit field. that makes sense; it's the documentation which doesn't. var self = this; self.resolveCells(args, function(){ var values; if (funcId > 12) { // "array form" values = fetchValuesForAggregate(self, args[0], options); var k = args[1]; if (k instanceof CellRef) { k = self.getRefData(k); } if (typeof k != "number") { return callback(new CalcError("VALUE")); } } else { values = fetchValuesForAggregate(self, args, options); } self.func(AGGREGATE_FUNCS[funcId - 1], callback, values); }); }).argsAsync([ [ "funcId", [ "values", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ] ], [ "options", [ "or", [ "null", 0 ], [ "values", 0, 1, 2, 3, 4, 5, 6, 7 ] ] ], [ "args", "rest" ] ]); defineFunction("subtotal", function(callback, funcId){ var self = this; var ignoreHidden = funcId > 100; if (ignoreHidden) { funcId -= 100; } var args = []; for (var i = 2; i < arguments.length; ++i) { args.push(arguments[i]); } self.resolveCells(args, function(){ var values = fetchValuesForAggregate(self, args, ignoreHidden ? 1 : 0); self.func(AGGREGATE_FUNCS[funcId - 1], callback, values); }); }).argsAsync([ [ "funcId", [ "values", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111 ] ], [ "+", [ "ref", [ "or", "ref", "#matrix" ] ] ] ]); // https://support.office.com/en-sg/article/AVEDEV-function-ec78fa01-4755-466c-9a2b-0c4f9eacaf6d defineFunction("avedev", function(numbers){ var avg = numbers.reduce(function(sum, num){ return sum + num; }, 0) / numbers.length; return numbers.reduce(function(sum, num){ return sum + Math.abs(num - avg); }, 0) / numbers.length; }).args([ [ "numbers", [ "collect", "number" ] ], [ "?", [ "assert", "$numbers.length >= 2", "NUM" ] ] ]); function _binom_dist(x, n, p, cumulative) { if (!cumulative) { return _combinations(n, x) * Math.pow(p, x) * Math.pow(1-p, n-x); } else { var sum = 0; for (var j = 0; j <= x; ++j) { sum += _combinations(n, j) * Math.pow(p, j) * Math.pow(1-p, n-j); } return sum; } } defineFunction("binom.dist", _binom_dist).args([ [ "successes", "integer+" ], [ "trials", [ "and", "integer", [ "assert", "$trials >= $successes" ] ] ], [ "probability", [ "and", "number", [ "[between]", 0, 1 ] ] ], [ "cumulative", "logical" ] ]); defineAlias("binomdist", "binom.dist"); defineFunction("binom.inv", function(n, p, alpha){ // XXX: could a binary search be faster? for (var x = 0; x <= n; ++x) { if (_binom_dist(x, n, p, true) >= alpha) { return x; } } return new CalcError("N/A"); // XXX: is this right? }).args([ [ "trials", "integer+" ], [ "probability", [ "and", "number", [ "[between]", 0, 1 ] ] ], [ "alpha", [ "and", "number", [ "[between]", 0, 1 ] ] ] ]); defineAlias("critbinom", "binom.inv"); defineFunction("binom.dist.range", function(n, p, s, s2){ var sum = 0; for (var k = s; k <= s2; ++k) { sum += _combinations(n, k) * Math.pow(p, k) * Math.pow(1-p, n-k); } return sum; }).args([ [ "trials", "integer+" ], [ "probability", [ "and", "number", [ "[between]", 0, 1 ] ] ], [ "successes_min", [ "and", "integer", [ "[between]", 0, "$trials" ] ] ], [ "successes_max", [ "or", [ "and", "integer", [ "[between]", "$successes_min", "$trials" ] ], [ "null", "$successes_min" ] ] ] ]); defineFunction("negbinom.dist", function(x, k, p, cumulative){ if (cumulative) { var sum = 0; while (x >= 0) { sum += _combinations(x+k-1, x) * Math.pow(p, k) * Math.pow(1-p, x); x--; } return sum; } return _combinations(x+k-1, x) * Math.pow(p, k) * Math.pow(1-p, x); }).args([ [ "number_f", "integer+" ], [ "number_s", "integer+" ], [ "probability_s", [ "and", "number", [ "[between]", 0, 1 ] ] ], [ "cumulative", "logical" ] ]); defineAlias("negbinomdist", "negbinom.dist"); /* -----[ lookup functions ]----- */ defineFunction("address", function(row, col, abs, a1, sheet){ // by some lucky coincidence, we get the corret `rel` value by just subtracting 1 from the // abs argument var cell = new CellRef(row - 1, col - 1, abs - 1); if (sheet) { cell.setSheet(sheet, true); } return a1 ? cell.print(0, 0) : cell.print(); }).args([ [ "row", "integer++" ], [ "col", "integer++" ], [ "abs", [ "or", [ "null", 1 ], [ "values", 1, 2, 3, 4 ]]], [ "a1", [ "or", [ "null", true ], "logical" ]], [ "sheet", [ "or", "null", "string" ]] ]); defineFunction("areas", function(ref){ var count = 0; (function loop(x){ if (x instanceof CellRef || x instanceof RangeRef) { count++; } else if (x instanceof UnionRef) { x.refs.forEach(loop); } // XXX: NameRef if we add support })(ref); return count; }).args([ [ "ref", "ref" ] ]); defineFunction("choose", function(index, args){ if (index > args.length) { return new CalcError("N/A"); } else { return args[index - 1]; } }).args([ [ "*index", "integer" ], [ "+", [ "value", "anything" ] ] ]); defineFunction("column", function(ref){ if (!ref) { return this.formula.col + 1; } if (ref instanceof CellRef) { return ref.col + 1; } return this.asMatrix(ref).mapCol(function(col){ return col + ref.topLeft.col + 1; }); }).args([ [ "ref", [ "or", "area", "null" ]] ]); defineFunction("columns", function(m){ return m instanceof Ref ? m.width() : m.width; }).args([ [ "ref", [ "or", "area", "#matrix" ] ] ]); defineFunction("formulatext", function(ref){ var cell = this.getRefCells(ref)[0]; // XXX: overkill, but oh well. if (!cell.formula) { return new CalcError("N/A"); } return cell.formula.print(cell.row, cell.col); }).args([ [ "ref", "ref" ] ]); defineFunction("hlookup", function(value, m, row, approx){ var resultCol = null; m.eachCol(function(col){ var data = m.get(0, col); if (approx) { if (data > value) { return true; } resultCol = col; } else if (data === value) { resultCol = col; return true; } }); if (resultCol == null) { return new CalcError("N/A"); } return m.get(row - 1, resultCol); }).args([ [ "value", "anyvalue" ], [ "range", "matrix" ], [ "row", "integer++" ], [ "approx", [ "or", "logical", [ "null", true ]]] ]); defineFunction("index", function(callback, ref, row, col, areanum){ var self = this; if (ref instanceof UnionRef) { ref = ref.refs[areanum - 1]; } if ((!row && !col) || !ref) { return callback(new CalcError("N/A")); } if (ref instanceof CellRef) { ref = ref.toRangeRef(); } if (ref instanceof RangeRef) { if (row && col) { if (col > ref.width() || row > ref.height()) { return callback(new CalcError("REF")); } // fetching a single cell var cell = ref.toCell(row - 1, col - 1); self.resolveCells([ cell ], function(){ callback(self.getRefData(cell)); }); return; } if (!row) { // fetch a full column var colRange = ref.toColumn(col - 1); self.resolveCells([ colRange ], function(){ callback(self.asMatrix(colRange)); }); return; } if (!col) { // fetch a full row var rowRange = ref.toRow(row - 1); self.resolveCells([ rowRange ], function(){