@khanacademy/perseus-core 3.1.0 → 3.2.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 CHANGED
@@ -40,395 +40,103 @@ const addLibraryVersionToPerseusDebug = (libraryName, libraryVersion) => {
40
40
  }
41
41
  };
42
42
 
43
- // This file is processed by a Rollup plugin (replace) to inject the production
44
- const libName = "@khanacademy/perseus-core";
45
- const libVersion = "3.1.0";
46
- addLibraryVersionToPerseusDebug(libName, libVersion);
43
+ // Current version.
44
+ var VERSION = '1.13.3';
47
45
 
48
- /**
49
- * @typedef {Object} Errors utility for referencing the Perseus error taxonomy.
50
- */
51
- const Errors = Object.freeze({
52
- /**
53
- * @property {ErrorKind} Unknown The kind of error is not known.
54
- */
55
- Unknown: "Unknown",
56
- /**
57
- * @property {ErrorKind} Internal The error is internal to the executing code.
58
- */
59
- Internal: "Internal",
60
- /**
61
- * @property {ErrorKind} InvalidInput There was a problem with the provided
62
- * input, such as the wrong format or a null value.
63
- */
64
- InvalidInput: "InvalidInput",
65
- /**
66
- * @property {ErrorKind} NotAllowed There was a problem due to the state of
67
- * the system not matching the requested operation or input. For example,
68
- * trying to create a username that is valid, but is already taken by
69
- * another user. Use {@link InvalidInput} instead when the input isn't
70
- * valid regardless of the state of the system. Use {@link NotFound} when
71
- * the failure is due to not being able to find a resource.
72
- */
73
- NotAllowed: "NotAllowed",
74
- /**
75
- * @property {ErrorKind} TransientService There was a problem when making a
76
- * request to a service.
77
- */
78
- TransientService: "TransientService",
79
- /**
80
- * @property {ErrorKind} Service There was a non-transient problem when
81
- * making a request to service.
82
- */
83
- Service: "Service"
84
- });
46
+ // Establish the root object, `window` (`self`) in the browser, `global`
47
+ // on the server, or `this` in some virtual machines. We use `self`
48
+ // instead of `window` for `WebWorker` support.
49
+ var root = (typeof self == 'object' && self.self === self && self) ||
50
+ (typeof global == 'object' && global.global === global && global) ||
51
+ Function('return this')() ||
52
+ {};
85
53
 
86
- /**
87
- * @type {ErrorKind} The kind of error being reported
88
- */
54
+ // Save bytes in the minified (but not gzipped) version:
55
+ var ArrayProto = Array.prototype, ObjProto = Object.prototype;
56
+ var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
89
57
 
90
- class PerseusError extends Error {
91
- constructor(message, kind, options) {
92
- super(message);
93
- this.kind = void 0;
94
- this.metadata = void 0;
95
- this.kind = kind;
96
- this.metadata = options == null ? void 0 : options.metadata;
97
- }
98
- }
58
+ // Create quick reference variables for speed access to core prototypes.
59
+ var push = ArrayProto.push,
60
+ slice = ArrayProto.slice,
61
+ toString = ObjProto.toString,
62
+ hasOwnProperty = ObjProto.hasOwnProperty;
99
63
 
100
- /**
101
- * The Perseus "data schema" file.
102
- *
103
- * This file, and the types in it, represents the "data schema" that Perseus
104
- * uses. The @khanacademy/perseus-editor package edits and produces objects
105
- * that conform to the types in this file. Similarly, the top-level renderers
106
- * in @khanacademy/perseus, consume objects that conform to these types.
107
- *
108
- * WARNING: This file should not import any types from elsewhere so that it is
109
- * easy to reason about changes that alter the Perseus schema. This helps
110
- * ensure that it is not changed accidentally when upgrading a dependant
111
- * package or other part of Perseus code. Note that TypeScript does type
112
- * checking via something called "structural typing". This means that as long
113
- * as the shape of a type matches, the name it goes by doesn't matter. As a
114
- * result, a `Coord` type that looks like this `[x: number, y: number]` is
115
- * _identical_, in TypeScript's eyes, to this `Vector2` type `[x: number, y:
116
- * number]`. Also, with tuples, the labels for each entry is ignored, so `[x:
117
- * number, y: number]` is compatible with `[min: number, max: number]`. The
118
- * labels are for humans, not TypeScript. :)
119
- *
120
- * If you make changes to types in this file, be very sure that:
121
- *
122
- * a) the changes are backwards compatible. If they are not, old data from
123
- * previous versions of the "schema" could become unrenderable, or worse,
124
- * introduce hard-to-diagnose bugs.
125
- * b) the parsing code (`util/parse-perseus-json/`) is updated to handle
126
- * the new format _as well as_ the old format.
127
- */
64
+ // Modern feature detection.
65
+ var supportsArrayBuffer = typeof ArrayBuffer !== 'undefined',
66
+ supportsDataView = typeof DataView !== 'undefined';
128
67
 
129
- // TODO(FEI-4010): Remove `Perseus` prefix for all types here
68
+ // All **ECMAScript 5+** native function implementations that we hope to use
69
+ // are declared here.
70
+ var nativeIsArray = Array.isArray,
71
+ nativeKeys = Object.keys,
72
+ nativeCreate = Object.create,
73
+ nativeIsView = supportsArrayBuffer && ArrayBuffer.isView;
130
74
 
131
- // Same name as Mafs
75
+ // Create references to these builtin functions because we override them.
76
+ var _isNaN = isNaN,
77
+ _isFinite = isFinite;
132
78
 
133
- /**
134
- * Our core set of Perseus widgets.
135
- *
136
- * This interface is the basis for "registering" all Perseus widget types.
137
- * There should be one key/value pair for each supported widget. If you create
138
- * a new widget, an entry should be added to this interface. Note that this
139
- * only registers the widget options type, you'll also need to register the
140
- * widget so that it's available at runtime (@see
141
- * {@link file://./widgets.ts#registerWidget}).
142
- *
143
- * Importantly, the key should be the name that is used in widget IDs. For most
144
- * widgets that is the same as the widget option's `type` field. In cases where
145
- * a widget has been deprecated and replaced with the deprecated-standin
146
- * widget, it should be the original widget type!
147
- *
148
- * If you define the widget outside of this package, you can still add the new
149
- * widget to this interface by writing the following in that package that
150
- * contains the widget. TypeScript will merge that definition of the
151
- * `PerseusWidgets` with the one defined below.
152
- *
153
- * ```typescript
154
- * declare module "@khanacademy/perseus" {
155
- * interface PerseusWidgetTypes {
156
- * // A new widget
157
- * "new-awesomeness": MyAwesomeNewWidget;
158
- *
159
- * // A deprecated widget
160
- * "super-old-widget": DeprecatedStandinWidget;
161
- * }
162
- * }
163
- *
164
- * // The new widget's options definition
165
- * type MyAwesomeNewWidget = WidgetOptions<'new-awesomeness', MyAwesomeNewWidgetOptions>;
166
- *
167
- * // The deprecated widget's options definition
168
- * type SuperOldWidget = WidgetOptions<'super-old-widget', object>;
169
- * ```
170
- *
171
- * This interface can be extended through the magic of TypeScript "Declaration
172
- * merging". Specifically, we augment this module and extend this interface.
173
- *
174
- * @see {@link https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation}
175
- */
79
+ // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
80
+ var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
81
+ var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
82
+ 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
176
83
 
177
- /**
178
- * A map of widget IDs to widget options. This is most often used as the type
179
- * for a set of widgets defined in a `PerseusItem` but can also be useful to
180
- * represent a function parameter where only `widgets` from a `PerseusItem` are
181
- * needed. Today Widget IDs are made up of the widget type and an incrementing
182
- * integer (eg. `interactive-graph 1` or `radio 3`). It is suggested to avoid
183
- * reading/parsing the widget id to derive any information from it, except in
184
- * the case of this map.
185
- *
186
- * @see {@link PerseusWidgetTypes} additional widgets can be added to this map type
187
- * by augmenting the PerseusWidgetTypes with new widget types!
188
- */
84
+ // The largest integer that can be represented exactly.
85
+ var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
189
86
 
190
- /**
191
- * A "PerseusItem" is a classic Perseus item. It is rendered by the
192
- * `ServerItemRenderer` and the layout is pre-set.
193
- *
194
- * To render more complex Perseus items, see the `Item` type in the multi item
195
- * area.
196
- */
87
+ // Some functions take a variable number of arguments, or a few expected
88
+ // arguments at the beginning and then a variable number of values to operate
89
+ // on. This helper accumulates all remaining arguments past the function’s
90
+ // argument length (or an explicit `startIndex`), into an array that becomes
91
+ // the last argument. Similar to ES6’s "rest parameter".
92
+ function restArguments(func, startIndex) {
93
+ startIndex = startIndex == null ? func.length - 1 : +startIndex;
94
+ return function() {
95
+ var length = Math.max(arguments.length - startIndex, 0),
96
+ rest = Array(length),
97
+ index = 0;
98
+ for (; index < length; index++) {
99
+ rest[index] = arguments[index + startIndex];
100
+ }
101
+ switch (startIndex) {
102
+ case 0: return func.call(this, rest);
103
+ case 1: return func.call(this, arguments[0], rest);
104
+ case 2: return func.call(this, arguments[0], arguments[1], rest);
105
+ }
106
+ var args = Array(startIndex + 1);
107
+ for (index = 0; index < startIndex; index++) {
108
+ args[index] = arguments[index];
109
+ }
110
+ args[startIndex] = rest;
111
+ return func.apply(this, args);
112
+ };
113
+ }
197
114
 
198
- /**
199
- * A "PerseusArticle" is an item that is meant to be rendered as an article.
200
- * This item is never scored and is rendered by the `ArticleRenderer`.
201
- */
115
+ // Is a given variable an object?
116
+ function isObject(obj) {
117
+ var type = typeof obj;
118
+ return type === 'function' || (type === 'object' && !!obj);
119
+ }
202
120
 
203
- const ItemExtras = [
204
- // The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
205
- "calculator",
206
- // The user might benefit from using a statistics Chi Squared Table like https://people.richland.edu/james/lecture/m170/tbl-chi.html
207
- "chi2Table",
208
- // The user might benefit from a monthly payments calculator. Provided on Khan Academy when true
209
- "financialCalculatorMonthlyPayment",
210
- // The user might benefit from a total amount calculator. Provided on Khan Academy when true
211
- "financialCalculatorTotalAmount",
212
- // The user might benefit from a time to pay off calculator. Provided on Khan Academy when true
213
- "financialCalculatorTimeToPayOff",
214
- // The user might benefit from using a Periodic Table of Elements. Provided on Khan Academy when true
215
- "periodicTable",
216
- // The user might benefit from using a Periodic Table of Elements with key. Provided on Khan Academy when true
217
- "periodicTableWithKey",
218
- // The user might benefit from using a statistics T Table like https://www.statisticshowto.com/tables/t-distribution-table/
219
- "tTable",
220
- // The user might benefit from using a statistics Z Table like https://www.ztable.net/
221
- "zTable"];
121
+ // Is a given value equal to null?
122
+ function isNull(obj) {
123
+ return obj === null;
124
+ }
222
125
 
223
- /**
224
- * The type representing the common structure of all widget's options. The
225
- * `Options` generic type represents the widget-specific option data.
226
- */
126
+ // Is a given variable undefined?
127
+ function isUndefined(obj) {
128
+ return obj === void 0;
129
+ }
227
130
 
228
- // prettier-ignore
131
+ // Is a given value a boolean?
132
+ function isBoolean(obj) {
133
+ return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
134
+ }
229
135
 
230
- // prettier-ignore
231
-
232
- // prettier-ignore
233
-
234
- // prettier-ignore
235
-
236
- // prettier-ignore
237
-
238
- // prettier-ignore
239
-
240
- // prettier-ignore
241
-
242
- // prettier-ignore
243
-
244
- // prettier-ignore
245
-
246
- // prettier-ignore
247
-
248
- // prettier-ignore
249
-
250
- // prettier-ignore
251
-
252
- // prettier-ignore
253
-
254
- // prettier-ignore
255
-
256
- // prettier-ignore
257
-
258
- // prettier-ignore
259
-
260
- // prettier-ignore
261
-
262
- // prettier-ignore
263
-
264
- // prettier-ignore
265
-
266
- // prettier-ignore
267
-
268
- // prettier-ignore
269
-
270
- // prettier-ignore
271
-
272
- // prettier-ignore
273
-
274
- // prettier-ignore
275
-
276
- // prettier-ignore
277
-
278
- // prettier-ignore
279
-
280
- // prettier-ignore
281
-
282
- // prettier-ignore
283
-
284
- // prettier-ignore
285
-
286
- // prettier-ignore
287
-
288
- // prettier-ignore
289
-
290
- // prettier-ignore
291
-
292
- // prettier-ignore
293
-
294
- // prettier-ignore
295
-
296
- //prettier-ignore
297
-
298
- /**
299
- * A background image applied to various widgets.
300
- */
301
-
302
- /**
303
- * The type of markings to display on the graph.
304
- * - axes: shows the axes without the gride lines
305
- * - graph: shows the axes and the grid lines
306
- * - grid: shows only the grid lines
307
- * - none: shows no markings
308
- */
309
-
310
- const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
311
-
312
- // 2D range: xMin, xMax, yMin, yMax
313
-
314
- const lockedFigureColorNames = ["blue", "green", "grayH", "purple", "pink", "orange", "red"];
315
- const lockedFigureColors = {
316
- blue: "#3D7586",
317
- green: "#447A53",
318
- grayH: "#3B3D45",
319
- purple: "#594094",
320
- pink: "#B25071",
321
- red: "#D92916",
322
- orange: "#946700"
323
- };
324
- const lockedFigureFillStyles = {
325
- none: 0,
326
- white: 1,
327
- translucent: 0.4,
328
- solid: 1
329
- };
330
-
331
- // Not associated with a specific figure
332
-
333
- const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
334
-
335
- // Current version.
336
- var VERSION = '1.13.3';
337
-
338
- // Establish the root object, `window` (`self`) in the browser, `global`
339
- // on the server, or `this` in some virtual machines. We use `self`
340
- // instead of `window` for `WebWorker` support.
341
- var root = (typeof self == 'object' && self.self === self && self) ||
342
- (typeof global == 'object' && global.global === global && global) ||
343
- Function('return this')() ||
344
- {};
345
-
346
- // Save bytes in the minified (but not gzipped) version:
347
- var ArrayProto = Array.prototype, ObjProto = Object.prototype;
348
- var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
349
-
350
- // Create quick reference variables for speed access to core prototypes.
351
- var push = ArrayProto.push,
352
- slice = ArrayProto.slice,
353
- toString = ObjProto.toString,
354
- hasOwnProperty = ObjProto.hasOwnProperty;
355
-
356
- // Modern feature detection.
357
- var supportsArrayBuffer = typeof ArrayBuffer !== 'undefined',
358
- supportsDataView = typeof DataView !== 'undefined';
359
-
360
- // All **ECMAScript 5+** native function implementations that we hope to use
361
- // are declared here.
362
- var nativeIsArray = Array.isArray,
363
- nativeKeys = Object.keys,
364
- nativeCreate = Object.create,
365
- nativeIsView = supportsArrayBuffer && ArrayBuffer.isView;
366
-
367
- // Create references to these builtin functions because we override them.
368
- var _isNaN = isNaN,
369
- _isFinite = isFinite;
370
-
371
- // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
372
- var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
373
- var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
374
- 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
375
-
376
- // The largest integer that can be represented exactly.
377
- var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
378
-
379
- // Some functions take a variable number of arguments, or a few expected
380
- // arguments at the beginning and then a variable number of values to operate
381
- // on. This helper accumulates all remaining arguments past the function’s
382
- // argument length (or an explicit `startIndex`), into an array that becomes
383
- // the last argument. Similar to ES6’s "rest parameter".
384
- function restArguments(func, startIndex) {
385
- startIndex = startIndex == null ? func.length - 1 : +startIndex;
386
- return function() {
387
- var length = Math.max(arguments.length - startIndex, 0),
388
- rest = Array(length),
389
- index = 0;
390
- for (; index < length; index++) {
391
- rest[index] = arguments[index + startIndex];
392
- }
393
- switch (startIndex) {
394
- case 0: return func.call(this, rest);
395
- case 1: return func.call(this, arguments[0], rest);
396
- case 2: return func.call(this, arguments[0], arguments[1], rest);
397
- }
398
- var args = Array(startIndex + 1);
399
- for (index = 0; index < startIndex; index++) {
400
- args[index] = arguments[index];
401
- }
402
- args[startIndex] = rest;
403
- return func.apply(this, args);
404
- };
405
- }
406
-
407
- // Is a given variable an object?
408
- function isObject(obj) {
409
- var type = typeof obj;
410
- return type === 'function' || (type === 'object' && !!obj);
411
- }
412
-
413
- // Is a given value equal to null?
414
- function isNull(obj) {
415
- return obj === null;
416
- }
417
-
418
- // Is a given variable undefined?
419
- function isUndefined(obj) {
420
- return obj === void 0;
421
- }
422
-
423
- // Is a given value a boolean?
424
- function isBoolean(obj) {
425
- return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
426
- }
427
-
428
- // Is a given value a DOM element?
429
- function isElement(obj) {
430
- return !!(obj && obj.nodeType === 1);
431
- }
136
+ // Is a given value a DOM element?
137
+ function isElement(obj) {
138
+ return !!(obj && obj.nodeType === 1);
139
+ }
432
140
 
433
141
  // Internal function for creating a `toString`-based type tester.
434
142
  function tagTester(name) {
@@ -2356,6 +2064,812 @@ var _ = mixin(allExports);
2356
2064
  // Legacy Node.js API.
2357
2065
  _._ = _;
2358
2066
 
2067
+ function getMatrixSize(matrix) {
2068
+ const matrixSize = [1, 1];
2069
+
2070
+ // We need to find the widest row and tallest column to get the correct
2071
+ // matrix size.
2072
+ _(matrix).each((matrixRow, row) => {
2073
+ let rowWidth = 0;
2074
+ _(matrixRow).each((matrixCol, col) => {
2075
+ if (matrixCol != null && matrixCol.toString().length) {
2076
+ rowWidth = col + 1;
2077
+ }
2078
+ });
2079
+
2080
+ // Matrix width:
2081
+ matrixSize[1] = Math.max(matrixSize[1], rowWidth);
2082
+
2083
+ // Matrix height:
2084
+ if (rowWidth > 0) {
2085
+ matrixSize[0] = Math.max(matrixSize[0], row + 1);
2086
+ }
2087
+ });
2088
+ return matrixSize;
2089
+ }
2090
+
2091
+ /**
2092
+ * Get the character used for separating decimals.
2093
+ */
2094
+ const getDecimalSeparator = locale => {
2095
+ var _match$;
2096
+ switch (locale) {
2097
+ // TODO(somewhatabstract): Remove this when Chrome supports the `ka`
2098
+ // locale properly.
2099
+ // https://github.com/formatjs/formatjs/issues/1526#issuecomment-559891201
2100
+ //
2101
+ // Supported locales in Chrome:
2102
+ // https://source.chromium.org/chromium/chromium/src/+/master:third_party/icu/scripts/chrome_ui_languages.list
2103
+ case "ka":
2104
+ return ",";
2105
+ default:
2106
+ const numberWithDecimalSeparator = 1.1;
2107
+ // TODO(FEI-3647): Update to use .formatToParts() once we no longer have to
2108
+ // support Safari 12.
2109
+ const match = new Intl.NumberFormat(locale).format(numberWithDecimalSeparator)
2110
+ // 0x661 is ARABIC-INDIC DIGIT ONE
2111
+ // 0x6F1 is EXTENDED ARABIC-INDIC DIGIT ONE
2112
+ .match(/[^\d\u0661\u06F1]/);
2113
+ return (_match$ = match == null ? void 0 : match[0]) != null ? _match$ : ".";
2114
+ }
2115
+ };
2116
+
2117
+ /**
2118
+ * APPROXIMATE equality on numbers and primitives.
2119
+ */
2120
+ function approximateEqual(x, y) {
2121
+ if (typeof x === "number" && typeof y === "number") {
2122
+ return Math.abs(x - y) < 1e-9;
2123
+ }
2124
+ return x === y;
2125
+ }
2126
+
2127
+ /**
2128
+ * Deep APPROXIMATE equality on primitives, numbers, arrays, and objects.
2129
+ * Recursive.
2130
+ */
2131
+ function approximateDeepEqual(x, y) {
2132
+ if (Array.isArray(x) && Array.isArray(y)) {
2133
+ if (x.length !== y.length) {
2134
+ return false;
2135
+ }
2136
+ for (let i = 0; i < x.length; i++) {
2137
+ if (!approximateDeepEqual(x[i], y[i])) {
2138
+ return false;
2139
+ }
2140
+ }
2141
+ return true;
2142
+ }
2143
+ if (Array.isArray(x) || Array.isArray(y)) {
2144
+ return false;
2145
+ }
2146
+ if (typeof x === "function" && typeof y === "function") {
2147
+ return approximateEqual(x, y);
2148
+ }
2149
+ if (typeof x === "function" || typeof y === "function") {
2150
+ return false;
2151
+ }
2152
+ if (typeof x === "object" && typeof y === "object" && !!x && !!y) {
2153
+ return x === y || _.all(x, function (v, k) {
2154
+ // @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
2155
+ return approximateDeepEqual(y[k], v);
2156
+ }) && _.all(y, function (v, k) {
2157
+ // @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
2158
+ return approximateDeepEqual(x[k], v);
2159
+ });
2160
+ }
2161
+ if (typeof x === "object" && !!x || typeof y === "object" && !!y) {
2162
+ return false;
2163
+ }
2164
+ return approximateEqual(x, y);
2165
+ }
2166
+
2167
+ // TODO(benchristel): in the future, we may want to make deepClone work for
2168
+ // Record<string, Cloneable> as well. Currently, it only does arrays.
2169
+
2170
+ function deepClone(obj) {
2171
+ if (Array.isArray(obj)) {
2172
+ return obj.map(deepClone);
2173
+ }
2174
+ return obj;
2175
+ }
2176
+
2177
+ const MOVABLES = {
2178
+ PLOT: "PLOT",
2179
+ PARABOLA: "PARABOLA",
2180
+ SINUSOID: "SINUSOID"
2181
+ };
2182
+
2183
+ // TODO(charlie): These really need to go into a utility file as they're being
2184
+ // used by both interactive-graph and now grapher.
2185
+ function canonicalSineCoefficients(coeffs) {
2186
+ // For a curve of the form f(x) = a * Sin(b * x - c) + d,
2187
+ // this function ensures that a, b > 0, and c is its
2188
+ // smallest possible positive value.
2189
+ let amplitude = coeffs[0];
2190
+ let angularFrequency = coeffs[1];
2191
+ let phase = coeffs[2];
2192
+ const verticalOffset = coeffs[3];
2193
+
2194
+ // Guarantee a > 0
2195
+ if (amplitude < 0) {
2196
+ amplitude *= -1;
2197
+ angularFrequency *= -1;
2198
+ phase *= -1;
2199
+ }
2200
+ const period = 2 * Math.PI;
2201
+ // Guarantee b > 0
2202
+ if (angularFrequency < 0) {
2203
+ angularFrequency *= -1;
2204
+ phase *= -1;
2205
+ phase += period / 2;
2206
+ }
2207
+
2208
+ // Guarantee c is smallest possible positive value
2209
+ while (phase > 0) {
2210
+ phase -= period;
2211
+ }
2212
+ while (phase < 0) {
2213
+ phase += period;
2214
+ }
2215
+ return [amplitude, angularFrequency, phase, verticalOffset];
2216
+ }
2217
+ function canonicalTangentCoefficients(coeffs) {
2218
+ // For a curve of the form f(x) = a * Tan(b * x - c) + d,
2219
+ // this function ensures that a, b > 0, and c is its
2220
+ // smallest possible positive value.
2221
+ let amplitude = coeffs[0];
2222
+ let angularFrequency = coeffs[1];
2223
+ let phase = coeffs[2];
2224
+ const verticalOffset = coeffs[3];
2225
+
2226
+ // Guarantee a > 0
2227
+ if (amplitude < 0) {
2228
+ amplitude *= -1;
2229
+ angularFrequency *= -1;
2230
+ phase *= -1;
2231
+ }
2232
+ const period = Math.PI;
2233
+ // Guarantee b > 0
2234
+ if (angularFrequency < 0) {
2235
+ angularFrequency *= -1;
2236
+ phase *= -1;
2237
+ phase += period / 2;
2238
+ }
2239
+
2240
+ // Guarantee c is smallest possible positive value
2241
+ while (phase > 0) {
2242
+ phase -= period;
2243
+ }
2244
+ while (phase < 0) {
2245
+ phase += period;
2246
+ }
2247
+ return [amplitude, angularFrequency, phase, verticalOffset];
2248
+ }
2249
+ const PlotDefaults = {
2250
+ areEqual: function (coeffs1, coeffs2) {
2251
+ return approximateDeepEqual(coeffs1, coeffs2);
2252
+ },
2253
+ movable: MOVABLES.PLOT,
2254
+ getPropsForCoeffs: function (coeffs) {
2255
+ return {
2256
+ // @ts-expect-error - TS2339 - Property 'getFunctionForCoeffs' does not exist on type '{ readonly areEqual: (coeffs1: any, coeffs2: any) => boolean; readonly Movable: any; readonly getPropsForCoeffs: (coeffs: any) => any; }'.
2257
+ fn: _.partial(this.getFunctionForCoeffs, coeffs)
2258
+ };
2259
+ }
2260
+ };
2261
+ const Linear = _.extend({}, PlotDefaults, {
2262
+ url: "https://ka-perseus-graphie.s3.amazonaws.com/67aaf581e6d9ef9038c10558a1f70ac21c11c9f8.png",
2263
+ defaultCoords: [[0.25, 0.75], [0.75, 0.75]],
2264
+ getCoefficients: function (coords) {
2265
+ const p1 = coords[0];
2266
+ const p2 = coords[1];
2267
+ const denom = p2[0] - p1[0];
2268
+ const num = p2[1] - p1[1];
2269
+ if (denom === 0) {
2270
+ return;
2271
+ }
2272
+ const m = num / denom;
2273
+ const b = p2[1] - m * p2[0];
2274
+ return [m, b];
2275
+ },
2276
+ getFunctionForCoeffs: function (coeffs, x) {
2277
+ const m = coeffs[0];
2278
+ const b = coeffs[1];
2279
+ return m * x + b;
2280
+ },
2281
+ getEquationString: function (coords) {
2282
+ const coeffs = this.getCoefficients(coords);
2283
+ const m = coeffs[0];
2284
+ const b = coeffs[1];
2285
+ return "y = " + m.toFixed(3) + "x + " + b.toFixed(3);
2286
+ }
2287
+ });
2288
+ const Quadratic = _.extend({}, PlotDefaults, {
2289
+ url: "https://ka-perseus-graphie.s3.amazonaws.com/e23d36e6fc29ee37174e92c9daba2a66677128ab.png",
2290
+ defaultCoords: [[0.5, 0.5], [0.75, 0.75]],
2291
+ movable: MOVABLES.PARABOLA,
2292
+ getCoefficients: function (coords) {
2293
+ const p1 = coords[0];
2294
+ const p2 = coords[1];
2295
+
2296
+ // Parabola with vertex (h, k) has form: y = a * (h - k)^2 + k
2297
+ const h = p1[0];
2298
+ const k = p1[1];
2299
+
2300
+ // Use these to calculate familiar a, b, c
2301
+ const a = (p2[1] - k) / ((p2[0] - h) * (p2[0] - h));
2302
+ const b = -2 * h * a;
2303
+ const c = a * h * h + k;
2304
+ return [a, b, c];
2305
+ },
2306
+ getFunctionForCoeffs: function (coeffs, x) {
2307
+ const a = coeffs[0];
2308
+ const b = coeffs[1];
2309
+ const c = coeffs[2];
2310
+ return (a * x + b) * x + c;
2311
+ },
2312
+ getPropsForCoeffs: function (coeffs) {
2313
+ return {
2314
+ a: coeffs[0],
2315
+ b: coeffs[1],
2316
+ c: coeffs[2]
2317
+ };
2318
+ },
2319
+ getEquationString: function (coords) {
2320
+ const coeffs = this.getCoefficients(coords);
2321
+ const a = coeffs[0];
2322
+ const b = coeffs[1];
2323
+ const c = coeffs[2];
2324
+ return "y = " + a.toFixed(3) + "x^2 + " + b.toFixed(3) + "x + " + c.toFixed(3);
2325
+ }
2326
+ });
2327
+ const Sinusoid = _.extend({}, PlotDefaults, {
2328
+ url: "https://ka-perseus-graphie.s3.amazonaws.com/3d68e7718498475f53b206c2ab285626baf8857e.png",
2329
+ defaultCoords: [[0.5, 0.5], [0.6, 0.6]],
2330
+ movable: MOVABLES.SINUSOID,
2331
+ getCoefficients: function (coords) {
2332
+ const p1 = coords[0];
2333
+ const p2 = coords[1];
2334
+ const a = p2[1] - p1[1];
2335
+ const b = Math.PI / (2 * (p2[0] - p1[0]));
2336
+ const c = p1[0] * b;
2337
+ const d = p1[1];
2338
+ return [a, b, c, d];
2339
+ },
2340
+ getFunctionForCoeffs: function (coeffs, x) {
2341
+ const a = coeffs[0];
2342
+ const b = coeffs[1];
2343
+ const c = coeffs[2];
2344
+ const d = coeffs[3];
2345
+ return a * Math.sin(b * x - c) + d;
2346
+ },
2347
+ getPropsForCoeffs: function (coeffs) {
2348
+ return {
2349
+ a: coeffs[0],
2350
+ b: coeffs[1],
2351
+ c: coeffs[2],
2352
+ d: coeffs[3]
2353
+ };
2354
+ },
2355
+ getEquationString: function (coords) {
2356
+ const coeffs = this.getCoefficients(coords);
2357
+ const a = coeffs[0];
2358
+ const b = coeffs[1];
2359
+ const c = coeffs[2];
2360
+ const d = coeffs[3];
2361
+ return "y = " + a.toFixed(3) + " sin(" + b.toFixed(3) + "x - " + c.toFixed(3) + ") + " + d.toFixed(3);
2362
+ },
2363
+ areEqual: function (coeffs1, coeffs2) {
2364
+ return approximateDeepEqual(canonicalSineCoefficients(coeffs1), canonicalSineCoefficients(coeffs2));
2365
+ }
2366
+ });
2367
+ const Tangent = _.extend({}, PlotDefaults, {
2368
+ url: "https://ka-perseus-graphie.s3.amazonaws.com/7db80d23c35214f98659fe1cf0765811c1bbfbba.png",
2369
+ defaultCoords: [[0.5, 0.5], [0.75, 0.75]],
2370
+ getCoefficients: function (coords) {
2371
+ const p1 = coords[0];
2372
+ const p2 = coords[1];
2373
+ const a = p2[1] - p1[1];
2374
+ const b = Math.PI / (4 * (p2[0] - p1[0]));
2375
+ const c = p1[0] * b;
2376
+ const d = p1[1];
2377
+ return [a, b, c, d];
2378
+ },
2379
+ getFunctionForCoeffs: function (coeffs, x) {
2380
+ const a = coeffs[0];
2381
+ const b = coeffs[1];
2382
+ const c = coeffs[2];
2383
+ const d = coeffs[3];
2384
+ return a * Math.tan(b * x - c) + d;
2385
+ },
2386
+ getEquationString: function (coords) {
2387
+ const coeffs = this.getCoefficients(coords);
2388
+ const a = coeffs[0];
2389
+ const b = coeffs[1];
2390
+ const c = coeffs[2];
2391
+ const d = coeffs[3];
2392
+ return "y = " + a.toFixed(3) + " sin(" + b.toFixed(3) + "x - " + c.toFixed(3) + ") + " + d.toFixed(3);
2393
+ },
2394
+ areEqual: function (coeffs1, coeffs2) {
2395
+ return approximateDeepEqual(canonicalTangentCoefficients(coeffs1), canonicalTangentCoefficients(coeffs2));
2396
+ }
2397
+ });
2398
+ const Exponential = _.extend({}, PlotDefaults, {
2399
+ url: "https://ka-perseus-graphie.s3.amazonaws.com/9cbfad55525e3ce755a31a631b074670a5dad611.png",
2400
+ defaultCoords: [[0.5, 0.55], [0.75, 0.75]],
2401
+ defaultAsymptote: [[0, 0.5], [1.0, 0.5]],
2402
+ /**
2403
+ * Add extra constraints for movement of the points or asymptote (below):
2404
+ * newCoord: [x, y]
2405
+ * The end position of the point or asymptote endpoint
2406
+ * oldCoord: [x, y]
2407
+ * The old position of the point or asymptote endpoint
2408
+ * coords:
2409
+ * An array of coordinates representing the proposed end configuration
2410
+ * of the plot coordinates.
2411
+ * asymptote:
2412
+ * An array of coordinates representing the proposed end configuration
2413
+ * of the asymptote.
2414
+ *
2415
+ * Return: either a coordinate (to be used as the resulting coordinate of
2416
+ * the move) or a boolean, where `true` uses newCoord as the resulting
2417
+ * coordinate, and `false` uses oldCoord as the resulting coordinate.
2418
+ */
2419
+ extraCoordConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
2420
+ const y = asymptote[0][1];
2421
+ return _.all(coords, coord => coord[1] !== y);
2422
+ },
2423
+ extraAsymptoteConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
2424
+ const y = newCoord[1];
2425
+ const isValid = _.all(coords, coord => coord[1] > y) || _.all(coords, coord => coord[1] < y);
2426
+ if (isValid) {
2427
+ return [oldCoord[0], y];
2428
+ }
2429
+ // Snap the asymptote as close as possible, i.e., if the user moves
2430
+ // the mouse really quickly into an invalid region
2431
+ const oldY = oldCoord[1];
2432
+ const wasBelow = _.all(coords, coord => coord[1] > oldY);
2433
+ if (wasBelow) {
2434
+ const bottomMost = _.min(_.map(coords, coord => coord[1]));
2435
+ return [oldCoord[0], bottomMost - graph.snapStep[1]];
2436
+ }
2437
+ const topMost = _.max(_.map(coords, coord => coord[1]));
2438
+ return [oldCoord[0], topMost + graph.snapStep[1]];
2439
+ },
2440
+ allowReflectOverAsymptote: true,
2441
+ getCoefficients: function (coords, asymptote) {
2442
+ const p1 = coords[0];
2443
+ const p2 = coords[1];
2444
+ const c = asymptote[0][1];
2445
+ const b = Math.log((p1[1] - c) / (p2[1] - c)) / (p1[0] - p2[0]);
2446
+ const a = (p1[1] - c) / Math.exp(b * p1[0]);
2447
+ return [a, b, c];
2448
+ },
2449
+ getFunctionForCoeffs: function (coeffs, x) {
2450
+ const a = coeffs[0];
2451
+ const b = coeffs[1];
2452
+ const c = coeffs[2];
2453
+ return a * Math.exp(b * x) + c;
2454
+ },
2455
+ getEquationString: function (coords, asymptote) {
2456
+ if (!asymptote) {
2457
+ return null;
2458
+ }
2459
+ const coeffs = this.getCoefficients(coords, asymptote);
2460
+ const a = coeffs[0];
2461
+ const b = coeffs[1];
2462
+ const c = coeffs[2];
2463
+ return "y = " + a.toFixed(3) + "e^(" + b.toFixed(3) + "x) + " + c.toFixed(3);
2464
+ }
2465
+ });
2466
+ const Logarithm = _.extend({}, PlotDefaults, {
2467
+ url: "https://ka-perseus-graphie.s3.amazonaws.com/f6491e99d34af34d924bfe0231728ad912068dc3.png",
2468
+ defaultCoords: [[0.55, 0.5], [0.75, 0.75]],
2469
+ defaultAsymptote: [[0.5, 0], [0.5, 1.0]],
2470
+ extraCoordConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
2471
+ const x = asymptote[0][0];
2472
+ return _.all(coords, coord => coord[0] !== x) && coords[0][1] !== coords[1][1];
2473
+ },
2474
+ extraAsymptoteConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
2475
+ const x = newCoord[0];
2476
+ const isValid = _.all(coords, coord => coord[0] > x) || _.all(coords, coord => coord[0] < x);
2477
+ if (isValid) {
2478
+ return [x, oldCoord[1]];
2479
+ }
2480
+ // Snap the asymptote as close as possible, i.e., if the user moves
2481
+ // the mouse really quickly into an invalid region
2482
+ const oldX = oldCoord[0];
2483
+ const wasLeft = _.all(coords, coord => coord[0] > oldX);
2484
+ if (wasLeft) {
2485
+ const leftMost = _.min(_.map(coords, coord => coord[0]));
2486
+ return [leftMost - graph.snapStep[0], oldCoord[1]];
2487
+ }
2488
+ const rightMost = _.max(_.map(coords, coord => coord[0]));
2489
+ return [rightMost + graph.snapStep[0], oldCoord[1]];
2490
+ },
2491
+ allowReflectOverAsymptote: true,
2492
+ getCoefficients: function (coords, asymptote) {
2493
+ // It's easiest to calculate the logarithm's coefficients by thinking
2494
+ // about it as the inverse of the exponential, so we flip x and y and
2495
+ // perform some algebra on the coefficients. This also unifies the
2496
+ // logic between the two 'models'.
2497
+ const flip = coord => [coord[1], coord[0]];
2498
+ const inverseCoeffs = Exponential.getCoefficients(_.map(coords, flip), _.map(asymptote, flip));
2499
+ if (inverseCoeffs) {
2500
+ const c = -inverseCoeffs[2] / inverseCoeffs[0];
2501
+ const b = 1 / inverseCoeffs[0];
2502
+ const a = 1 / inverseCoeffs[1];
2503
+ return [a, b, c];
2504
+ }
2505
+ },
2506
+ getFunctionForCoeffs: function (coeffs, x, asymptote) {
2507
+ const a = coeffs[0];
2508
+ const b = coeffs[1];
2509
+ const c = coeffs[2];
2510
+ return a * Math.log(b * x + c);
2511
+ },
2512
+ getEquationString: function (coords, asymptote) {
2513
+ if (!asymptote) {
2514
+ return null;
2515
+ }
2516
+ const coeffs = this.getCoefficients(coords, asymptote);
2517
+ const a = coeffs[0];
2518
+ const b = coeffs[1];
2519
+ const c = coeffs[2];
2520
+ return "y = ln(" + a.toFixed(3) + "x + " + b.toFixed(3) + ") + " + c.toFixed(3);
2521
+ }
2522
+ });
2523
+ const AbsoluteValue = _.extend({}, PlotDefaults, {
2524
+ url: "https://ka-perseus-graphie.s3.amazonaws.com/8256a630175a0cb1d11de223d6de0266daf98721.png",
2525
+ defaultCoords: [[0.5, 0.5], [0.75, 0.75]],
2526
+ getCoefficients: function (coords) {
2527
+ const p1 = coords[0];
2528
+ const p2 = coords[1];
2529
+ const denom = p2[0] - p1[0];
2530
+ const num = p2[1] - p1[1];
2531
+ if (denom === 0) {
2532
+ return;
2533
+ }
2534
+ let m = Math.abs(num / denom);
2535
+ if (p2[1] < p1[1]) {
2536
+ m *= -1;
2537
+ }
2538
+ const horizontalOffset = p1[0];
2539
+ const verticalOffset = p1[1];
2540
+ return [m, horizontalOffset, verticalOffset];
2541
+ },
2542
+ getFunctionForCoeffs: function (coeffs, x) {
2543
+ const m = coeffs[0];
2544
+ const horizontalOffset = coeffs[1];
2545
+ const verticalOffset = coeffs[2];
2546
+ return m * Math.abs(x - horizontalOffset) + verticalOffset;
2547
+ },
2548
+ getEquationString: function (coords) {
2549
+ const coeffs = this.getCoefficients(coords);
2550
+ const m = coeffs[0];
2551
+ const horizontalOffset = coeffs[1];
2552
+ const verticalOffset = coeffs[2];
2553
+ return "y = " + m.toFixed(3) + "| x - " + horizontalOffset.toFixed(3) + "| + " + verticalOffset.toFixed(3);
2554
+ }
2555
+ });
2556
+
2557
+ /* Utility functions for dealing with graphing interfaces. */
2558
+ const functionTypeMapping = {
2559
+ linear: Linear,
2560
+ quadratic: Quadratic,
2561
+ sinusoid: Sinusoid,
2562
+ tangent: Tangent,
2563
+ exponential: Exponential,
2564
+ logarithm: Logarithm,
2565
+ absolute_value: AbsoluteValue
2566
+ };
2567
+ const allTypes = _.keys(functionTypeMapping);
2568
+ function functionForType(type) {
2569
+ // @ts-expect-error: TypeScript doesn't know how to use deal with generics
2570
+ // and conditional types in this way.
2571
+ return functionTypeMapping[type];
2572
+ }
2573
+
2574
+ var grapherUtil = /*#__PURE__*/Object.freeze({
2575
+ __proto__: null,
2576
+ MOVABLES: MOVABLES,
2577
+ allTypes: allTypes,
2578
+ functionForType: functionForType
2579
+ });
2580
+
2581
+ // This file is processed by a Rollup plugin (replace) to inject the production
2582
+ const libName = "@khanacademy/perseus-core";
2583
+ const libVersion = "3.2.0";
2584
+ addLibraryVersionToPerseusDebug(libName, libVersion);
2585
+
2586
+ /**
2587
+ * @typedef {Object} Errors utility for referencing the Perseus error taxonomy.
2588
+ */
2589
+ const Errors = Object.freeze({
2590
+ /**
2591
+ * @property {ErrorKind} Unknown The kind of error is not known.
2592
+ */
2593
+ Unknown: "Unknown",
2594
+ /**
2595
+ * @property {ErrorKind} Internal The error is internal to the executing code.
2596
+ */
2597
+ Internal: "Internal",
2598
+ /**
2599
+ * @property {ErrorKind} InvalidInput There was a problem with the provided
2600
+ * input, such as the wrong format or a null value.
2601
+ */
2602
+ InvalidInput: "InvalidInput",
2603
+ /**
2604
+ * @property {ErrorKind} NotAllowed There was a problem due to the state of
2605
+ * the system not matching the requested operation or input. For example,
2606
+ * trying to create a username that is valid, but is already taken by
2607
+ * another user. Use {@link InvalidInput} instead when the input isn't
2608
+ * valid regardless of the state of the system. Use {@link NotFound} when
2609
+ * the failure is due to not being able to find a resource.
2610
+ */
2611
+ NotAllowed: "NotAllowed",
2612
+ /**
2613
+ * @property {ErrorKind} TransientService There was a problem when making a
2614
+ * request to a service.
2615
+ */
2616
+ TransientService: "TransientService",
2617
+ /**
2618
+ * @property {ErrorKind} Service There was a non-transient problem when
2619
+ * making a request to service.
2620
+ */
2621
+ Service: "Service"
2622
+ });
2623
+
2624
+ /**
2625
+ * @type {ErrorKind} The kind of error being reported
2626
+ */
2627
+
2628
+ class PerseusError extends Error {
2629
+ constructor(message, kind, options) {
2630
+ super(message);
2631
+ this.kind = void 0;
2632
+ this.metadata = void 0;
2633
+ this.kind = kind;
2634
+ this.metadata = options == null ? void 0 : options.metadata;
2635
+ }
2636
+ }
2637
+
2638
+ /**
2639
+ * The Perseus "data schema" file.
2640
+ *
2641
+ * This file, and the types in it, represents the "data schema" that Perseus
2642
+ * uses. The @khanacademy/perseus-editor package edits and produces objects
2643
+ * that conform to the types in this file. Similarly, the top-level renderers
2644
+ * in @khanacademy/perseus, consume objects that conform to these types.
2645
+ *
2646
+ * WARNING: This file should not import any types from elsewhere so that it is
2647
+ * easy to reason about changes that alter the Perseus schema. This helps
2648
+ * ensure that it is not changed accidentally when upgrading a dependant
2649
+ * package or other part of Perseus code. Note that TypeScript does type
2650
+ * checking via something called "structural typing". This means that as long
2651
+ * as the shape of a type matches, the name it goes by doesn't matter. As a
2652
+ * result, a `Coord` type that looks like this `[x: number, y: number]` is
2653
+ * _identical_, in TypeScript's eyes, to this `Vector2` type `[x: number, y:
2654
+ * number]`. Also, with tuples, the labels for each entry is ignored, so `[x:
2655
+ * number, y: number]` is compatible with `[min: number, max: number]`. The
2656
+ * labels are for humans, not TypeScript. :)
2657
+ *
2658
+ * If you make changes to types in this file, be very sure that:
2659
+ *
2660
+ * a) the changes are backwards compatible. If they are not, old data from
2661
+ * previous versions of the "schema" could become unrenderable, or worse,
2662
+ * introduce hard-to-diagnose bugs.
2663
+ * b) the parsing code (`util/parse-perseus-json/`) is updated to handle
2664
+ * the new format _as well as_ the old format.
2665
+ */
2666
+
2667
+ // TODO(FEI-4010): Remove `Perseus` prefix for all types here
2668
+
2669
+ // Same name as Mafs
2670
+
2671
+ /**
2672
+ * Our core set of Perseus widgets.
2673
+ *
2674
+ * This interface is the basis for "registering" all Perseus widget types.
2675
+ * There should be one key/value pair for each supported widget. If you create
2676
+ * a new widget, an entry should be added to this interface. Note that this
2677
+ * only registers the widget options type, you'll also need to register the
2678
+ * widget so that it's available at runtime (@see
2679
+ * {@link file://./widgets.ts#registerWidget}).
2680
+ *
2681
+ * Importantly, the key should be the name that is used in widget IDs. For most
2682
+ * widgets that is the same as the widget option's `type` field. In cases where
2683
+ * a widget has been deprecated and replaced with the deprecated-standin
2684
+ * widget, it should be the original widget type!
2685
+ *
2686
+ * If you define the widget outside of this package, you can still add the new
2687
+ * widget to this interface by writing the following in that package that
2688
+ * contains the widget. TypeScript will merge that definition of the
2689
+ * `PerseusWidgets` with the one defined below.
2690
+ *
2691
+ * ```typescript
2692
+ * declare module "@khanacademy/perseus" {
2693
+ * interface PerseusWidgetTypes {
2694
+ * // A new widget
2695
+ * "new-awesomeness": MyAwesomeNewWidget;
2696
+ *
2697
+ * // A deprecated widget
2698
+ * "super-old-widget": DeprecatedStandinWidget;
2699
+ * }
2700
+ * }
2701
+ *
2702
+ * // The new widget's options definition
2703
+ * type MyAwesomeNewWidget = WidgetOptions<'new-awesomeness', MyAwesomeNewWidgetOptions>;
2704
+ *
2705
+ * // The deprecated widget's options definition
2706
+ * type SuperOldWidget = WidgetOptions<'super-old-widget', object>;
2707
+ * ```
2708
+ *
2709
+ * This interface can be extended through the magic of TypeScript "Declaration
2710
+ * merging". Specifically, we augment this module and extend this interface.
2711
+ *
2712
+ * @see {@link https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation}
2713
+ */
2714
+
2715
+ /**
2716
+ * A map of widget IDs to widget options. This is most often used as the type
2717
+ * for a set of widgets defined in a `PerseusItem` but can also be useful to
2718
+ * represent a function parameter where only `widgets` from a `PerseusItem` are
2719
+ * needed. Today Widget IDs are made up of the widget type and an incrementing
2720
+ * integer (eg. `interactive-graph 1` or `radio 3`). It is suggested to avoid
2721
+ * reading/parsing the widget id to derive any information from it, except in
2722
+ * the case of this map.
2723
+ *
2724
+ * @see {@link PerseusWidgetTypes} additional widgets can be added to this map type
2725
+ * by augmenting the PerseusWidgetTypes with new widget types!
2726
+ */
2727
+
2728
+ /**
2729
+ * A "PerseusItem" is a classic Perseus item. It is rendered by the
2730
+ * `ServerItemRenderer` and the layout is pre-set.
2731
+ *
2732
+ * To render more complex Perseus items, see the `Item` type in the multi item
2733
+ * area.
2734
+ */
2735
+
2736
+ /**
2737
+ * A "PerseusArticle" is an item that is meant to be rendered as an article.
2738
+ * This item is never scored and is rendered by the `ArticleRenderer`.
2739
+ */
2740
+
2741
+ const ItemExtras = [
2742
+ // The user might benefit from using a Scientific Calculator. Provided on Khan Academy when true
2743
+ "calculator",
2744
+ // The user might benefit from using a statistics Chi Squared Table like https://people.richland.edu/james/lecture/m170/tbl-chi.html
2745
+ "chi2Table",
2746
+ // The user might benefit from a monthly payments calculator. Provided on Khan Academy when true
2747
+ "financialCalculatorMonthlyPayment",
2748
+ // The user might benefit from a total amount calculator. Provided on Khan Academy when true
2749
+ "financialCalculatorTotalAmount",
2750
+ // The user might benefit from a time to pay off calculator. Provided on Khan Academy when true
2751
+ "financialCalculatorTimeToPayOff",
2752
+ // The user might benefit from using a Periodic Table of Elements. Provided on Khan Academy when true
2753
+ "periodicTable",
2754
+ // The user might benefit from using a Periodic Table of Elements with key. Provided on Khan Academy when true
2755
+ "periodicTableWithKey",
2756
+ // The user might benefit from using a statistics T Table like https://www.statisticshowto.com/tables/t-distribution-table/
2757
+ "tTable",
2758
+ // The user might benefit from using a statistics Z Table like https://www.ztable.net/
2759
+ "zTable"];
2760
+
2761
+ /**
2762
+ * The type representing the common structure of all widget's options. The
2763
+ * `Options` generic type represents the widget-specific option data.
2764
+ */
2765
+
2766
+ // prettier-ignore
2767
+
2768
+ // prettier-ignore
2769
+
2770
+ // prettier-ignore
2771
+
2772
+ // prettier-ignore
2773
+
2774
+ // prettier-ignore
2775
+
2776
+ // prettier-ignore
2777
+
2778
+ // prettier-ignore
2779
+
2780
+ // prettier-ignore
2781
+
2782
+ // prettier-ignore
2783
+
2784
+ // prettier-ignore
2785
+
2786
+ // prettier-ignore
2787
+
2788
+ // prettier-ignore
2789
+
2790
+ // prettier-ignore
2791
+
2792
+ // prettier-ignore
2793
+
2794
+ // prettier-ignore
2795
+
2796
+ // prettier-ignore
2797
+
2798
+ // prettier-ignore
2799
+
2800
+ // prettier-ignore
2801
+
2802
+ // prettier-ignore
2803
+
2804
+ // prettier-ignore
2805
+
2806
+ // prettier-ignore
2807
+
2808
+ // prettier-ignore
2809
+
2810
+ // prettier-ignore
2811
+
2812
+ // prettier-ignore
2813
+
2814
+ // prettier-ignore
2815
+
2816
+ // prettier-ignore
2817
+
2818
+ // prettier-ignore
2819
+
2820
+ // prettier-ignore
2821
+
2822
+ // prettier-ignore
2823
+
2824
+ // prettier-ignore
2825
+
2826
+ // prettier-ignore
2827
+
2828
+ // prettier-ignore
2829
+
2830
+ // prettier-ignore
2831
+
2832
+ // prettier-ignore
2833
+
2834
+ //prettier-ignore
2835
+
2836
+ /**
2837
+ * A background image applied to various widgets.
2838
+ */
2839
+
2840
+ /**
2841
+ * The type of markings to display on the graph.
2842
+ * - axes: shows the axes without the gride lines
2843
+ * - graph: shows the axes and the grid lines
2844
+ * - grid: shows only the grid lines
2845
+ * - none: shows no markings
2846
+ */
2847
+
2848
+ const PerseusExpressionAnswerFormConsidered = ["correct", "wrong", "ungraded"];
2849
+
2850
+ // 2D range: xMin, xMax, yMin, yMax
2851
+
2852
+ const lockedFigureColorNames = ["blue", "green", "grayH", "purple", "pink", "orange", "red"];
2853
+ const lockedFigureColors = {
2854
+ blue: "#3D7586",
2855
+ green: "#447A53",
2856
+ grayH: "#3B3D45",
2857
+ purple: "#594094",
2858
+ pink: "#B25071",
2859
+ red: "#D92916",
2860
+ orange: "#946700"
2861
+ };
2862
+ const lockedFigureFillStyles = {
2863
+ none: 0,
2864
+ white: 1,
2865
+ translucent: 0.4,
2866
+ solid: 1
2867
+ };
2868
+
2869
+ // Not associated with a specific figure
2870
+
2871
+ const plotterPlotTypes = ["bar", "line", "pic", "histogram", "dotplot"];
2872
+
2359
2873
  /**
2360
2874
  * _ utilities for objects
2361
2875
  */
@@ -2400,5 +2914,5 @@ const mapObject = function mapObject(obj, lambda) {
2400
2914
  return result;
2401
2915
  };
2402
2916
 
2403
- export { Errors, ItemExtras, PerseusError, PerseusExpressionAnswerFormConsidered, addLibraryVersionToPerseusDebug, libVersion, lockedFigureColorNames, lockedFigureColors, lockedFigureFillStyles, mapObject, plotterPlotTypes, pluck };
2917
+ export { Errors, grapherUtil as GrapherUtil, ItemExtras, PerseusError, PerseusExpressionAnswerFormConsidered, addLibraryVersionToPerseusDebug, approximateDeepEqual, approximateEqual, deepClone, getDecimalSeparator, getMatrixSize, libVersion, lockedFigureColorNames, lockedFigureColors, lockedFigureFillStyles, mapObject, plotterPlotTypes, pluck };
2404
2918
  //# sourceMappingURL=index.js.map