How to use defineFunction method in chromy

Best JavaScript code snippet using chromy

runtime.functions.js

Source:runtime.functions.js Github

copy

Full Screen

...77 var unpackDate = runtime.unpackDate;78 var daysInYear = runtime.daysInYear;79 /* -----[ Math functions ]----- */80 [ "abs", "cos", "sin", "acos", "asin", "tan", "atan", "exp", "sqrt" ].forEach(function(name){81 defineFunction(name, Math[name]).args([82 [ "*n", "number" ]83 ]);84 });85 defineFunction("ln", Math.log).args([86 [ "*n", "number" ]87 ]);88 defineFunction("log", function(num, base){89 return Math.log(num) / Math.log(base);90 }).args([91 [ "*num", "number++" ],92 [ "*base", [ "or", "number++", [ "null", 10 ] ] ],93 [ "?", [ "assert", "$base != 1", "DIV/0" ] ]94 ]);95 defineFunction("log10", function(num){96 return Math.log(num) / Math.log(10);97 }).args([98 [ "*num", "number++" ]99 ]);100 defineFunction("pi", function(){101 return Math.PI;102 }).args([]);103 defineFunction("sqrtpi", function(n){104 return Math.sqrt(n * Math.PI);105 }).args([106 [ "*num", "number+" ]107 ]);108 defineFunction("degrees", function(rad){109 return ((180 * rad) / Math.PI) % 360;110 }).args([111 [ "*radians", "number" ]112 ]);113 defineFunction("radians", function(deg){114 return Math.PI * deg / 180;115 }).args([116 [ "*degrees", "number" ]117 ]);118 function _cosh(n){119 return (Math.exp(n) + Math.exp(-n)) / 2;120 }121 defineFunction("cosh", _cosh).args([122 [ "*num", "number" ]123 ]);124 defineFunction("acosh", function(n){125 return Math.log(n + Math.sqrt(n - 1) * Math.sqrt(n + 1));126 }).args([127 [ "*num", "number" ],128 [ "?", [ "assert", "$num >= 1" ] ]129 ]);130 function _sinh(n){131 return (Math.exp(n) - Math.exp(-n)) / 2;132 }133 defineFunction("sinh", _sinh).args([134 [ "*num", "number" ]135 ]);136 defineFunction("asinh", function(n){137 return Math.log(n + Math.sqrt(n * n + 1));138 }).args([139 [ "*num", "number" ]140 ]);141 defineFunction("sec", function(n){142 return 1 / Math.cos(n);143 }).args([144 [ "*num", "number" ]145 ]);146 defineFunction("sech", function(n){147 return 1 / _cosh(n);148 }).args([149 [ "*num", "number" ]150 ]);151 defineFunction("csc", function(n){152 return 1 / Math.sin(n);153 }).args([154 [ "*num", "number" ]155 ]);156 defineFunction("csch", function(n){157 return 1 / _sinh(n);158 }).args([159 [ "*num", "number" ]160 ]);161 defineFunction("atan2", function(x, y){162 return Math.atan(y / x);163 }).args([164 [ "*x", "divisor" ],165 [ "*y", "number" ]166 ]);167 function _tanh(n) {168 return _sinh(n) / _cosh(n);169 }170 defineFunction("tanh", _tanh).args([171 [ "*num", "number" ]172 ]);173 defineFunction("atanh", function(n){174 return Math.log(Math.sqrt(1 - n*n) / (1 - n));175 }).args([176 [ "*num", [ "and", "number", [ "(between)", -1, 1 ] ] ]177 ]);178 defineFunction("cot", function(n){179 return 1 / Math.tan(n);180 }).args([181 [ "*num", "divisor" ]182 ]);183 defineFunction("coth", function(n){184 return 1 / _tanh(n);185 }).args([186 [ "*num", "divisor" ]187 ]);188 defineFunction("acot", function(n){189 return Math.PI / 2 - Math.atan(n);190 }).args([191 [ "*num", "number" ]192 ]);193 defineFunction("acoth", function(n){194 return Math.log((n + 1) / (n - 1)) / 2;195 }).args([196 [ "*num", "number" ],197 [ "?", [ "or",198 [ "assert", "$num < -1"],199 [ "assert", "$num > 1" ] ] ]200 ]);201 defineFunction("power", function(a, b){202 return Math.pow(a, b);203 }).args([204 [ "*a", "number" ],205 [ "*b", "number" ]206 ]);207 defineFunction("mod", function(a, b){208 return a % b;209 }).args([210 [ "*a", "number" ],211 [ "*b", "divisor" ]212 ]);213 defineFunction("quotient", function(a, b){214 return Math.floor(a / b);215 }).args([216 [ "*a", "number" ],217 [ "*b", "divisor" ]218 ]);219 defineFunction("ceiling", function(num, s){220 return s ? s * Math.ceil(num / s) : 0;221 }).args([222 [ "*number", "number" ],223 [ "*significance", "number" ],224 [ "?", [ "assert", "$significance >= 0 || $number < 0" ] ]225 ]);226 defineFunction("ceiling.precise", function(num, s){227 s = Math.abs(s);228 return s ? s * Math.ceil(num / s) : 0;229 }).args([230 [ "*number", "number" ],231 [ "*significance", [ "or", "number", [ "null", 1 ] ] ]232 ]);233 defineAlias("iso.ceiling", "ceiling.precise");234 // XXX: how do we know if this function is correct?235 //236 // https://support.office.com/en-gb/article/CEILING-MATH-function-80f95d2f-b499-4eee-9f16-f795a8e306c8237 //238 // “There are many combinations of Significance and Mode values that affect rounding of negative239 // numbers in different ways.” — right, thanks for the info. :-\240 defineFunction("ceiling.math", function(num, s, mode){241 if (!s || !num) {242 return 0;243 }244 if (num < 0 && ((!mode && s < 0) || (mode && s > 0))) {245 s = -s;246 }247 return s ? s * Math.ceil(num / s) : 0;248 }).args([249 [ "*number", "number" ],250 [ "*significance", [ "or", "number", [ "null", "$number < 0 ? -1 : 1" ] ] ],251 [ "*mode", [ "or", "logical", [ "null", 0 ] ] ]252 ]);253 defineFunction("floor", function(num, s){254 return s ? s * Math.floor(num / s) : 0;255 }).args([256 [ "*number", "number" ],257 [ "*significance", "number" ],258 [ "?", [ "assert", "$significance >= 0 || $number < 0" ] ]259 ]);260 defineFunction("floor.precise", function(num, s){261 s = Math.abs(s);262 return s ? s * Math.floor(num / s) : 0;263 }).args([264 [ "*number", "number" ],265 [ "*significance", [ "or", "number", [ "null", 1 ] ] ]266 ]);267 // XXX: check this268 defineFunction("floor.math", function(num, s, mode){269 if (!s || !num) {270 return 0;271 }272 if (num < 0 && ((!mode && s < 0) || (mode && s > 0))) {273 s = -s;274 }275 return s ? s * Math.floor(num / s) : 0;276 }).args([277 [ "*number", "number" ],278 [ "*significance", [ "or", "number", [ "null", "$number < 0 ? -1 : 1" ] ] ],279 [ "*mode", [ "or", "logical", [ "null", 0 ] ] ]280 ]);281 defineFunction("int", Math.floor).args([282 [ "*number", "number" ]283 ]);284 defineFunction("mround", function(num, mult){285 return mult ? mult * Math.round(num / mult) : 0;286 }).args([287 [ "*number", "number" ],288 [ "*multiple", "number" ]289 ]);290 defineFunction("round", function(num, digits){291 var sign = num < 0 ? -1 : 1;292 if (sign < 0) { num = -num; }293 digits = Math.pow(10, digits);294 num *= digits;295 num = Math.round(num);296 return sign * num / digits;297 }).args([298 [ "*number", "number" ],299 [ "*digits", "number" ]300 ]);301 defineFunction("roundup", function(num, digits){302 digits = Math.pow(10, digits);303 num *= digits;304 num = num < 0 ? Math.floor(num) : Math.ceil(num);305 return num / digits;306 }).args([307 [ "*number", "number" ],308 [ "*digits", "number" ]309 ]);310 defineFunction("rounddown", function(num, digits){311 digits = Math.pow(10, digits);312 num *= digits;313 num = num < 0 ? Math.ceil(num) : Math.floor(num);314 return num / digits;315 }).args([316 [ "*number", "number" ],317 [ "*digits", "number" ]318 ]);319 defineFunction("even", function(num){320 var n = num < 0 ? Math.floor(num) : Math.ceil(num);321 return n % 2 ? n + (n < 0 ? -1 : 1) : n;322 }).args([323 [ "*number", "number" ]324 ]);325 defineFunction("odd", function(num){326 var n = num < 0 ? Math.floor(num) : Math.ceil(num);327 return n % 2 ? n : n + (n < 0 ? -1 : 1);328 }).args([329 [ "*number", "number" ]330 ]);331 defineFunction("sign", function(num){332 return num < 0 ? -1 : num > 0 ? 1 : 0;333 }).args([334 [ "*number", "number" ]335 ]);336 function _gcd(a, b) {337 while (b) {338 var r = a % b;339 a = b;340 b = r;341 }342 return a;343 }344 function _lcm(a, b) {345 return Math.abs(a * b) / _gcd(a, b);346 }347 defineFunction("gcd", function(args){348 var a = args[0];349 for (var i = 1; i < args.length; ++i) {350 a = _gcd(a, args[i]);351 }352 return a;353 }).args([354 [ "numbers", [ "collect", "number" ] ]355 ]);356 defineFunction("lcm", function(args){357 var a = args[0];358 for (var i = 1; i < args.length; ++i) {359 a = _lcm(a, args[i]);360 }361 return a;362 }).args([363 [ "numbers", [ "collect", "number" ] ]364 ]);365 defineFunction("sum", function(numbers){366 return numbers.reduce(function(sum, num){367 return sum + num;368 }, 0);369 }).args([370 [ "numbers", [ "collect", "number" ] ]371 ]);372 defineFunction("product", function(numbers){373 return numbers.reduce(function(prod, num){374 return prod * num;375 }, 1);376 }).args([377 [ "numbers", [ "collect", "number" ] ]378 ]);379 defineFunction("sumproduct", function(first, rest) {380 var sum = 0;381 first.each(function(p, row, col){382 if (typeof p == "number") {383 for (var i = 0; i < rest.length; ++i) {384 var v = rest[i].get(row, col);385 if (typeof v != "number") {386 return;387 }388 p *= v;389 }390 sum += p;391 }392 });393 return sum;394 }).args([395 [ "a1", "matrix" ],396 [ "+",397 [ "a2", [ "and", "matrix",398 [ "assert", "$a2.width == $a1.width" ],399 [ "assert", "$a2.height == $a1.height" ] ] ] ]400 ]);401 defineFunction("sumsq", function(numbers){402 return numbers.reduce(function(sum, num){403 return sum + num * num;404 }, 0);405 }).args([406 [ "numbers", [ "collect", "number" ] ]407 ]);408 defineFunction("sumx2my2", function(a, b){409 var sum = 0;410 a.each(function(x, row, col){411 var y = b.get(row, col);412 if (typeof x == "number" && typeof y == "number") {413 sum += x*x - y*y;414 }415 });416 return sum;417 }).args([418 [ "a", "matrix" ],419 [ "b", [ "and", "matrix",420 [ "assert", "$b.width == $a.width" ],421 [ "assert", "$b.height == $a.height" ] ] ]422 ]);423 defineFunction("sumx2py2", function(a, b){424 var sum = 0;425 a.each(function(x, row, col){426 var y = b.get(row, col);427 if (typeof x == "number" && typeof y == "number") {428 sum += x*x + y*y;429 }430 });431 return sum;432 }).args([433 [ "a", "matrix" ],434 [ "b", [ "and", "matrix",435 [ "assert", "$b.width == $a.width" ],436 [ "assert", "$b.height == $a.height" ] ] ]437 ]);438 defineFunction("sumxmy2", function(a, b){439 var sum = 0;440 a.each(function(x, row, col){441 var y = b.get(row, col);442 if (typeof x == "number" && typeof y == "number") {443 sum += (x - y) * (x - y);444 }445 });446 return sum;447 }).args([448 [ "a", "matrix" ],449 [ "b", [ "and", "matrix",450 [ "assert", "$b.width == $a.width" ],451 [ "assert", "$b.height == $a.height" ] ] ]452 ]);453 defineFunction("seriessum", function(x, n, m, a){454 var sum = 0;455 a.each(function(coef){456 if (typeof coef != "number") {457 throw new CalcError("VALUE");458 }459 sum += coef * Math.pow(x, n);460 n += m;461 });462 return sum;463 }).args([464 [ "x", "number" ],465 [ "y", "number" ],466 [ "m", "number" ],467 [ "a", "matrix" ]468 ]);469 defineFunction("min", function(numbers){470 return numbers.length ? Math.min.apply(Math, numbers) : 0;471 }).args([472 [ "numbers", [ "collect", "number" ] ]473 ]);474 defineFunction("max", function(numbers){475 return numbers.length ? Math.max.apply(Math, numbers) : 0;476 }).args([477 [ "numbers", [ "collect", "number" ] ]478 ]);479 defineFunction("counta", function(values){480 return values.length;481 }).args([482 [ "values", [ "#collect", "anyvalue" ] ]483 ]);484 defineFunction("count", function(numbers){485 return numbers.length;486 }).args([487 [ "numbers", [ "#collect", "number" ] ]488 ]);489 defineFunction("countunique", function(values){490 var count = 0, seen = [];491 values.forEach(function(val){492 if (seen.indexOf(val) < 0) {493 count++;494 seen.push(val);495 }496 });497 return count;498 }).args([499 [ "values", [ "#collect", "anyvalue" ] ]500 ]);501 defineFunction("countblank", function(a){502 var count = 0;503 function add(val) {504 if (val == null || val === "") {505 count++;506 }507 }508 function loop(args){509 for (var i = 0; i < args.length; ++i) {510 var x = args[i];511 if (x instanceof Matrix) {512 x.each(add, true);513 } else {514 add(x);515 }516 }517 }518 loop(a);519 return count;520 }).args([521 [ "+", [ "args", [ "or", "matrix", "anyvalue" ] ] ]522 ]);523 defineFunction("iseven", function(num){524 return num % 2 === 0;525 }).args([526 [ "*number", "number" ]527 ]);528 defineFunction("isodd", function(num){529 return num % 2 !== 0;530 }).args([531 [ "*number", "number" ]532 ]);533 defineFunction("n", function(val){534 if (typeof val == "boolean") {535 return val ? 1 : 0;536 }537 if (typeof val == "number") {538 return val;539 }540 return 0;541 }).args([542 [ "*value", "anyvalue" ]543 ]);544 defineFunction("na", function(){545 return new CalcError("N/A");546 }).args([]);547 /* -----[ the "*IFS" functions ]----- */548 // helper function: take `args` like COUNTIFS (see Excel docs) and549 // calls `f` for each cell matching all criteria. `f` receives550 // `chunks` (parsed args containing matrix and predicate) and551 // row,col of matching cells.552 function forIFS(args, f) {553 var chunks = [], i = 0, matrix = args[0];554 while (i < args.length) {555 chunks.push({556 matrix: args[i++],557 pred: parseCriteria(args[i++])558 });559 }560 ROW: for (var row = 0; row < matrix.height; ++row) {561 COL: for (var col = 0; col < matrix.width; ++col) {562 for (i = 0; i < chunks.length; ++i) {563 var val = chunks[i].matrix.get(row, col);564 if (!chunks[i].pred(val == null || val === "" ? 0 : val)) {565 continue COL;566 }567 }568 f(row, col);569 }570 }571 }572 var ARGS_COUNTIFS = [573 [ "m1", "matrix" ],574 [ "c1", "anyvalue" ],575 [ [ "m2", "matrix" ],576 [ "c2", "anyvalue" ] ]577 ];578 defineFunction("countifs", function(m1, c1, rest){579 var count = 0;580 rest.unshift(m1, c1);581 forIFS(rest, function(){ count++; });582 return count;583 }).args(ARGS_COUNTIFS);584 var ARGS_SUMIFS = [585 [ "range", "matrix" ]586 ].concat(ARGS_COUNTIFS);587 defineFunction("sumifs", function(range, m1, c1, args){588 // hack: insert a predicate that filters out non-numeric589 // values; should also accept blank cells. it's safe to590 // modify args.591 args.unshift(range, numericPredicate, m1, c1);592 var sum = 0;593 forIFS(args, function(row, col){594 var val = range.get(row, col);595 if (val) {596 sum += val;597 }598 });599 return sum;600 }).args(ARGS_SUMIFS);601 // similar to sumifs, but compute average of matching cells602 defineFunction("averageifs", function(range, m1, c1, args){603 args.unshift(range, numericPredicate, m1, c1);604 var sum = 0, count = 0;605 forIFS(args, function(row, col){606 var val = range.get(row, col);607 if (val == null || val === "") {608 val = 0;609 }610 sum += val;611 count++;612 });613 return count ? sum / count : new CalcError("DIV/0");614 }).args(ARGS_SUMIFS);615 defineFunction("countif", function(matrix, criteria){616 criteria = parseCriteria(criteria);617 var count = 0;618 matrix.each(function(val){619 if (criteria(val)) {620 count++;621 }622 });623 return count;624 }).args([625 [ "range", "matrix" ],626 [ "*criteria", "anyvalue" ]627 ]);628 var ARGS_SUMIF = [629 [ "range", "matrix" ],630 [ "*criteria", "anyvalue" ],631 [ "sumRange", [ "or", "area", "#matrix", [ "null", "$range" ] ] ]632 ];633 function fetchSumRange(continuation) {634 return function(callback, range, criteria, sumRange) {635 var self = this;636 if (sumRange instanceof Ref) {637 // make sure it covers the same area as `range`, as the “spec” mentions:638 //639 // The sum_range argument does not have to be the same size and shape as the640 // range argument. The actual cells that are added are determined by using the641 // upper leftmost cell in the sum_range argument as the beginning cell, and then642 // including cells that correspond in size and shape to the range argument.643 //644 // It does make one wonder, since only the top-left cell in `sumRange` matters, why645 // should it be a range at all? Oh well, Excel.646 var r = sumRange.clone().toRangeRef();647 if (r.width() != range.width || r.height() != range.height) {648 if (!isFinite(r.topLeft.row)) {649 r.topLeft.row = 0;650 }651 if (!isFinite(r.topLeft.col)) {652 r.topLeft.col = 0;653 }654 r.bottomRight.row = r.topLeft.row + range.height - 1;655 r.bottomRight.col = r.topLeft.col + range.width - 1;656 return self.resolveCells([ r ], function(){657 callback(continuation(range, criteria, self.asMatrix(r)));658 });659 }660 }661 callback(continuation(range, criteria, self.asMatrix(sumRange)));662 };663 }664 defineFunction("sumif", fetchSumRange(function(range, criteria, sumRange){665 var sum = 0;666 criteria = parseCriteria(criteria);667 range.each(function(val, row, col){668 if (criteria(val)) {669 var v = sumRange.get(row, col);670 if (numericPredicate(v)) {671 sum += v || 0;672 }673 }674 });675 return sum;676 })).argsAsync(ARGS_SUMIF);677 defineFunction("averageif", fetchSumRange(function(range, criteria, sumRange){678 var sum = 0, count = 0;679 criteria = parseCriteria(criteria);680 range.each(function(val, row, col){681 if (criteria(val)) {682 var v = sumRange.get(row, col);683 if (numericPredicate(v)) {684 sum += v || 0;685 count++;686 }687 }688 });689 return count ? sum / count : new CalcError("DIV/0");690 })).argsAsync(ARGS_SUMIF);691 (function(def){692 def("large", function(numbers, nth){693 return numbers.sort(descending)[nth];694 });695 def("small", function(numbers, nth){696 return numbers.sort(ascending)[nth];697 });698 })(function(name, handler){699 defineFunction(name, function(matrix, nth){700 var numbers = [];701 var error = matrix.each(function(val){702 if (val instanceof CalcError) {703 return val;704 }705 if (typeof val == "number") {706 numbers.push(val);707 }708 });709 if (error) {710 return error;711 }712 if (nth > numbers.length) {713 return new CalcError("NUM");714 }715 return handler(numbers, nth - 1);716 }).args([717 [ "array", "matrix" ],718 [ "*nth", "number++" ]719 ]);720 });721 function _avg(numbers) {722 return numbers.reduce(function(sum, num){723 return sum + num;724 }, 0) / numbers.length;725 }726 function _var_sp(numbers, divisor, avg) {727 if (avg == null) {728 avg = _avg(numbers);729 }730 return numbers.reduce(function(sum, num){731 return sum + Math.pow(num - avg, 2);732 }, 0) / divisor;733 }734 function _stdev_sp(numbers, divisor) {735 return Math.sqrt(_var_sp(numbers, divisor));736 }737 // https://support.office.com/en-sg/article/STDEV-S-function-7d69cf97-0c1f-4acf-be27-f3e83904cc23738 defineFunction("stdev.s", function(numbers){739 return _stdev_sp(numbers, numbers.length - 1);740 }).args([741 [ "numbers", [ "collect", "number" ] ],742 [ "?", [ "assert", "$numbers.length >= 2", "NUM" ] ]743 ]);744 // https://support.office.com/en-sg/article/STDEV-P-function-6e917c05-31a0-496f-ade7-4f4e7462f285745 defineFunction("stdev.p", function(numbers){746 return _stdev_sp(numbers, numbers.length);747 }).args([748 [ "numbers", [ "collect", "number" ] ],749 [ "?", [ "assert", "$numbers.length >= 2", "NUM" ] ]750 ]);751 defineFunction("var.s", function(numbers){752 return _var_sp(numbers, numbers.length - 1);753 }).args([754 [ "numbers", [ "collect", "number" ] ],755 [ "?", [ "assert", "$numbers.length >= 2", "NUM" ] ]756 ]);757 defineFunction("var.p", function(numbers){758 return _var_sp(numbers, numbers.length);759 }).args([760 [ "numbers", [ "collect", "number" ] ],761 [ "?", [ "assert", "$numbers.length >= 2", "NUM" ] ]762 ]);763 defineFunction("median", function(numbers){764 var n = numbers.length;765 numbers.sort(ascending);766 if (n % 2) {767 // when length is odd, the median is the number in the middle768 return numbers[n >> 1];769 }770 // that's the average of the two middle numbers, written in in a fancy way771 return (numbers[n >>= 1] + numbers[n - 1]) / 2;772 }).args([773 [ "numbers", [ "collect", "number" ] ],774 [ "?", [ "assert", "$numbers.length > 0", "N/A" ] ]775 ]);776 defineFunction("mode.sngl", function(numbers){777 numbers.sort(ascending);778 var prev = null, count = 0, max = 1, mode = null;779 for (var i = 0; i < numbers.length; ++i) {780 var n = numbers[i];781 if (n != prev) {782 count = 1;783 prev = n;784 } else {785 count++;786 }787 if (count > max) {788 max = count;789 mode = n;790 }791 }792 return mode == null ? new CalcError("N/A") : mode;793 }).args([794 [ "numbers", [ "collect", "number" ] ]795 ]);796 defineFunction("mode.mult", function(numbers){797 var seen = Object.create(null), max = 2, res = [];798 numbers.forEach(function(num){799 var s = seen[num] || 0;800 seen[num] = ++s;801 if (s == max) {802 res.push(num);803 } else if (s > max) {804 max = s;805 res = [ num ];806 }807 });808 var m = new Matrix(this);809 res.forEach(function(num, i){810 m.set(i, 0, num);811 });812 return m;813 }).args([814 [ "numbers", [ "collect", "number" ] ]815 ]);816 defineFunction("geomean", function(numbers){817 var n = numbers.length;818 var p = numbers.reduce(function(p, num){819 if (num < 0) {820 throw new CalcError("NUM");821 }822 return p * num;823 }, 1);824 return Math.pow(p, 1/n);825 }).args([826 [ "numbers", [ "collect", "number" ] ],827 [ "?", [ "assert", "$numbers.length > 0", "NUM" ] ]828 ]);829 defineFunction("harmean", function(numbers){830 var n = numbers.length;831 var s = numbers.reduce(function(s, num){832 if (!num) {833 throw new CalcError("DIV/0");834 }835 return s + 1 / num;836 }, 0);837 return n / s;838 }).args([839 [ "numbers", [ "collect", "number" ] ],840 [ "?", [ "assert", "$numbers.length > 0", "NUM" ] ]841 ]);842 defineFunction("trimmean", function(numbers, p){843 var n = numbers.length;844 numbers.sort(ascending);845 var discard = Math.floor(n * p);846 if (discard % 2) {847 --discard;848 }849 discard /= 2;850 var sum = 0;851 for (var i = discard; i < n-discard; ++i) {852 sum += numbers[i];853 }854 return sum / (n - discard * 2);855 }).args([856 [ "numbers", [ "collect", "number", 1 ] ],857 [ "percent", [ "and", "number", [ "[between)", 0, 1 ] ] ],858 [ "?", [ "assert", "$numbers.length > 0", "NUM" ] ]859 ]);860 defineFunction("frequency", function(data, bins){861 // apparently this always returns a vertical matrix in Excel, so we collect all numbers in862 // bins instead of receiving it as a Matrix and try to mimic its shape.863 data.sort(ascending);864 bins.sort(ascending);865 var prev = -Infinity;866 var i = 0;867 function count(max) {868 var n = 0;869 while (i < data.length && data[i] > prev && data[i] <= max) {870 ++n; ++i;871 }872 return n;873 }874 var m = new Matrix(this);875 bins.forEach(function(val, i){876 var n = count(val);877 prev = val;878 m.set(i, 0, n);879 });880 m.set(m.height, 0, data.length - i);881 return m;882 }).args([883 [ "data", [ "collect", "number", 1 ] ],884 [ "bins", [ "collect", "number", 1 ] ]885 ]);886 defineFunction("rank.eq", function(val, numbers, asc) {887 numbers.sort(asc ? ascending : descending);888 var pos = numbers.indexOf(val);889 return pos < 0 ? new CalcError("N/A") : pos + 1;890 }).args([891 [ "value", "number" ],892 [ "numbers", [ "collect", "number" ] ],893 [ "order", [ "or", "logical", [ "null", false ] ] ]894 ]);895 defineAlias("rank", "rank.eq");896 defineFunction("rank.avg", function(val, numbers, asc) {897 numbers.sort(asc ? ascending : descending);898 var pos = numbers.indexOf(val);899 if (pos < 0) {900 return new CalcError("N/A");901 }902 for (var i = pos; numbers[i] == val; ++i){}903 return (pos + i + 1) / 2;904 }).args([905 [ "value", "number" ],906 [ "numbers", [ "collect", "number" ] ],907 [ "order", [ "or", "logical", [ "null", false ] ] ]908 ]);909 // formula available at https://support.office.microsoft.com/en-us/article/KURT-function-cbbc2312-dfa6-4cc4-b5c0-1b3c59cc9377910 defineFunction("kurt", function(numbers){911 var n = numbers.length;912 var avg = _avg(numbers);913 var variance = _var_sp(numbers, n-1, avg);914 var stddev = Math.sqrt(variance);915 var sum = numbers.reduce(function(sum, num){916 return sum + Math.pow((num - avg) / stddev, 4);917 }, 0);918 return n*(n+1)/((n-1)*(n-2)*(n-3)) * sum919 - 3*Math.pow(n-1, 2)/((n-2)*(n-3));920 }).args([921 [ "numbers", [ "collect", "number" ] ],922 [ "?", [ "assert", "$numbers.length >= 4", "NUM" ] ]923 ]);924 function _percentrank(numbers, x, exc) {925 var nlt = 0, ngt = 0, left = null, right = null, found = false;926 numbers.forEach(function(num){927 if (num < x) {928 nlt++;929 left = left == null ? num : Math.max(left, num);930 } else if (num > x) {931 ngt++;932 right = right == null ? num : Math.min(right, num);933 } else {934 found = true;935 }936 });937 if (!nlt && !ngt) {938 return new CalcError("N/A");939 }940 if (found) {941 if (exc) {942 return (nlt + 1) / (numbers.length + 1);943 }944 return nlt / (nlt + ngt);945 }946 return ((right - x) * _percentrank(numbers, left, exc) +947 (x - left) * _percentrank(numbers, right, exc)) / (right - left);948 }949 var ARGS_PERCENTRANK = [950 [ "array", [ "collect", "number", 1 ] ],951 [ "x", "number" ],952 [ "significance", [ "or", [ "null", 3 ], "integer++" ] ],953 [ "?", [ "assert", "$array.length > 0", "NUM" ] ]954 ];955 defineFunction("percentrank.inc", function(numbers, x, significance) {956 var p = _percentrank(numbers, x, 0);957 p = p.toFixed(significance + 1);958 return parseFloat(p.substr(0, p.length - 1));959 }).args(ARGS_PERCENTRANK);960 defineFunction("percentrank.exc", function(numbers, x, significance) {961 var p = _percentrank(numbers, x, 1);962 p = p.toFixed(significance + 1);963 return parseFloat(p.substr(0, p.length - 1));964 }).args(ARGS_PERCENTRANK);965 defineAlias("percentrank", "percentrank.inc");966 function _covariance(x, y, divisor) {967 var sum = 0;968 var ax = _avg(x);969 var ay = _avg(y);970 var n = x.length;971 for (var i = 0; i < n; ++i) {972 sum += (x[i] - ax) * (y[i] - ay);973 }974 return sum / divisor;975 }976 defineFunction("covariance.p", function(x, y){977 return _covariance(x, y, x.length);978 }).args([979 [ "array1", [ "collect", "number", 1 ] ],980 [ "array2", [ "collect", "number", 1 ] ],981 [ "?", [ "assert", "$array1.length == $array2.length", "N/A" ] ],982 [ "?", [ "assert", "$array1.length > 0", "DIV/0" ] ]983 ]);984 defineFunction("covariance.s", function(x, y){985 return _covariance(x, y, x.length - 1);986 }).args([987 [ "array1", [ "collect", "number", 1 ] ],988 [ "array2", [ "collect", "number", 1 ] ],989 [ "?", [ "assert", "$array1.length == $array2.length", "N/A" ] ],990 [ "?", [ "assert", "$array1.length > 1", "DIV/0" ] ]991 ]);992 defineAlias("covar", "covariance.p");993 /* -----[ Factorials ]----- */994 var _fact = util.memoize(function(n){995 for (var i = 2, fact = 1; i <= n; ++i) {996 fact *= i;997 }998 return fact;999 });1000 defineFunction("fact", _fact).args([1001 [ "*n", "integer+" ]1002 ]);1003 defineFunction("factdouble", function(n){1004 for (var i = 2 + (n&1), fact = 1; i <= n; i += 2) {1005 fact *= i;1006 }1007 return fact;1008 }).args([1009 [ "*n", "integer+" ]1010 ]);1011 defineFunction("multinomial", function(numbers){1012 var div = 1, sum = 0;1013 numbers.forEach(function(n){1014 if (n < 0) {1015 throw new CalcError("NUM");1016 }1017 sum += n;1018 div *= _fact(n);1019 });1020 return _fact(sum) / div;1021 }).args([1022 [ "numbers", [ "collect", "number" ] ]1023 ]);1024 var _combinations = util.memoize(function (n, k){1025 for (var f1 = k + 1, f2 = 1, p1 = 1, p2 = 1; f2 <= n - k; ++f1, ++f2) {1026 p1 *= f1;1027 p2 *= f2;1028 }1029 return p1/p2;1030 });1031 defineFunction("combin", _combinations).args([1032 [ "*n", "integer++" ],1033 [ "*k", [ "and", "integer", [ "[between]", 0, "$n" ] ] ]1034 ]);1035 defineFunction("combina", function(n, k){1036 return _combinations(n + k - 1, n - 1);1037 }).args([1038 [ "*n", "integer++" ],1039 [ "*k", [ "and", "integer", [ "[between]", 1, "$n" ] ] ]1040 ]);1041 /* -----[ Statistical functions ]----- */1042 defineFunction("average", function(numbers){1043 var sum = numbers.reduce(function(sum, num){1044 return sum + num;1045 }, 0);1046 return sum / numbers.length;1047 }).args([1048 // most numeric functions must treat booleans as numbers (1 for TRUE1049 // and 0 for FALSE), but AVERAGE shouldn't.1050 [ "numbers", [ "collect", "number!" ] ],1051 [ "?", [ "assert", "$numbers.length > 0", "DIV/0" ] ]1052 ]);1053 defineFunction("averagea", function(values){1054 var sum = 0, count = 0;1055 values.forEach(function(num){1056 if (typeof num != "string") {1057 sum += num;1058 }1059 ++count;1060 });1061 return count ? sum / count : new CalcError("DIV/0");1062 }).args([1063 [ "values", [ "collect", "anyvalue" ] ]1064 ]);1065 function _percentile(numbers, rank) {1066 numbers.sort(ascending);1067 var n = numbers.length;1068 var k = rank | 0, d = rank - k;1069 if (k === 0) {1070 return numbers[0];1071 }1072 if (k >= n) {1073 return numbers[n - 1];1074 }1075 --k;1076 return numbers[k] + d * (numbers[k + 1] - numbers[k]);1077 }1078 function _percentile_inc(numbers, p){1079 // algorithm from https://en.wikipedia.org/wiki/Percentile#Microsoft_Excel_method1080 var rank = p * (numbers.length - 1) + 1;1081 return _percentile(numbers, rank);1082 }1083 function _percentile_exc(numbers, p){1084 // https://en.wikipedia.org/wiki/Percentile#NIST_method1085 var rank = p * (numbers.length + 1);1086 return _percentile(numbers, rank);1087 }1088 defineFunction("percentile.inc", _percentile_inc).args([1089 [ "numbers", [ "collect", "number", 1 ] ],1090 [ "p", [ "and", "number", [ "[between]", 0, 1 ] ] ]1091 ]);1092 defineFunction("percentile.exc", _percentile_exc).args([1093 [ "numbers", [ "collect", "number", 1 ] ],1094 [ "p", [ "and", "number", [ "(between)", 0, 1 ] ] ]1095 ]);1096 defineFunction("quartile.inc", function(numbers, quarter){1097 return _percentile_inc(numbers, quarter / 4);1098 }).args([1099 [ "numbers", [ "collect", "number", 1 ] ],1100 [ "quarter", [ "values", 0, 1, 2, 3, 4 ] ]1101 ]);1102 defineFunction("quartile.exc", function(numbers, quarter){1103 return _percentile_exc(numbers, quarter / 4);1104 }).args([1105 [ "numbers", [ "collect", "number", 1 ] ],1106 [ "quarter", [ "values", 0, 1, 2, 3, 4 ] ]1107 ]);1108 defineAlias("quartile", "quartile.inc");1109 defineAlias("percentile", "percentile.inc");1110 var AGGREGATE_FUNCS = [1111 "AVERAGE", "COUNT", "COUNTA", "MAX", "MIN", "PRODUCT",1112 "STDEV.S", "STDEV.P", "SUM", "VAR.S", "VAR.P", "MEDIAN",1113 "MODE.SNGL", "LARGE", "SMALL", "PERCENTILE.INC",1114 "QUARTILE.INC", "PERCENTILE.EXC", "QUARTILE.EXC"1115 ];1116 function fetchValuesForAggregate(self, args, options) {1117 var values = [];1118 var opt_ignore_hidden_rows = 1;1119 var opt_ignore_errors = 2;1120 var opt_use_aggregates = 4;1121 (function fetchValues(args) {1122 if (args instanceof Ref) {1123 self.getRefCells(args, true).forEach(function(cell){1124 var value = cell.value;1125 if ((options & opt_ignore_hidden_rows) && cell.hidden) {1126 return;1127 }1128 if (cell.formula) {1129 // XXX: formula.print is fast, but still, can't we do any better here?1130 // perhaps access the input string directly somehow?1131 var str = cell.formula.print(cell.row, cell.col);1132 if (/^\s*(?:aggregate|subtotal)\s*\(/i.test(str)) {1133 if (!(options & opt_use_aggregates)) {1134 return;1135 }1136 }1137 }1138 if ((options & opt_ignore_errors) && value instanceof CalcError) {1139 return;1140 }1141 if (typeof value == "number" || value instanceof CalcError) {1142 values.push(value);1143 }1144 });1145 } else if (Array.isArray(args)) {1146 for (var i = 0; i < args.length; ++i) {1147 fetchValues(args[i]);1148 }1149 } else if (args instanceof Matrix) {1150 args.each(fetchValues);1151 } else if (typeof args == "number") {1152 values.push(args);1153 } else if (args instanceof CalcError && !(options & opt_ignore_errors)) {1154 values.push(args);1155 }1156 })(args);1157 return values;1158 }1159 // AGGREGATE function1160 //1161 // https://support.office.com/en-SG/article/aggregate-function-c8caed56-07df-4aeb-9741-23693ffbe5251162 //1163 // we can only partially type-check this function. also, we need to use the async version in1164 // order to resolve references and delegate values to the function to aggregate.1165 defineFunction("aggregate", function(callback, funcId, options, args){1166 // options is a bit field. that makes sense; it's the documentation which doesn't.1167 var self = this;1168 self.resolveCells(args, function(){1169 var values;1170 if (funcId > 12) {1171 // "array form"1172 values = fetchValuesForAggregate(self, args[0], options);1173 var k = args[1];1174 if (k instanceof CellRef) {1175 k = self.getRefData(k);1176 }1177 if (typeof k != "number") {1178 return callback(new CalcError("VALUE"));1179 }1180 } else {1181 values = fetchValuesForAggregate(self, args, options);1182 }1183 self.func(AGGREGATE_FUNCS[funcId - 1], callback, values);1184 });1185 }).argsAsync([1186 [ "funcId", [ "values", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,1187 11, 12, 13, 14, 15, 16, 17, 18, 19 ] ],1188 [ "options", [ "or",1189 [ "null", 0 ],1190 [ "values", 0, 1, 2, 3, 4, 5, 6, 7 ] ] ],1191 [ "args", "rest" ]1192 ]);1193 defineFunction("subtotal", function(callback, funcId){1194 var self = this;1195 var ignoreHidden = funcId > 100;1196 if (ignoreHidden) {1197 funcId -= 100;1198 }1199 var args = [];1200 for (var i = 2; i < arguments.length; ++i) {1201 args.push(arguments[i]);1202 }1203 self.resolveCells(args, function(){1204 var values = fetchValuesForAggregate(self, args, ignoreHidden ? 1 : 0);1205 self.func(AGGREGATE_FUNCS[funcId - 1], callback, values);1206 });1207 }).argsAsync([1208 [ "funcId", [ "values", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,1209 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111 ] ],1210 [ "+", [ "ref", [ "or", "ref", "#matrix" ] ] ]1211 ]);1212 // https://support.office.com/en-sg/article/AVEDEV-function-ec78fa01-4755-466c-9a2b-0c4f9eacaf6d1213 defineFunction("avedev", function(numbers){1214 var avg = numbers.reduce(function(sum, num){1215 return sum + num;1216 }, 0) / numbers.length;1217 return numbers.reduce(function(sum, num){1218 return sum + Math.abs(num - avg);1219 }, 0) / numbers.length;1220 }).args([1221 [ "numbers", [ "collect", "number" ] ],1222 [ "?", [ "assert", "$numbers.length >= 2", "NUM" ] ]1223 ]);1224 function _binom_dist(x, n, p, cumulative) {1225 if (!cumulative) {1226 return _combinations(n, x) * Math.pow(p, x) * Math.pow(1-p, n-x);1227 } else {1228 var sum = 0;1229 for (var j = 0; j <= x; ++j) {1230 sum += _combinations(n, j) * Math.pow(p, j) * Math.pow(1-p, n-j);1231 }1232 return sum;1233 }1234 }1235 defineFunction("binom.dist", _binom_dist).args([1236 [ "successes", "integer+" ],1237 [ "trials", [ "and", "integer", [ "assert", "$trials >= $successes" ] ] ],1238 [ "probability", [ "and", "number", [ "[between]", 0, 1 ] ] ],1239 [ "cumulative", "logical" ]1240 ]);1241 defineAlias("binomdist", "binom.dist");1242 defineFunction("binom.inv", function(n, p, alpha){1243 // XXX: could a binary search be faster?1244 for (var x = 0; x <= n; ++x) {1245 if (_binom_dist(x, n, p, true) >= alpha) {1246 return x;1247 }1248 }1249 return new CalcError("N/A"); // XXX: is this right?1250 }).args([1251 [ "trials", "integer+" ],1252 [ "probability", [ "and", "number", [ "[between]", 0, 1 ] ] ],1253 [ "alpha", [ "and", "number", [ "[between]", 0, 1 ] ] ]1254 ]);1255 defineAlias("critbinom", "binom.inv");1256 defineFunction("binom.dist.range", function(n, p, s, s2){1257 var sum = 0;1258 for (var k = s; k <= s2; ++k) {1259 sum += _combinations(n, k) * Math.pow(p, k) * Math.pow(1-p, n-k);1260 }1261 return sum;1262 }).args([1263 [ "trials", "integer+" ],1264 [ "probability", [ "and", "number", [ "[between]", 0, 1 ] ] ],1265 [ "successes_min", [ "and", "integer", [ "[between]", 0, "$trials" ] ] ],1266 [ "successes_max", [ "or",1267 [ "and", "integer",1268 [ "[between]", "$successes_min", "$trials" ] ],1269 [ "null", "$successes_min" ] ] ]1270 ]);1271 defineFunction("negbinom.dist", function(x, k, p, cumulative){1272 if (cumulative) {1273 var sum = 0;1274 while (x >= 0) {1275 sum += _combinations(x+k-1, x) * Math.pow(p, k) * Math.pow(1-p, x);1276 x--;1277 }1278 return sum;1279 }1280 return _combinations(x+k-1, x) * Math.pow(p, k) * Math.pow(1-p, x);1281 }).args([1282 [ "number_f", "integer+" ],1283 [ "number_s", "integer+" ],1284 [ "probability_s", [ "and", "number", [ "[between]", 0, 1 ] ] ],1285 [ "cumulative", "logical" ]1286 ]);1287 defineAlias("negbinomdist", "negbinom.dist");1288 /* -----[ lookup functions ]----- */1289 defineFunction("address", function(row, col, abs, a1, sheet){1290 // by some lucky coincidence, we get the corret `rel` value by just subtracting 1 from the1291 // abs argument1292 var cell = new CellRef(row - 1, col - 1, abs - 1);1293 if (sheet) {1294 cell.setSheet(sheet, true);1295 }1296 return a1 ? cell.print(0, 0) : cell.print();1297 }).args([1298 [ "row", "integer++" ],1299 [ "col", "integer++" ],1300 [ "abs", [ "or", [ "null", 1 ], [ "values", 1, 2, 3, 4 ]]],1301 [ "a1", [ "or", [ "null", true ], "logical" ]],1302 [ "sheet", [ "or", "null", "string" ]]1303 ]);1304 defineFunction("areas", function(ref){1305 var count = 0;1306 (function loop(x){1307 if (x instanceof CellRef || x instanceof RangeRef) {1308 count++;1309 } else if (x instanceof UnionRef) {1310 x.refs.forEach(loop);1311 }1312 // XXX: NameRef if we add support1313 })(ref);1314 return count;1315 }).args([1316 [ "ref", "ref" ]1317 ]);1318 defineFunction("choose", function(index, args){1319 if (index > args.length) {1320 return new CalcError("N/A");1321 } else {1322 return args[index - 1];1323 }1324 }).args([1325 [ "*index", "integer" ],1326 [ "+", [ "value", "anything" ] ]1327 ]);1328 defineFunction("column", function(ref){1329 if (!ref) {1330 return this.formula.col + 1;1331 }1332 if (ref instanceof CellRef) {1333 return ref.col + 1;1334 }1335 return this.asMatrix(ref).mapCol(function(col){1336 return col + ref.topLeft.col + 1;1337 });1338 }).args([1339 [ "ref", [ "or", "area", "null" ]]1340 ]);1341 defineFunction("columns", function(m){1342 return m instanceof Ref ? m.width() : m.width;1343 }).args([1344 [ "ref", [ "or", "area", "#matrix" ] ]1345 ]);1346 defineFunction("formulatext", function(ref){1347 var cell = this.getRefCells(ref)[0]; // XXX: overkill, but oh well.1348 if (!cell.formula) {1349 return new CalcError("N/A");1350 }1351 return cell.formula.print(cell.row, cell.col);1352 }).args([1353 [ "ref", "ref" ]1354 ]);1355 defineFunction("hlookup", function(value, m, row, approx){1356 var resultCol = null;1357 m.eachCol(function(col){1358 var data = m.get(0, col);1359 if (approx) {1360 if (data > value) {1361 return true;1362 }1363 resultCol = col;1364 } else if (data === value) {1365 resultCol = col;1366 return true;1367 }1368 });1369 if (resultCol == null) {1370 return new CalcError("N/A");1371 }1372 return m.get(row - 1, resultCol);1373 }).args([1374 [ "value", "anyvalue" ],1375 [ "range", "matrix" ],1376 [ "row", "integer++" ],1377 [ "approx", [ "or", "logical", [ "null", true ]]]1378 ]);1379 defineFunction("index", function(callback, ref, row, col, areanum){1380 var self = this;1381 if (ref instanceof UnionRef) {1382 ref = ref.refs[areanum - 1];1383 }1384 if ((!row && !col) || !ref) {1385 return callback(new CalcError("N/A"));1386 }1387 if (ref instanceof CellRef) {1388 ref = ref.toRangeRef();1389 }1390 if (ref instanceof RangeRef) {1391 if (row && col) {1392 if (col > ref.width() || row > ref.height()) {1393 return callback(new CalcError("REF"));1394 }1395 // fetching a single cell1396 var cell = ref.toCell(row - 1, col - 1);1397 self.resolveCells([ cell ], function(){1398 callback(self.getRefData(cell));1399 });1400 return;1401 }1402 if (!row) {1403 // fetch a full column1404 var colRange = ref.toColumn(col - 1);1405 self.resolveCells([ colRange ], function(){1406 callback(self.asMatrix(colRange));1407 });1408 return;1409 }1410 if (!col) {1411 // fetch a full row1412 var rowRange = ref.toRow(row - 1);1413 self.resolveCells([ rowRange ], function(){1414 callback(self.asMatrix(rowRange));1415 });1416 return;1417 }1418 }1419 else if (ref instanceof Matrix) {1420 if (ref.width > 1 && ref.height > 1) {1421 if (row && col) {1422 return callback(ref.get(row - 1, col - 1));1423 }1424 if (!row) {1425 return callback(ref.mapRow(function(row){1426 return ref.get(row, col - 1);1427 }));1428 }1429 if (!col) {1430 return callback(ref.mapCol(function(col){1431 return ref.get(row - 1, col);1432 }));1433 }1434 }1435 if (ref.width == 1) {1436 return callback(ref.get(row - 1, 0));1437 }1438 if (ref.height == 1) {1439 return callback(ref.get(0, col - 1));1440 }1441 }1442 else {1443 callback(new CalcError("REF"));1444 }1445 }).argsAsync([1446 [ "range", [ "or", "ref", "matrix" ] ],1447 [ "row", [ "or", "integer+", "null" ] ],1448 [ "col", [ "or", "integer+", "null" ] ],1449 [ "areanum", [ "or", "integer++", [ "null", 1 ] ] ]1450 ]);1451 defineFunction("indirect", function(thing){1452 try {1453 // XXX: does more work than needed. we could go for parseReference, but that one1454 // doesn't (yet?) support "SheetName!" prefix.1455 var f = this.formula;1456 var exp = calc.parseFormula(f.sheet, f.row, f.col, thing);1457 var ref = exp.ast;1458 if (ref instanceof NameRef) {1459 ref = this.ss.nameValue(ref, f.sheet, f.row, f.col);1460 }1461 if (!(ref instanceof Ref)) {1462 throw 1;1463 }1464 return ref.absolute(f.row, f.col);1465 } catch(ex) {1466 return new CalcError("REF");1467 }1468 }).args([1469 [ "thing", "string" ]1470 ]);1471 // XXX: LOOKUP. seems to be deprecated in favor of HLOOKUP/VLOOKUP1472 // XXX: double-check this one.1473 defineFunction("match", function(val, m, type){1474 var index = 1, cmp;1475 if (type === 0) {1476 cmp = parseCriteria(val);1477 } else if (type === -1) {1478 cmp = parseCriteria("<=" + val);1479 } else if (type === 1) {1480 cmp = parseCriteria(">=" + val);1481 }1482 if (m.each(function(el){1483 if (el != null && cmp(el)) {1484 if (type !== 0 && val != el) {1485 --index;1486 }1487 return true;1488 }1489 index++;1490 }, true) && index > 0) {1491 return index;1492 } else {1493 return new CalcError("N/A");1494 }1495 }).args([1496 [ "value", "anyvalue" ],1497 [ "range", "matrix" ],1498 [ "type", [ "or",1499 [ "values", -1, 0, 1 ],1500 [ "null", 1 ]]]1501 ]);1502 defineFunction("offset", function(ref, rows, cols, height, width){1503 var topLeft = (ref instanceof CellRef ? ref : ref.topLeft).clone();1504 topLeft.row += rows;1505 topLeft.col += cols;1506 if (topLeft.row < 0 || topLeft.col < 0) {1507 return new CalcError("VALUE");1508 }1509 if (height > 1 || width > 1) {1510 return new RangeRef(topLeft, new CellRef(topLeft.row + height - 1,1511 topLeft.col + width - 1))1512 .setSheet(ref.sheet, ref.hasSheet());1513 }1514 return topLeft;1515 }).args([1516 [ "ref", "area" ],1517 [ "*rows", "integer" ],1518 [ "*cols", "integer" ],1519 [ "*height", [ "or", "integer++", [ "null", "$ref.height()" ]]],1520 [ "*width", [ "or", "integer++", [ "null", "$ref.width()" ]]]1521 ]);1522 defineFunction("row", function(ref){1523 if (!ref) {1524 return this.formula.row + 1;1525 }1526 if (ref instanceof CellRef) {1527 return ref.row + 1;1528 }1529 return this.asMatrix(ref).mapRow(function(row){1530 return row + ref.topLeft.row + 1;1531 });1532 }).args([1533 [ "ref", [ "or", "area", "null" ]]1534 ]);1535 defineFunction("rows", function(m){1536 return m instanceof Ref ? m.height() : m.height;1537 }).args([1538 [ "ref", [ "or", "area", "#matrix" ] ]1539 ]);1540 defineFunction("vlookup", function(value, m, col, approx){1541 var resultRow = null;1542 if (typeof value != "number") {1543 approx = false;1544 }1545 if (typeof value == "string") {1546 value = value.toLowerCase();1547 }1548 m.eachRow(function(row){1549 var data = m.get(row, 0);1550 if (approx) {1551 if (data > value) {1552 return true;1553 }1554 resultRow = row;1555 } else {1556 if (typeof data == "string") {1557 data = data.toLowerCase();1558 }1559 if (data === value) {1560 resultRow = row;1561 return true;1562 }1563 }1564 });1565 if (resultRow == null) {1566 return new CalcError("N/A");1567 }1568 return m.get(resultRow, col - 1);1569 }).args([1570 [ "value", "anyvalue" ],1571 [ "range", "matrix" ],1572 [ "col", "integer++" ],1573 [ "approx", [ "or", "logical", [ "null", true ]]]1574 ]);1575 /* -----[ Date and time functions ]----- */1576 defineFunction("date", function(year, month, date){1577 return packDate(year, month-1, date);1578 }).args([1579 [ "*year", "integer" ],1580 [ "*month", "integer" ],1581 [ "*date", "integer" ]1582 ]);1583 defineFunction("day", function(date){1584 return unpackDate(date).date;1585 }).args([1586 [ "*date", "date" ]1587 ]);1588 defineFunction("month", function(date){1589 return unpackDate(date).month + 1;1590 }).args([1591 [ "*date", "date" ]1592 ]);1593 defineFunction("year", function(date){1594 return unpackDate(date).year;1595 }).args([1596 [ "*date", "date" ]1597 ]);1598 defineFunction("weekday", function(date){1599 // XXX: TODO type1600 return unpackDate(date).day + 1;1601 }).args([1602 [ "*date", "date" ]1603 ]);1604 // https://support.office.com/en-GB/article/WEEKNUM-function-e5c43a03-b4ab-426c-b411-b18c13c753401605 // XXX: this is a mess.1606 defineFunction("weeknum", function(date, type){1607 var fw = packDate(unpackDate(date).year, 0, 1);1608 var sy = unpackDate(fw);1609 var diff;1610 if (type == 21) {1611 // Monday-based weeks, first week is the one containing the first Thursday of the year1612 // we want to place in fw and sy the first Thursday1613 diff = 3 - (sy.day + 6) % 7;1614 if (diff < 0) {1615 diff += 7;1616 }1617 fw += diff;1618 sy.date += diff;1619 sy.day = 4; // Thursday.1620 type = 1;1621 } else {1622 if (type == 1) {1623 type = 0;1624 } else if (type == 2) {1625 type = 1;1626 } else {1627 type = (type - 10) % 7;1628 }1629 // finally compatible with what we got:1630 // type == 0 means week starts on Sunday1631 // 1 Monday1632 // 2 Tuesday1633 // ...1634 }1635 diff = sy.day - type;1636 if (diff < 0) {1637 diff += 7;1638 }1639 fw -= diff;1640 return Math.ceil((date + 1 - fw) / 7);1641 }).args([1642 [ "*date", "date" ],1643 [ "*type", [ "or", [ "null", 1 ],1644 [ "values", 1, 2, 11, 12, 13, 14, 15, 16, 17, 21 ] ] ]1645 ]);1646 function weeksInYear(year) {1647 var d = unpackDate(packDate(year, 0, 1));1648 if ((d.day == 4) || (d.day == 3 && runtime.isLeapYear(year))) {1649 // long year1650 return 53;1651 }1652 return 52;1653 }1654 defineFunction("isoweeknum", function isoweeknum(date){1655 // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_of_a_given_date1656 var d = unpackDate(date);1657 var dow = d.day || 7;1658 var wk = Math.floor((d.ord - dow + 10) / 7);1659 if (wk < 1) {1660 return weeksInYear(d.year - 1);1661 } else if (wk == 53 && wk > weeksInYear(d.year)) {1662 return 1;1663 }1664 return wk;1665 }).args([1666 [ "*date", "date" ]1667 ]);1668 defineFunction("now", function(){1669 return runtime.dateToSerial(new Date());1670 }).args([]);1671 defineFunction("today", function(){1672 return runtime.dateToSerial(new Date()) | 0;1673 }).args([]);1674 defineFunction("time", function(hh, mm, ss){1675 return runtime.packTime(hh, mm, ss, 0);1676 }).args([1677 [ "*hours", "integer" ],1678 [ "*minutes", "integer" ],1679 [ "*seconds", "integer" ]1680 ]);1681 defineFunction("hour", function(time){1682 return runtime.unpackTime(time).hours;1683 }).args([1684 [ "*time", "datetime" ]1685 ]);1686 defineFunction("minute", function(time){1687 return runtime.unpackTime(time).minutes;1688 }).args([1689 [ "*time", "datetime" ]1690 ]);1691 defineFunction("second", function(time){1692 return runtime.unpackTime(time).seconds;1693 }).args([1694 [ "*time", "datetime" ]1695 ]);1696 defineFunction("edate", function(base, months){1697 var d = unpackDate(base);1698 var m = d.month + months;1699 var y = d.year + Math.floor(m/12);1700 m %= 12;1701 if (m < 0) {1702 m += 12;1703 }1704 d = Math.min(d.date, daysInMonth(y, m));1705 return packDate(y, m, d);1706 }).args([1707 [ "*start_date", "date" ],1708 [ "*months", "integer" ]1709 ]);1710 defineFunction("eomonth", function(base, months){1711 var d = unpackDate(base);1712 var m = d.month + months;1713 var y = d.year + Math.floor(m/12);1714 m %= 12;1715 if (m < 0) {1716 m += 12;1717 }1718 d = daysInMonth(y, m);1719 return packDate(y, m, d);1720 }).args([1721 [ "*start_date", "date" ],1722 [ "*months", "integer" ]1723 ]);1724 defineFunction("workday", function(date, n, holidays){1725 // XXX: the algorithm here is pretty dumb, can we do better?1726 var inc = n > 0 ? 1 : -1;1727 n = Math.abs(n);1728 var dow = unpackDate(date).day;1729 while (n > 0) {1730 date += inc;1731 dow = (dow + inc) % 7;1732 if (dow > 0 && dow < 6 && holidays.indexOf(date) < 0) {1733 --n;1734 }1735 }1736 return date;1737 }).args([1738 [ "start_date", "date" ],1739 [ "days", "integer" ],1740 [ "holidays", [ "collect", "date" ] ]1741 ]);1742 defineFunction("networkdays", function(date, end, holidays){1743 // XXX: the algorithm here is pretty dumb, can we do better?1744 if (date > end) {1745 var tmp = date;1746 date = end;1747 end = tmp;1748 }1749 var count = 0;1750 var dow = unpackDate(date).day;1751 while (date <= end) {1752 if (dow > 0 && dow < 6 && holidays.indexOf(date) < 0) {1753 count++;1754 }1755 date++;1756 dow = (dow + 1) % 7;1757 }1758 return count;1759 }).args([1760 [ "start_date", "date" ],1761 [ "end_date", "date" ],1762 [ "holidays", [ "collect", "date" ] ]1763 ]);1764 defineFunction("days", function(start, end){1765 return end - start;1766 }).args([1767 [ "*start_date", "date" ],1768 [ "*end_date", "date" ]1769 ]);1770 function _days_360(start, end, method) {1771 var d1 = unpackDate(start);1772 var d2 = unpackDate(end);1773 // https://en.wikipedia.org/wiki/360-day_calendar1774 // humanity is a mess.1775 if (method) {1776 // EU method1777 if (d1.date == 31) {1778 d1.date = 30;1779 }1780 if (d2.date == 31) {1781 d2.date = 30;1782 }1783 } else {1784 // US method1785 if (d1.month == 1 && d2.month == 11786 && d1.date == daysInMonth(d1.year, 1)1787 && d2.date == daysInMonth(d2.year, 1)) {1788 d2.date = 30;1789 }1790 if (d1.date == daysInMonth(d1.year, d1.month)) {1791 d1.date = 30;1792 if (d2.date == 31) {1793 d2.date = 30;1794 }1795 } else {1796 if (d1.date == 30 && d2.date == 31) {1797 d2.date = 30;1798 }1799 }1800 }1801 return (360 * (d2.year - d1.year)1802 + 30 * (d2.month - d1.month)1803 + (d2.date - d1.date));1804 }1805 runtime._days_360 = _days_360;1806 defineFunction("days360", _days_360).args([1807 [ "*start_date", "date" ],1808 [ "*end_date", "date" ],1809 [ "*method", [ "or", "logical", [ "null", false ] ] ]1810 ]);1811 defineFunction("yearfrac", function(start, end, method){1812 switch (method) {1813 case 0:1814 return _days_360(start, end, false) / 360;1815 case 1:1816 return (end - start) / daysInYear(unpackDate(start).year);1817 case 2:1818 return (end - start) / 360;1819 case 3:1820 return (end - start) / 365;1821 case 4:1822 return _days_360(start, end, true) / 360;1823 }1824 }).args([1825 [ "*start_date", "date" ],1826 [ "*end_date", "date" ],1827 [ "*method", [ "or", [ "null", 0 ], [ "values", 0, 1, 2, 3, 4 ] ] ]1828 ]);1829 defineFunction("datevalue", function(text){1830 var date = runtime.parseDate(text);1831 if (date) {1832 return runtime.dateToSerial(date);1833 }1834 return new CalcError("VALUE");1835 }).args([1836 [ "*text", "string" ]1837 ]);1838 defineFunction("timevalue", function(text){1839 var m = text.toLowerCase().match(/(\d+):(\d+)(:(\d+)(\.(\d+))?)?\s*(am?|pm?)?/);1840 if (m) {1841 var hh = parseFloat(m[1]);1842 var mm = parseFloat(m[2]);1843 var ss = m[3] ? parseFloat(m[4]) : 0;1844 //var ms = m[5] ? parseFloat(m[6]) : 0;1845 var ampm = m[7];1846 if (ampm && (hh > 12 || hh < 1)) {1847 return new CalcError("VALUE");1848 }1849 if (/^p/.test(ampm)) {1850 hh += 12;1851 }1852 return runtime.packTime(hh, mm, ss, 0);1853 }1854 return new CalcError("VALUE");1855 }).args([1856 [ "*text", "string" ]1857 ]);1858 /* -----[ Matrix functions ]----- */1859 defineFunction("mdeterm", function(m){1860 var error = m.each(function(val){1861 if (typeof val != "number") {1862 return new CalcError("VALUE");1863 }1864 }, true);1865 return error || m.determinant();1866 }).args([1867 [ "m", [ "and", "matrix",1868 [ "assert", "$m.width == $m.height" ] ] ]1869 ]);1870 defineFunction("transpose", function(m){1871 return m.transpose();1872 }).args([1873 [ "range", "matrix" ]1874 ]);1875 defineFunction("mmult", function(a, b){1876 return a.multiply(b);1877 }).args([1878 [ "a", "matrix" ],1879 [ "b", [ "and", "matrix",1880 [ "assert", "$b.height == $a.width" ] ] ]1881 ]);1882 defineFunction("munit", function(n){1883 return new Matrix(this).unit(n);1884 }).args([1885 [ "n", "integer+" ]1886 ]);1887 defineFunction("minverse", function(m){1888 var error = m.each(function(val){1889 if (typeof val != "number") {1890 return new CalcError("VALUE");1891 }1892 }, true);1893 return error || m.inverse() || new CalcError("VALUE");1894 }).args([1895 [ "m", [ "and", "matrix",1896 [ "assert", "$m.width == $m.height" ] ] ]1897 ]);1898 /* -----[ Other ]----- */1899 defineFunction("rand", function() {1900 return Math.random();1901 }).args([]);1902 defineFunction("randbetween", function(min, max){1903 return min + Math.floor((max - min + 1) * Math.random());1904 }).args([1905 [ "min", "integer" ],1906 [ "max", [ "and", "integer", [ "assert", "$max >= $min" ] ] ]1907 ]);1908 defineFunction("true", function(){1909 return true;1910 }).args([]);1911 defineFunction("false", function(){1912 return true;1913 }).args([]);1914 defineFunction("roman", function(num){1915 return util.arabicToRoman(num).toUpperCase();1916 }).args([1917 [ "*number", "integer" ]1918 ]);1919 defineFunction("arabic", function(rom){1920 var num = util.romanToArabic(rom);1921 return num == null ? new CalcError("VALUE") : num;1922 }).args([1923 [ "*roman", "string" ]1924 ]);1925 defineFunction("base", function(number, radix, minLen){1926 var str = number.toString(radix).toUpperCase();1927 while (str.length < minLen) {1928 str = "0" + str;1929 }1930 return str;1931 }).args([1932 [ "*number", "integer" ],1933 [ "*radix", [ "and", "integer", [ "[between]", 2, 36 ] ] ],1934 [ "*minLen", [ "or", "integer+", [ "null", 0 ] ] ]1935 ]);1936 defineFunction("decimal", function(text, radix){1937 text = text.toUpperCase();1938 var val = 0;1939 for (var i = 0; i < text.length; ++i) {1940 var d = text.charCodeAt(i);1941 if (d >= 48 && d <= 57) {1942 d -= 48;1943 } else if (d >= 65 && d < (55 + radix)) {1944 d -= 55;1945 } else {1946 return new CalcError("VALUE");1947 }1948 val = val * radix + d;1949 }1950 return val;1951 }).args([1952 [ "*text", "string" ],1953 [ "*radix", [ "and", "integer", [ "[between]", 2, 36 ] ] ]1954 ]);1955 /* -----[ String functions ]----- */1956 defineFunction("char", function(code){1957 return String.fromCharCode(code);1958 }).args([1959 [ "*code", "integer+" ]1960 ]);1961 // From XRegExp1962 var RX_NON_PRINTABLE = /[\0-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;1963 defineFunction("clean", function(text){1964 return text.replace(RX_NON_PRINTABLE, "");1965 }).args([1966 [ "*text", "string" ]1967 ]);1968 defineFunction("code", function(text){1969 return text.charAt(0);1970 }).args([1971 [ "*text", "string" ]1972 ]);1973 defineAlias("unichar", "char");1974 defineAlias("unicode", "code");1975 defineFunction("concatenate", function(args){1976 var out = "";1977 for (var i = 0; i < args.length; ++i) {1978 out += args[i];1979 }1980 return out;1981 }).args([1982 [ "+",1983 [ "*text", "string" ] ]1984 ]);1985 defineFunction("dollar", function(number, decimals){1986 var format = "$#,##0DECIMALS;($#,##0DECIMALS)";1987 var dec = "";1988 var denomitator = 1;1989 while (decimals-- > 0) {1990 dec += "0";1991 }1992 while (++decimals < 0) {1993 denomitator *= 10;1994 }1995 if (dec !== "") {1996 dec = "." + dec;1997 } else if (denomitator !== 1) {1998 number = Math.round(number / denomitator) * denomitator;1999 }2000 format = format.replace(/DECIMALS/g, dec);2001 return spreadsheet.formatting.text(number, format);2002 }).args([2003 [ "*number", "number" ],2004 [ "*decimals", [ "or", "integer", [ "null", 2 ] ] ]2005 ]);2006 defineFunction("exact", function(a, b){2007 return a === b;2008 }).args([2009 [ "*text1", "string" ],2010 [ "*text2", "string" ]2011 ]);2012 defineFunction("find", function(substring, string, start){2013 var pos = string.indexOf(substring, start - 1);2014 return pos < 0 ? new CalcError("VALUE") : pos + 1;2015 }).args([2016 [ "*substring", "string" ],2017 [ "*string", "string" ],2018 [ "*start", [ "or", "integer++", [ "null", 1 ] ] ]2019 ]);2020 defineFunction("fixed", function(number, decimals, noCommas){2021 var scale = Math.pow(10, decimals);2022 number = Math.round(number * scale) / scale;2023 var format = noCommas ? "0" : "#,##0";2024 if (decimals > 0) {2025 format += ".";2026 while (decimals-- > 0) { format += "0"; }2027 }2028 return spreadsheet.formatting.text(number, format);2029 }).args([2030 [ "*number", "number" ],2031 [ "*decimals", [ "or", "integer", [ "null", 2 ] ] ],2032 [ "*noCommas", [ "or", "boolean", [ "null", false ] ] ]2033 ]);2034 defineFunction("left", function(text, length){2035 return text.substr(0, length);2036 }).args([2037 [ "*text", "string" ],2038 [ "*length", [ "or", "integer+", [ "null", 1 ] ] ]2039 ]);2040 defineFunction("right", function(text, length){2041 return text.substr(-length);2042 }).args([2043 [ "*text", "string" ],2044 [ "*length", [ "or", "integer+", [ "null", 1 ] ] ]2045 ]);2046 defineFunction("len", function(text){2047 return text.length;2048 }).args([2049 [ "*text", "string" ]2050 ]);2051 defineFunction("lower", function(text){2052 return text.toLowerCase();2053 }).args([2054 [ "*text", "string" ]2055 ]);2056 defineFunction("upper", function(text){2057 return text.toUpperCase();2058 }).args([2059 [ "*text", "string" ]2060 ]);2061 defineFunction("ltrim", function(text){2062 return text.replace(/^\s+/, "");2063 }).args([2064 [ "*text", "string" ]2065 ]);2066 defineFunction("rtrim", function(text){2067 return text.replace(/\s+$/, "");2068 }).args([2069 [ "*text", "string" ]2070 ]);2071 defineFunction("trim", function(text){2072 return text.replace(/^\s+|\s+$/, "");2073 }).args([2074 [ "*text", "string" ]2075 ]);2076 defineFunction("mid", function(text, start, length){2077 return text.substr(start - 1, length);2078 }).args([2079 [ "*text", "string" ],2080 [ "*start", "integer++" ],2081 [ "*length", "integer+" ]2082 ]);2083 defineFunction("proper", function(text){2084 return text.toLowerCase().replace(/\b./g, function(s){2085 return s.toUpperCase();2086 });2087 }).args([2088 [ "*text", "string" ]2089 ]);2090 defineFunction("replace", function(text, start, length, newText){2091 return text.substr(0, --start) + newText + text.substr(start + length);2092 }).args([2093 [ "*text", "string" ],2094 [ "*start", "integer++" ],2095 [ "*length", "integer+" ],2096 [ "*newText", "string" ]2097 ]);2098 defineFunction("rept", function(text, number){2099 var out = "";2100 while (number-- > 0) { out += text; }2101 return out;2102 }).args([2103 [ "*text", "string" ],2104 [ "*number", "integer+" ]2105 ]);2106 defineFunction("search", function(substring, string, start){2107 var pos = string.toLowerCase().indexOf(substring.toLowerCase(), start - 1);2108 return pos < 0 ? new CalcError("VALUE") : pos + 1;2109 }).args([2110 [ "*substring", "string" ],2111 [ "*string", "string" ],2112 [ "*start", [ "or", "integer++", [ "null", 1 ] ] ]2113 ]);2114 defineFunction("substitute", function(text, oldText, newText, nth){2115 if (oldText === newText) {2116 return text;2117 }2118 var a = text.split(oldText);2119 if (nth == null) {2120 return a.join(newText);2121 }2122 text = "";2123 nth--;2124 for (var i = 0; i < a.length; ++i) {2125 text += a[i];2126 if (i < a.length - 1) {2127 if (i === nth) {2128 text += newText;2129 } else {2130 text += oldText;2131 }2132 }2133 }2134 return text;2135 }).args([2136 [ "*text", "string" ],2137 [ "*oldText", "string" ],2138 [ "*newText", "string" ],2139 [ "*nth", [ "or", "integer++", "null" ] ]2140 ]);2141 defineFunction("t", function(value){2142 return typeof value == "string" ? value : "";2143 }).args([2144 [ "*value", "anyvalue" ]2145 ]);2146 defineFunction("text", function(value, format){2147 return spreadsheet.formatting.text(value, format);2148 }).args([2149 [ "*value", "anyvalue" ],2150 [ "*format", "string" ]2151 ]);2152 defineFunction("value", function(value){2153 if (typeof value == "number") {2154 return value;2155 }2156 if (typeof value == "boolean") {2157 return +value;2158 }2159 // XXX: this is dirty. we need it so we can parse i.e. "$12,345.50"2160 value = (value+"").replace(/[$€,]/g, "");2161 value = parseFloat(value);2162 return isNaN(value) ? new CalcError("VALUE") : value;2163 }).args([2164 [ "*value", "anyvalue" ]2165 ]);2166 function Hyperlink(link, text) {2167 this.link = link;2168 this.text = text;2169 }2170 Hyperlink.prototype.toString = function() {2171 return this.text;2172 };2173 defineFunction("hyperlink", function(link, text){2174 return new Hyperlink(link, text);2175 }).args([2176 [ "*link", "string" ],2177 [ "*text", [ "or", "string", [ "null", "$link" ] ] ]2178 ]);2179 //// other misc functions2180 defineFunction("iferror", function(value, valueIfError){2181 return value instanceof CalcError ? valueIfError : value;2182 }).args([2183 [ "*value", "forced!" ],2184 [ "*value_if_error", "anyvalue!" ]2185 ]);2186 //// utils2187 var parseCriteria = (function(){2188 var RXCACHE = Object.create(null);2189 function makeComparator(cmp, x) {2190 if (typeof x == "string") {2191 var num = parseFloat(x);2192 if (!isNaN(num) && num == x) {2193 x = num;2194 }...

Full Screen

Full Screen

functions.js

Source:functions.js Github

copy

Full Screen

...18 names: string[],19 props: FunctionPropSpec,20 handler: ?FunctionHandler, // null only if handled in parser21) {22 _defineFunction({names, props, handler});23};24// A normal square root25defineFunction(["\\sqrt"], {26 numArgs: 1,27 numOptionalArgs: 1,28}, function(context, args, optArgs) {29 const index = optArgs[0];30 const body = args[0];31 return {32 type: "sqrt",33 body: body,34 index: index,35 };36});37// Non-mathy text, possibly in a font38const textFunctionFonts = {39 "\\text": undefined, "\\textrm": "mathrm", "\\textsf": "mathsf",40 "\\texttt": "mathtt", "\\textnormal": "mathrm", "\\textbf": "mathbf",41 "\\textit": "textit",42};43defineFunction([44 "\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal",45 "\\textbf", "\\textit",46], {47 numArgs: 1,48 argTypes: ["text"],49 greediness: 2,50 allowedInText: true,51}, function(context, args) {52 const body = args[0];53 return {54 type: "text",55 body: ordargument(body),56 font: textFunctionFonts[context.funcName],57 };58});59// A two-argument custom color60defineFunction(["\\textcolor"], {61 numArgs: 2,62 allowedInText: true,63 greediness: 3,64 argTypes: ["color", "original"],65}, function(context, args) {66 const color = args[0];67 const body = args[1];68 return {69 type: "color",70 color: color.value,71 value: ordargument(body),72 };73});74// \color is handled in Parser.js's parseImplicitGroup75defineFunction(["\\color"], {76 numArgs: 1,77 allowedInText: true,78 greediness: 3,79 argTypes: ["color"],80}, null);81// colorbox82defineFunction(["\\colorbox"], {83 numArgs: 2,84 allowedInText: true,85 greediness: 3,86 argTypes: ["color", "text"],87}, function(context, args) {88 const color = args[0];89 const body = args[1];90 return {91 type: "enclose",92 label: context.funcName,93 backgroundColor: color,94 body: body,95 };96});97// fcolorbox98defineFunction(["\\fcolorbox"], {99 numArgs: 3,100 allowedInText: true,101 greediness: 3,102 argTypes: ["color", "color", "text"],103}, function(context, args) {104 const borderColor = args[0];105 const backgroundColor = args[1];106 const body = args[2];107 return {108 type: "enclose",109 label: context.funcName,110 backgroundColor: backgroundColor,111 borderColor: borderColor,112 body: body,113 };114});115// An overline116defineFunction(["\\overline"], {117 numArgs: 1,118}, function(context, args) {119 const body = args[0];120 return {121 type: "overline",122 body: body,123 };124});125// An underline126defineFunction(["\\underline"], {127 numArgs: 1,128}, function(context, args) {129 const body = args[0];130 return {131 type: "underline",132 body: body,133 };134});135// A box of the width and height136defineFunction(["\\rule"], {137 numArgs: 2,138 numOptionalArgs: 1,139 argTypes: ["size", "size", "size"],140}, function(context, args, optArgs) {141 const shift = optArgs[0];142 const width = args[0];143 const height = args[1];144 return {145 type: "rule",146 shift: shift && shift.value,147 width: width.value,148 height: height.value,149 };150});151// TODO: In TeX, \mkern only accepts mu-units, and \kern does not accept152// mu-units. In current KaTeX we relax this; both commands accept any unit.153defineFunction(["\\kern", "\\mkern"], {154 numArgs: 1,155 argTypes: ["size"],156}, function(context, args) {157 return {158 type: "kern",159 dimension: args[0].value,160 };161});162// A KaTeX logo163defineFunction(["\\KaTeX"], {164 numArgs: 0,165 allowedInText: true,166}, function(context) {167 return {168 type: "katex",169 };170});171import "./functions/phantom";172// Math class commands except \mathop173defineFunction([174 "\\mathord", "\\mathbin", "\\mathrel", "\\mathopen",175 "\\mathclose", "\\mathpunct", "\\mathinner",176], {177 numArgs: 1,178}, function(context, args) {179 const body = args[0];180 return {181 type: "mclass",182 mclass: "m" + context.funcName.substr(5),183 value: ordargument(body),184 };185});186// Build a relation by placing one symbol on top of another187defineFunction(["\\stackrel"], {188 numArgs: 2,189}, function(context, args) {190 const top = args[0];191 const bottom = args[1];192 const bottomop = new ParseNode("op", {193 type: "op",194 limits: true,195 alwaysHandleSupSub: true,196 symbol: false,197 value: ordargument(bottom),198 }, bottom.mode);199 const supsub = new ParseNode("supsub", {200 base: bottomop,201 sup: top,202 sub: null,203 }, top.mode);204 return {205 type: "mclass",206 mclass: "mrel",207 value: [supsub],208 };209});210// \mod-type functions211defineFunction(["\\bmod"], {212 numArgs: 0,213}, function(context, args) {214 return {215 type: "mod",216 modType: "bmod",217 value: null,218 };219});220defineFunction(["\\pod", "\\pmod", "\\mod"], {221 numArgs: 1,222}, function(context, args) {223 const body = args[0];224 return {225 type: "mod",226 modType: context.funcName.substr(1),227 value: ordargument(body),228 };229});230const fontAliases = {231 "\\Bbb": "\\mathbb",232 "\\bold": "\\mathbf",233 "\\frak": "\\mathfrak",234};235// Single-argument color functions236defineFunction([237 "\\blue", "\\orange", "\\pink", "\\red",238 "\\green", "\\gray", "\\purple",239 "\\blueA", "\\blueB", "\\blueC", "\\blueD", "\\blueE",240 "\\tealA", "\\tealB", "\\tealC", "\\tealD", "\\tealE",241 "\\greenA", "\\greenB", "\\greenC", "\\greenD", "\\greenE",242 "\\goldA", "\\goldB", "\\goldC", "\\goldD", "\\goldE",243 "\\redA", "\\redB", "\\redC", "\\redD", "\\redE",244 "\\maroonA", "\\maroonB", "\\maroonC", "\\maroonD", "\\maroonE",245 "\\purpleA", "\\purpleB", "\\purpleC", "\\purpleD", "\\purpleE",246 "\\mintA", "\\mintB", "\\mintC",247 "\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE",248 "\\grayF", "\\grayG", "\\grayH", "\\grayI",249 "\\kaBlue", "\\kaGreen",250], {251 numArgs: 1,252 allowedInText: true,253 greediness: 3,254}, function(context, args) {255 const body = args[0];256 return {257 type: "color",258 color: "katex-" + context.funcName.slice(1),259 value: ordargument(body),260 };261});262// There are 2 flags for operators; whether they produce limits in263// displaystyle, and whether they are symbols and should grow in264// displaystyle. These four groups cover the four possible choices.265// No limits, not symbols266defineFunction([267 "\\arcsin", "\\arccos", "\\arctan", "\\arctg", "\\arcctg",268 "\\arg", "\\ch", "\\cos", "\\cosec", "\\cosh", "\\cot", "\\cotg",269 "\\coth", "\\csc", "\\ctg", "\\cth", "\\deg", "\\dim", "\\exp",270 "\\hom", "\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin",271 "\\sinh", "\\sh", "\\tan", "\\tanh", "\\tg", "\\th",272], {273 numArgs: 0,274}, function(context) {275 return {276 type: "op",277 limits: false,278 symbol: false,279 body: context.funcName,280 };281});282// Limits, not symbols283defineFunction([284 "\\det", "\\gcd", "\\inf", "\\lim", "\\liminf", "\\limsup", "\\max",285 "\\min", "\\Pr", "\\sup",286], {287 numArgs: 0,288}, function(context) {289 return {290 type: "op",291 limits: true,292 symbol: false,293 body: context.funcName,294 };295});296// No limits, symbols297defineFunction([298 "\\int", "\\iint", "\\iiint", "\\oint",299], {300 numArgs: 0,301}, function(context) {302 return {303 type: "op",304 limits: false,305 symbol: true,306 body: context.funcName,307 };308});309// Limits, symbols310defineFunction([311 "\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap",312 "\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes",313 "\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint",314], {315 numArgs: 0,316}, function(context) {317 return {318 type: "op",319 limits: true,320 symbol: true,321 body: context.funcName,322 };323});324// \mathop class command325defineFunction(["\\mathop"], {326 numArgs: 1,327}, function(context, args) {328 const body = args[0];329 return {330 type: "op",331 limits: false,332 symbol: false,333 value: ordargument(body),334 };335});336import "./functions/operators";337// Fractions338defineFunction([339 "\\dfrac", "\\frac", "\\tfrac",340 "\\dbinom", "\\binom", "\\tbinom",341 "\\\\atopfrac", // can’t be entered directly342], {343 numArgs: 2,344 greediness: 2,345}, function(context, args) {346 const numer = args[0];347 const denom = args[1];348 let hasBarLine;349 let leftDelim = null;350 let rightDelim = null;351 let size = "auto";352 switch (context.funcName) {353 case "\\dfrac":354 case "\\frac":355 case "\\tfrac":356 hasBarLine = true;357 break;358 case "\\\\atopfrac":359 hasBarLine = false;360 break;361 case "\\dbinom":362 case "\\binom":363 case "\\tbinom":364 hasBarLine = false;365 leftDelim = "(";366 rightDelim = ")";367 break;368 default:369 throw new Error("Unrecognized genfrac command");370 }371 switch (context.funcName) {372 case "\\dfrac":373 case "\\dbinom":374 size = "display";375 break;376 case "\\tfrac":377 case "\\tbinom":378 size = "text";379 break;380 }381 return {382 type: "genfrac",383 numer: numer,384 denom: denom,385 hasBarLine: hasBarLine,386 leftDelim: leftDelim,387 rightDelim: rightDelim,388 size: size,389 };390});391// Horizontal overlap functions392defineFunction(["\\mathllap", "\\mathrlap", "\\mathclap"], {393 numArgs: 1,394 allowedInText: true,395}, function(context, args) {396 const body = args[0];397 return {398 type: "lap",399 alignment: context.funcName.slice(5),400 body: body,401 };402});403// smash, with optional [tb], as in AMS404defineFunction(["\\smash"], {405 numArgs: 1,406 numOptionalArgs: 1,407 allowedInText: true,408}, function(context, args, optArgs) {409 let smashHeight = false;410 let smashDepth = false;411 const tbArg = optArgs[0];412 if (tbArg) {413 // Optional [tb] argument is engaged.414 // ref: amsmath: \renewcommand{\smash}[1][tb]{%415 // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}%416 let letter = "";417 for (let i = 0; i < tbArg.value.length; ++i) {418 letter = tbArg.value[i].value;419 if (letter === "t") {420 smashHeight = true;421 } else if (letter === "b") {422 smashDepth = true;423 } else {424 smashHeight = false;425 smashDepth = false;426 break;427 }428 }429 } else {430 smashHeight = true;431 smashDepth = true;432 }433 const body = args[0];434 return {435 type: "smash",436 body: body,437 smashHeight: smashHeight,438 smashDepth: smashDepth,439 };440});441import "./functions/delimsizing";442// Sizing functions (handled in Parser.js explicitly, hence no handler)443defineFunction([444 "\\tiny", "\\scriptsize", "\\footnotesize", "\\small",445 "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge",446], {numArgs: 0}, null);447// Style changing functions (handled in Parser.js explicitly, hence no448// handler)449defineFunction([450 "\\displaystyle", "\\textstyle", "\\scriptstyle",451 "\\scriptscriptstyle",452], {numArgs: 0}, null);453// Old font changing functions454defineFunction([455 "\\rm", "\\sf", "\\tt", "\\bf", "\\it", //"\\sl", "\\sc",456], {numArgs: 0}, null);457defineFunction([458 // styles459 "\\mathrm", "\\mathit", "\\mathbf",460 // families461 "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",462 "\\mathtt",463 // aliases464 "\\Bbb", "\\bold", "\\frak",465], {466 numArgs: 1,467 greediness: 2,468}, function(context, args) {469 const body = args[0];470 let func = context.funcName;471 if (func in fontAliases) {472 func = fontAliases[func];473 }474 return {475 type: "font",476 font: func.slice(1),477 body: body,478 };479});480// Accents481defineFunction([482 "\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve",483 "\\check", "\\hat", "\\vec", "\\dot",484 "\\widehat", "\\widetilde", "\\overrightarrow", "\\overleftarrow",485 "\\Overrightarrow", "\\overleftrightarrow", "\\overgroup",486 "\\overlinesegment", "\\overleftharpoon", "\\overrightharpoon",487], {488 numArgs: 1,489}, function(context, args) {490 const base = args[0];491 const isStretchy = !utils.contains([492 "\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve",493 "\\check", "\\hat", "\\vec", "\\dot",494 ], context.funcName);495 const isShifty = !isStretchy || utils.contains([496 "\\widehat", "\\widetilde",497 ], context.funcName);498 return {499 type: "accent",500 label: context.funcName,501 isStretchy: isStretchy,502 isShifty: isShifty,503 base: base,504 };505});506// Text-mode accents507defineFunction([508 "\\'", "\\`", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"',509 "\\r", "\\H", "\\v",510], {511 numArgs: 1,512 allowedInText: true,513 allowedInMath: false,514}, function(context, args) {515 const base = args[0];516 return {517 type: "accent",518 label: context.funcName,519 isStretchy: false,520 isShifty: true,521 base: base,522 };523});524// Horizontal stretchy braces525defineFunction([526 "\\overbrace", "\\underbrace",527], {528 numArgs: 1,529}, function(context, args) {530 const base = args[0];531 return {532 type: "horizBrace",533 label: context.funcName,534 isOver: /^\\over/.test(context.funcName),535 base: base,536 };537});538// Stretchy accents under the body539defineFunction([540 "\\underleftarrow", "\\underrightarrow", "\\underleftrightarrow",541 "\\undergroup", "\\underlinesegment", "\\undertilde",542], {543 numArgs: 1,544}, function(context, args) {545 const base = args[0];546 return {547 type: "accentUnder",548 label: context.funcName,549 base: base,550 };551});552// Stretchy arrows with an optional argument553defineFunction([554 "\\xleftarrow", "\\xrightarrow", "\\xLeftarrow", "\\xRightarrow",555 "\\xleftrightarrow", "\\xLeftrightarrow", "\\xhookleftarrow",556 "\\xhookrightarrow", "\\xmapsto", "\\xrightharpoondown",557 "\\xrightharpoonup", "\\xleftharpoondown", "\\xleftharpoonup",558 "\\xrightleftharpoons", "\\xleftrightharpoons", "\\xLongequal",559 "\\xtwoheadrightarrow", "\\xtwoheadleftarrow", "\\xLongequal",560 "\\xtofrom",561], {562 numArgs: 1,563 numOptionalArgs: 1,564}, function(context, args, optArgs) {565 const below = optArgs[0];566 const body = args[0];567 return {568 type: "xArrow", // x for extensible569 label: context.funcName,570 body: body,571 below: below,572 };573});574// enclose575defineFunction(["\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\fbox"], {576 numArgs: 1,577}, function(context, args) {578 const body = args[0];579 return {580 type: "enclose",581 label: context.funcName,582 body: body,583 };584});585// Infix generalized fractions586defineFunction(["\\over", "\\choose", "\\atop"], {587 numArgs: 0,588 infix: true,589}, function(context) {590 let replaceWith;591 switch (context.funcName) {592 case "\\over":593 replaceWith = "\\frac";594 break;595 case "\\choose":596 replaceWith = "\\binom";597 break;598 case "\\atop":599 replaceWith = "\\\\atopfrac";600 break;601 default:602 throw new Error("Unrecognized infix genfrac command");603 }604 return {605 type: "infix",606 replaceWith: replaceWith,607 token: context.token,608 };609});610// Row breaks for aligned data611defineFunction(["\\\\", "\\cr"], {612 numArgs: 0,613 numOptionalArgs: 1,614 argTypes: ["size"],615}, function(context, args, optArgs) {616 const size = optArgs[0];617 return {618 type: "cr",619 size: size,620 };621});622// Environment delimiters623defineFunction(["\\begin", "\\end"], {624 numArgs: 1,625 argTypes: ["text"],626}, function(context, args) {627 const nameGroup = args[0];628 if (nameGroup.type !== "ordgroup") {629 throw new ParseError("Invalid environment name", nameGroup);630 }631 let name = "";632 for (let i = 0; i < nameGroup.value.length; ++i) {633 name += nameGroup.value[i].value;634 }635 return {636 type: "environment",637 name: name,638 nameGroup: nameGroup,639 };640});641// Box manipulation642defineFunction(["\\raisebox"], {643 numArgs: 2,644 argTypes: ["size", "text"],645 allowedInText: true,646}, function(context, args) {647 const amount = args[0];648 const body = args[1];649 return {650 type: "raisebox",651 dy: amount,652 body: body,653 value: ordargument(body),654 };655});656// \verb and \verb* are dealt with directly in Parser.js.657// If we end up here, it's because of a failure to match the two delimiters658// in the regex in Lexer.js. LaTeX raises the following error when \verb is659// terminated by end of line (or file).660defineFunction(["\\verb"], {661 numArgs: 0,662 allowedInText: true,663}, function(context) {664 throw new ParseError(665 "\\verb ended by end of line instead of matching delimiter");...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const chromy = new Chromy({visible: true});2chromy.chain()3 .evaluate(function() {4 return document.title;5 })6 .result(function(title) {7 console.log(title);8 })9 .end()10 .then(function() {11 console.log('result');12 })13 .catch(function(e) {14 console.log(e);15 });16const chromy = new Chromy({visible: true});17chromy.chain()18 .defineFunction('add', function(a, b) {19 return a + b;20 })21 .evaluate(function() {22 return add(1, 2);23 })24 .result(function(result) {25 console.log(result);26 })27 .end()28 .then(function() {29 console.log('result');30 })31 .catch(function(e) {32 console.log(e);33 });34const chromy = new Chromy({visible: true});35chromy.chain()36 .evaluate(function() {37 return document.title;38 })39 .result(function(title) {40 console.log(title);41 })42 .end()43 .then(function() {44 console.log('result');45 })46 .catch(function(e) {47 console.log(e);48 });49const chromy = new Chromy({visible: true});50chromy.chain()51 .evaluateAsync(function() {52 return new Promise(function(resolve) {53 setTimeout(function() {54 resolve(document.title);55 }, 1000);56 });57 })58 .result(function(title)

Full Screen

Using AI Code Generation

copy

Full Screen

1chromy.defineFunction('add', function(a, b) {2 return a + b;3});4chromy.evaluate(function() {5 return add(1, 2);6}).result(function(value) {7});8chromy.evaluate(function(a, b) {9 return add(a, b);10}, 1, 2).result(function(value) {11});12chromy.evaluate(function(a, b) {13 return add(a, b);14}, 1, 2, function(value) {15});16chromy.evaluate(function(a, b) {17 return add(a, b);18}, 1, 2, function(value) {19}).catch(function(e) {20 console.error(e);21});22chromy.evaluate(function(a, b) {23 return add(a, b);24}, 1, 2, function(value) {25}).catch(function(e) {26 console.error(e);27}).result(function(value) {28});

Full Screen

Using AI Code Generation

copy

Full Screen

1module.exports = function(chromy, scenario, vp) {2 chromy.evaluate(function() {3 defineFunction('window', 'getComputedStyle', function(el) {4 return el.style;5 });6 });7};8module.exports = function(chromy, scenario, vp) {9 chromy.evaluate(function() {10 return document.title;11 }).result(function(title) {12 console.log(title);13 });14};15module.exports = function(chromy, scenario, vp) {16 chromy.evaluateNow(function() {17 return document.title;18 }).result(function(title) {19 console.log(title);20 });21};22module.exports = function(chromy, scenario, vp) {23 chromy.evaluateAsync(function() {24 return document.title;25 }).result(function(title) {26 console.log(title);27 });28};29module.exports = function(chromy, scenario, vp) {30 chromy.wait(1000);31};

Full Screen

Using AI Code Generation

copy

Full Screen

1var chromy = new Chromy();2chromy.chain()3 .evaluate(function () {4 return document.title;5 })6 .result(function (title) {7 console.log(title);8 })9 .end()10 .then(function () {11 chromy.close();12 });13#### new Chromy(options)14Options to pass to [Puppeteer](

Full Screen

Using AI Code Generation

copy

Full Screen

1chromy.defineFunction('addTwo', function(a) {2 return a + 2;3});4chromy.evaluate(function(a) {5 return addTwo(a);6}, 5).result(function(result) {7});8chromy.evaluate(function(a) {9 return addTwo(a);10}, 5).result(function(result) {11});12chromy.evaluate(function(a) {13 return addTwo(a);14}, 5).result(function(result) {15});16chromy.evaluate(function(a) {17 return addTwo(a);18}, 5).result(function(result) {19});20chromy.evaluate(function(a) {21 return addTwo(a);22}, 5).result(function(result) {23});24chromy.evaluate(function(a) {25 return addTwo(a);26}, 5).result(function(result) {27});28chromy.evaluate(function(a) {29 return addTwo(a);30}, 5).result(function(result) {

Full Screen

Using AI Code Generation

copy

Full Screen

1chromy.defineFunction('getRandom', function() {2 return Math.random();3});4chromy.evaluate(function() {5 return getRandom();6}).result(function(value) {7 console.log(value);8});9chromy.defineFunction('add', function(a, b) {10 return a + b;11});12chromy.evaluate(function() {13 return add(2, 3);14}).result(function(value) {15 console.log(value);16});17chromy.defineFunction('getRandom', function() {18 return Math.random();19});20chromy.evaluate(function() {21 return getRandom();22}).result(function(value) {23 console.log(value);24});25chromy.defineFunction('getRandom', function(callback) {26 callback(Math.random());27});28chromy.evaluate(function() {29 getRandom(function(value) {30 console.log(value);31 });32});

Full Screen

Using AI Code Generation

copy

Full Screen

1module.exports = function(chromy, scenario, vp) {2 chromy.evaluate(function() {3 });4};5module.exports = function(chromy, scenario, vp) {6 chromy.evaluate(function() {7 });8};9module.exports = function(chromy, scenario, vp) {10 chromy.evaluate(function() {11 });12};13module.exports = function(chromy, scenario, vp) {14 chromy.evaluate(function() {15 });16};17module.exports = function(chromy, scenario, vp) {18 chromy.evaluate(function() {19 });20};

Full Screen

Using AI Code Generation

copy

Full Screen

1const chromy = require('chromy')2const path = require('path')3const fs = require('fs')4const util = require('util')5const writeFile = util.promisify(fs.writeFile)6async function run () {7 try {8 await chromyInstance.chain()9 .evaluate(() => {10 window.defineFunction('getTitle', () => {11 })12 })13 .evaluate(() => {14 return window.getTitle()15 })16 .end()17 .result((title) => {18 console.log('Title of the page is ' + title)19 })20 } catch (err) {21 console.error(err)22 }23}24run()25const chromy = require('chromy')26const path = require('path')27const fs = require('fs')28const util = require('util')29const writeFile = util.promisify(fs.writeFile)30async function run () {31 try {32 await chromyInstance.chain()33 .evaluate(() => {34 window.defineFunction('getTitle', () => {35 })36 })37 .evaluate(() => {38 return window.getTitle()39 })40 .end()41 .result((title) => {42 console.log('Title of the page is ' + title)43 })44 } catch (err) {45 console.error(err)46 }47}48run()49const chromy = require('chromy')50const path = require('path')51const fs = require('fs')52const util = require('util')53const writeFile = util.promisify(fs.writeFile)54async function run () {55 try {

Full Screen

Using AI Code Generation

copy

Full Screen

1chromy.evaluate(function() {2 function getLinks() {3 var links = document.querySelectorAll('a');4 return Array.prototype.map.call(links, function(e) {5 return e.getAttribute('href');6 });7 }8 __utils__.defineFunction('getLinks', getLinks);9});10chromy.evaluate(function() {11 return __utils__.getLinks();12}).result(function(links) {13 console.log(links);14});15chromy.evaluate(function() {16 return __utils__.getLinks();17}).then(function(links) {18 console.log(links);19});20chromy.evaluate(function() {21 return __utils__.getLinks();22}).then(function(links) {23 console.log(links);24});25chromy.evaluate(function() {26 return __utils__.getLinks();27}).then(function(links) {28 console.log(links);29});30chromy.evaluate(function() {31 return __utils__.getLinks();32}).then(function(links) {33 console.log(links);34});35chromy.evaluate(function() {36 return __utils__.getLinks();37}).then(function(links) {38 console.log(links);39});40chromy.evaluate(function() {41 return __utils__.getLinks();42}).then(function(links) {43 console.log(links);44});45chromy.evaluate(function() {46 return __utils__.getLinks();47}).then(function(links) {48 console.log(links);49});50chromy.evaluate(function() {51 return __utils__.getLinks();52}).then(function(links) {53 console.log(links);54});55chromy.evaluate(function() {

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run chromy automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful