@khanacademy/kmath 0.4.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.js +72 -56
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +95 -79
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -7,26 +7,30 @@ var _ = require('underscore');
|
|
|
7
7
|
var perseusCore = require('@khanacademy/perseus-core');
|
|
8
8
|
var $ = require('jquery');
|
|
9
9
|
|
|
10
|
-
function
|
|
10
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
11
11
|
|
|
12
|
-
var ___default = /*#__PURE__*/
|
|
13
|
-
var $__default = /*#__PURE__*/
|
|
12
|
+
var ___default = /*#__PURE__*/_interopDefaultCompat(_);
|
|
13
|
+
var $__default = /*#__PURE__*/_interopDefaultCompat($);
|
|
14
14
|
|
|
15
15
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
16
|
+
// version number during the release build.
|
|
17
|
+
// In dev, you'll never see the version number.
|
|
18
|
+
|
|
16
19
|
const libName = "@khanacademy/kmath";
|
|
17
|
-
const libVersion = "0.
|
|
20
|
+
const libVersion = "2.0.0";
|
|
18
21
|
perseusUtils.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* Number Utils
|
|
22
25
|
* A number is a js-number, e.g. 5.12
|
|
23
26
|
*/
|
|
27
|
+
|
|
24
28
|
const DEFAULT_TOLERANCE = 1e-9;
|
|
25
29
|
|
|
26
30
|
// TODO: Should this just be Number.Epsilon
|
|
27
31
|
const EPSILON = Math.pow(2, -42);
|
|
28
32
|
function is$2(x) {
|
|
29
|
-
return ___default
|
|
33
|
+
return ___default.default.isNumber(x) && !___default.default.isNaN(x);
|
|
30
34
|
}
|
|
31
35
|
function equal$4(x, y, tolerance) {
|
|
32
36
|
// Checking for undefined makes this function behave nicely
|
|
@@ -110,14 +114,14 @@ var number = /*#__PURE__*/Object.freeze({
|
|
|
110
114
|
__proto__: null,
|
|
111
115
|
DEFAULT_TOLERANCE: DEFAULT_TOLERANCE,
|
|
112
116
|
EPSILON: EPSILON,
|
|
113
|
-
|
|
117
|
+
ceilTo: ceilTo$2,
|
|
114
118
|
equal: equal$4,
|
|
115
|
-
|
|
119
|
+
floorTo: floorTo$2,
|
|
120
|
+
is: is$2,
|
|
116
121
|
isInteger: isInteger,
|
|
117
122
|
round: round$2,
|
|
118
123
|
roundTo: roundTo$2,
|
|
119
|
-
|
|
120
|
-
ceilTo: ceilTo$2,
|
|
124
|
+
sign: sign$1,
|
|
121
125
|
toFraction: toFraction
|
|
122
126
|
});
|
|
123
127
|
|
|
@@ -125,6 +129,7 @@ var number = /*#__PURE__*/Object.freeze({
|
|
|
125
129
|
* Vector Utils
|
|
126
130
|
* A vector is an array of numbers e.g. [0, 3, 4].
|
|
127
131
|
*/
|
|
132
|
+
|
|
128
133
|
function arraySum(array) {
|
|
129
134
|
return array.reduce((memo, arg) => memo + arg, 0);
|
|
130
135
|
}
|
|
@@ -315,32 +320,32 @@ function ceilTo$1(vec, increment) {
|
|
|
315
320
|
|
|
316
321
|
var vector$1 = /*#__PURE__*/Object.freeze({
|
|
317
322
|
__proto__: null,
|
|
318
|
-
zip: zip,
|
|
319
|
-
map: map,
|
|
320
|
-
is: is$1,
|
|
321
|
-
normalize: normalize,
|
|
322
|
-
length: length,
|
|
323
|
-
dot: dot,
|
|
324
323
|
add: add$1,
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
324
|
+
angleDeg: angleDeg,
|
|
325
|
+
angleRad: angleRad,
|
|
326
|
+
cartFromPolarDeg: cartFromPolarDeg$1,
|
|
327
|
+
cartFromPolarRad: cartFromPolarRad$1,
|
|
328
|
+
ceilTo: ceilTo$1,
|
|
329
329
|
codirectional: codirectional,
|
|
330
330
|
collinear: collinear$1,
|
|
331
|
-
|
|
331
|
+
dot: dot,
|
|
332
|
+
equal: equal$3,
|
|
333
|
+
floorTo: floorTo$1,
|
|
334
|
+
is: is$1,
|
|
335
|
+
length: length,
|
|
336
|
+
map: map,
|
|
337
|
+
negate: negate,
|
|
338
|
+
normalize: normalize,
|
|
332
339
|
polarDegFromCart: polarDegFromCart$1,
|
|
333
|
-
|
|
334
|
-
cartFromPolarDeg: cartFromPolarDeg$1,
|
|
335
|
-
rotateRad: rotateRad$1,
|
|
336
|
-
rotateDeg: rotateDeg$1,
|
|
337
|
-
angleRad: angleRad,
|
|
338
|
-
angleDeg: angleDeg,
|
|
340
|
+
polarRadFromCart: polarRadFromCart$1,
|
|
339
341
|
projection: projection,
|
|
342
|
+
rotateDeg: rotateDeg$1,
|
|
343
|
+
rotateRad: rotateRad$1,
|
|
340
344
|
round: round$1,
|
|
341
345
|
roundTo: roundTo$1,
|
|
342
|
-
|
|
343
|
-
|
|
346
|
+
scale: scale,
|
|
347
|
+
subtract: subtract,
|
|
348
|
+
zip: zip
|
|
344
349
|
});
|
|
345
350
|
|
|
346
351
|
/**
|
|
@@ -348,6 +353,7 @@ var vector$1 = /*#__PURE__*/Object.freeze({
|
|
|
348
353
|
* A point is an array of two numbers e.g. [0, 0].
|
|
349
354
|
*/
|
|
350
355
|
|
|
356
|
+
|
|
351
357
|
// A point, in 2D, 3D, or nD space.
|
|
352
358
|
|
|
353
359
|
// Rotate point (around origin unless a center is specified)
|
|
@@ -433,31 +439,32 @@ const ceilTo = ceilTo$1;
|
|
|
433
439
|
|
|
434
440
|
var point = /*#__PURE__*/Object.freeze({
|
|
435
441
|
__proto__: null,
|
|
436
|
-
rotateRad: rotateRad,
|
|
437
|
-
rotateDeg: rotateDeg,
|
|
438
|
-
distanceToPoint: distanceToPoint$1,
|
|
439
|
-
distanceToLine: distanceToLine,
|
|
440
|
-
reflectOverLine: reflectOverLine,
|
|
441
|
-
compare: compare,
|
|
442
|
-
is: is,
|
|
443
442
|
addVector: addVector,
|
|
444
443
|
addVectors: addVectors,
|
|
445
|
-
|
|
444
|
+
cartFromPolarDeg: cartFromPolarDeg,
|
|
445
|
+
cartFromPolarRad: cartFromPolarRad,
|
|
446
|
+
ceilTo: ceilTo,
|
|
447
|
+
compare: compare,
|
|
448
|
+
distanceToLine: distanceToLine,
|
|
449
|
+
distanceToPoint: distanceToPoint$1,
|
|
446
450
|
equal: equal$2,
|
|
447
|
-
|
|
451
|
+
floorTo: floorTo,
|
|
452
|
+
is: is,
|
|
448
453
|
polarDegFromCart: polarDegFromCart,
|
|
449
|
-
|
|
450
|
-
|
|
454
|
+
polarRadFromCart: polarRadFromCart,
|
|
455
|
+
reflectOverLine: reflectOverLine,
|
|
456
|
+
rotateDeg: rotateDeg,
|
|
457
|
+
rotateRad: rotateRad,
|
|
451
458
|
round: round,
|
|
452
459
|
roundTo: roundTo,
|
|
453
|
-
|
|
454
|
-
ceilTo: ceilTo
|
|
460
|
+
subtractVector: subtractVector
|
|
455
461
|
});
|
|
456
462
|
|
|
457
463
|
/**
|
|
458
464
|
* Line Utils
|
|
459
465
|
* A line is an array of two points e.g. [[-5, 0], [5, 0]].
|
|
460
466
|
*/
|
|
467
|
+
|
|
461
468
|
function distanceToPoint(line, point$1) {
|
|
462
469
|
return distanceToLine(point$1, line);
|
|
463
470
|
}
|
|
@@ -489,9 +496,9 @@ function equal$1(line1, line2, tolerance) {
|
|
|
489
496
|
var line = /*#__PURE__*/Object.freeze({
|
|
490
497
|
__proto__: null,
|
|
491
498
|
distanceToPoint: distanceToPoint,
|
|
492
|
-
|
|
499
|
+
equal: equal$1,
|
|
493
500
|
midpoint: midpoint,
|
|
494
|
-
|
|
501
|
+
reflectPoint: reflectPoint
|
|
495
502
|
});
|
|
496
503
|
|
|
497
504
|
/**
|
|
@@ -500,6 +507,7 @@ var line = /*#__PURE__*/Object.freeze({
|
|
|
500
507
|
* For example, [[0, 0], [1, 0]] is the ray starting at the origin and
|
|
501
508
|
* traveling along the positive x-axis.
|
|
502
509
|
*/
|
|
510
|
+
|
|
503
511
|
function equal(ray1, ray2, tolerance) {
|
|
504
512
|
// Compare the directions of the rays
|
|
505
513
|
const v1 = subtract(ray1[1], ray1[0]);
|
|
@@ -546,6 +554,8 @@ const KhanMath = {
|
|
|
546
554
|
let mod;
|
|
547
555
|
a = Math.abs(a);
|
|
548
556
|
b = Math.abs(b);
|
|
557
|
+
|
|
558
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
549
559
|
while (b) {
|
|
550
560
|
mod = a % b;
|
|
551
561
|
a = b;
|
|
@@ -569,7 +579,8 @@ const KhanMath = {
|
|
|
569
579
|
return false;
|
|
570
580
|
}
|
|
571
581
|
if (n < 101) {
|
|
572
|
-
|
|
582
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
583
|
+
return !!$__default.default.grep(KhanMath.primes, function (p, i) {
|
|
573
584
|
return Math.abs(p - n) <= 0.5;
|
|
574
585
|
}).length;
|
|
575
586
|
}
|
|
@@ -594,7 +605,7 @@ const KhanMath = {
|
|
|
594
605
|
const maxf = Math.sqrt(number);
|
|
595
606
|
for (let f = 2; f <= maxf; f++) {
|
|
596
607
|
if (number % f === 0) {
|
|
597
|
-
return $__default
|
|
608
|
+
return $__default.default.merge(KhanMath.getPrimeFactorization(f), KhanMath.getPrimeFactorization(number / f));
|
|
598
609
|
}
|
|
599
610
|
}
|
|
600
611
|
},
|
|
@@ -680,7 +691,7 @@ const KhanMath = {
|
|
|
680
691
|
// Note: purposively more inclusive than answer-types' predicate.forms
|
|
681
692
|
// That is, it is not necessarily true that interpreted input are numeric
|
|
682
693
|
getNumericFormat: function (text) {
|
|
683
|
-
text = $__default
|
|
694
|
+
text = $__default.default.trim(text);
|
|
684
695
|
text = text.replace(/\u2212/, "-").replace(/([+-])\s+/g, "$1");
|
|
685
696
|
if (text.match(/^[+-]?\d+$/)) {
|
|
686
697
|
return "integer";
|
|
@@ -721,7 +732,7 @@ const KhanMath = {
|
|
|
721
732
|
return sign + (numerator === 1 ? "" : numerator) + pi + (denominator === 1 ? "" : "/" + denominator);
|
|
722
733
|
}
|
|
723
734
|
}
|
|
724
|
-
if (___default
|
|
735
|
+
if (___default.default(["proper", "improper", "mixed", "fraction"]).contains(format)) {
|
|
725
736
|
const fraction = toFraction(number$1);
|
|
726
737
|
const numerator = Math.abs(fraction[0]);
|
|
727
738
|
const denominator = fraction[1];
|
|
@@ -732,7 +743,9 @@ const KhanMath = {
|
|
|
732
743
|
if (format === "mixed") {
|
|
733
744
|
const modulus = numerator % denominator;
|
|
734
745
|
const integer = (numerator - modulus) / denominator;
|
|
735
|
-
return sign + (
|
|
746
|
+
return sign + (
|
|
747
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
748
|
+
integer ? integer + " " : "") + modulus + "/" + denominator;
|
|
736
749
|
} // otherwise proper, improper, or fraction
|
|
737
750
|
return sign + numerator + "/" + denominator;
|
|
738
751
|
}
|
|
@@ -752,6 +765,7 @@ function add(a, b) {
|
|
|
752
765
|
* A collection of geomtry-related utility functions
|
|
753
766
|
*/
|
|
754
767
|
|
|
768
|
+
|
|
755
769
|
// This should really be a readonly tuple of [number, number]
|
|
756
770
|
|
|
757
771
|
// Given a number, return whether it is positive (1), negative (-1), or zero (0)
|
|
@@ -780,7 +794,7 @@ function pointInRect(a, b, c) {
|
|
|
780
794
|
// http://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
|
|
781
795
|
function intersects(ab, cd) {
|
|
782
796
|
const triplets = [[ab[0], ab[1], cd[0]], [ab[0], ab[1], cd[1]], [cd[0], cd[1], ab[0]], [cd[0], cd[1], ab[1]]];
|
|
783
|
-
const orientations = ___default
|
|
797
|
+
const orientations = ___default.default.map(triplets, function (triplet) {
|
|
784
798
|
return sign(ccw(...triplet));
|
|
785
799
|
});
|
|
786
800
|
if (orientations[0] !== orientations[1] && orientations[2] !== orientations[3]) {
|
|
@@ -821,7 +835,7 @@ function polygonSidesIntersect(vertices) {
|
|
|
821
835
|
return false;
|
|
822
836
|
}
|
|
823
837
|
function vector(a, b) {
|
|
824
|
-
return ___default
|
|
838
|
+
return ___default.default.map(___default.default.zip(a, b), function (pair) {
|
|
825
839
|
return pair[0] - pair[1];
|
|
826
840
|
});
|
|
827
841
|
}
|
|
@@ -833,8 +847,8 @@ function reverseVector(vector) {
|
|
|
833
847
|
// path (assuming a closed loop, where the last point connects back to the
|
|
834
848
|
// first).
|
|
835
849
|
function clockwise(points) {
|
|
836
|
-
const segments = ___default
|
|
837
|
-
const areas = ___default
|
|
850
|
+
const segments = ___default.default.zip(points, points.slice(1).concat(points.slice(0, 1)));
|
|
851
|
+
const areas = ___default.default.map(segments, function (segment) {
|
|
838
852
|
const p1 = segment[0];
|
|
839
853
|
const p2 = segment[1];
|
|
840
854
|
return (p2[0] - p1[0]) * (p2[1] + p1[1]);
|
|
@@ -842,18 +856,18 @@ function clockwise(points) {
|
|
|
842
856
|
return sum(areas) > 0;
|
|
843
857
|
}
|
|
844
858
|
function magnitude(v) {
|
|
845
|
-
return Math.sqrt(___default
|
|
859
|
+
return Math.sqrt(___default.default.reduce(v, function (memo, el) {
|
|
846
860
|
// @ts-expect-error - TS2345 - Argument of type 'Coord' is not assignable to parameter of type 'number'.
|
|
847
861
|
return memo + Math.pow(el, 2);
|
|
848
862
|
}, 0));
|
|
849
863
|
}
|
|
850
864
|
function dotProduct(a, b) {
|
|
851
|
-
return ___default
|
|
865
|
+
return ___default.default.reduce(___default.default.zip(a, b), function (memo, pair) {
|
|
852
866
|
return memo + pair[0] * pair[1];
|
|
853
867
|
}, 0);
|
|
854
868
|
}
|
|
855
869
|
function sideLengths(coords) {
|
|
856
|
-
const segments = ___default
|
|
870
|
+
const segments = ___default.default.zip(coords, rotate(coords));
|
|
857
871
|
return segments.map(function (segment) {
|
|
858
872
|
// @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'. | TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
859
873
|
return magnitude(vector(...segment));
|
|
@@ -862,8 +876,8 @@ function sideLengths(coords) {
|
|
|
862
876
|
|
|
863
877
|
// Based on http://math.stackexchange.com/a/151149
|
|
864
878
|
function angleMeasures(coords) {
|
|
865
|
-
const triplets = ___default
|
|
866
|
-
const offsets = ___default
|
|
879
|
+
const triplets = ___default.default.zip(rotate(coords, -1), coords, rotate(coords, 1));
|
|
880
|
+
const offsets = ___default.default.map(triplets, function (triplet) {
|
|
867
881
|
const p = vector(triplet[1], triplet[0]);
|
|
868
882
|
const q = vector(triplet[2], triplet[1]);
|
|
869
883
|
// @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'Coord'. | TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'. | TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'.
|
|
@@ -871,10 +885,10 @@ function angleMeasures(coords) {
|
|
|
871
885
|
// @ts-expect-error - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
872
886
|
return sign(ccw(...triplet)) > 0 ? raw : -raw;
|
|
873
887
|
});
|
|
874
|
-
const sum = ___default
|
|
888
|
+
const sum = ___default.default.reduce(offsets, function (memo, arg) {
|
|
875
889
|
return memo + arg;
|
|
876
890
|
}, 0);
|
|
877
|
-
return ___default
|
|
891
|
+
return ___default.default.map(offsets, function (offset) {
|
|
878
892
|
return sum > 0 ? Math.PI - offset : Math.PI + offset;
|
|
879
893
|
});
|
|
880
894
|
}
|
|
@@ -908,14 +922,14 @@ function similar(coords1, coords2, tolerance) {
|
|
|
908
922
|
// @ts-expect-error - TS4104 - The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
|
|
909
923
|
sides = rotate(sides, i);
|
|
910
924
|
if (perseusCore.approximateDeepEqual(angles1, angles)) {
|
|
911
|
-
const sidePairs = ___default
|
|
912
|
-
const factors = ___default
|
|
925
|
+
const sidePairs = ___default.default.zip(sides1, sides);
|
|
926
|
+
const factors = ___default.default.map(sidePairs, function (pair) {
|
|
913
927
|
return pair[0] / pair[1];
|
|
914
928
|
});
|
|
915
|
-
const same = ___default
|
|
929
|
+
const same = ___default.default.all(factors, function (factor) {
|
|
916
930
|
return perseusCore.approximateEqual(factors[0], factor);
|
|
917
931
|
});
|
|
918
|
-
const congruentEnough = ___default
|
|
932
|
+
const congruentEnough = ___default.default.all(sidePairs, function (pair) {
|
|
919
933
|
return equal$4(pair[0], pair[1], tolerance);
|
|
920
934
|
});
|
|
921
935
|
if (same && congruentEnough) {
|
|
@@ -1007,26 +1021,27 @@ function getLineIntersectionString(firstPoints, secondPoints) {
|
|
|
1007
1021
|
|
|
1008
1022
|
var geometry = /*#__PURE__*/Object.freeze({
|
|
1009
1023
|
__proto__: null,
|
|
1010
|
-
|
|
1024
|
+
angleMeasures: angleMeasures,
|
|
1025
|
+
canonicalSineCoefficients: canonicalSineCoefficients,
|
|
1011
1026
|
ccw: ccw,
|
|
1027
|
+
clockwise: clockwise,
|
|
1012
1028
|
collinear: collinear,
|
|
1029
|
+
getLineEquation: getLineEquation,
|
|
1030
|
+
getLineIntersection: getLineIntersection,
|
|
1031
|
+
getLineIntersectionString: getLineIntersectionString,
|
|
1013
1032
|
intersects: intersects,
|
|
1033
|
+
lawOfCosines: lawOfCosines,
|
|
1034
|
+
magnitude: magnitude,
|
|
1014
1035
|
polygonSidesIntersect: polygonSidesIntersect,
|
|
1015
|
-
vector: vector,
|
|
1016
1036
|
reverseVector: reverseVector,
|
|
1017
|
-
clockwise: clockwise,
|
|
1018
|
-
magnitude: magnitude,
|
|
1019
|
-
angleMeasures: angleMeasures,
|
|
1020
|
-
similar: similar,
|
|
1021
|
-
lawOfCosines: lawOfCosines,
|
|
1022
|
-
canonicalSineCoefficients: canonicalSineCoefficients,
|
|
1023
1037
|
rotate: rotate,
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1038
|
+
sign: sign,
|
|
1039
|
+
similar: similar,
|
|
1040
|
+
vector: vector
|
|
1027
1041
|
});
|
|
1028
1042
|
|
|
1029
1043
|
// This file contains helper functions for working with angles.
|
|
1044
|
+
|
|
1030
1045
|
function convertDegreesToRadians(degrees) {
|
|
1031
1046
|
return degrees / 180 * Math.PI;
|
|
1032
1047
|
}
|
|
@@ -1057,6 +1072,7 @@ function polar(r, th) {
|
|
|
1057
1072
|
const getAngleFromVertex = (point, vertex) => {
|
|
1058
1073
|
const x = point[0] - vertex[0];
|
|
1059
1074
|
const y = point[1] - vertex[1];
|
|
1075
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
1060
1076
|
if (!x && !y) {
|
|
1061
1077
|
return 0;
|
|
1062
1078
|
}
|
|
@@ -1089,12 +1105,12 @@ const getClockwiseAngle = function (coords) {
|
|
|
1089
1105
|
|
|
1090
1106
|
var angles = /*#__PURE__*/Object.freeze({
|
|
1091
1107
|
__proto__: null,
|
|
1108
|
+
calculateAngleInDegrees: calculateAngleInDegrees,
|
|
1092
1109
|
convertDegreesToRadians: convertDegreesToRadians,
|
|
1093
1110
|
convertRadiansToDegrees: convertRadiansToDegrees,
|
|
1094
|
-
calculateAngleInDegrees: calculateAngleInDegrees,
|
|
1095
|
-
polar: polar,
|
|
1096
1111
|
getAngleFromVertex: getAngleFromVertex,
|
|
1097
|
-
getClockwiseAngle: getClockwiseAngle
|
|
1112
|
+
getClockwiseAngle: getClockwiseAngle,
|
|
1113
|
+
polar: polar
|
|
1098
1114
|
});
|
|
1099
1115
|
|
|
1100
1116
|
// TODO: there's another, very similar getSinusoidCoefficients function
|
|
@@ -1131,8 +1147,8 @@ function getQuadraticCoefficients(coords) {
|
|
|
1131
1147
|
|
|
1132
1148
|
var coefficients = /*#__PURE__*/Object.freeze({
|
|
1133
1149
|
__proto__: null,
|
|
1134
|
-
|
|
1135
|
-
|
|
1150
|
+
getQuadraticCoefficients: getQuadraticCoefficients,
|
|
1151
|
+
getSinusoidCoefficients: getSinusoidCoefficients
|
|
1136
1152
|
});
|
|
1137
1153
|
|
|
1138
1154
|
exports.KhanMath = KhanMath;
|