@khanacademy/perseus-core 3.6.0 → 4.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/LICENSE +18 -0
- package/dist/data-schema.d.ts +25 -7
- package/dist/es/index.js +262 -2140
- package/dist/es/index.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +293 -2147
- package/dist/index.js.map +1 -1
- package/dist/parse-perseus-json/perseus-parsers/interactive-graph-widget.d.ts +1 -0
- package/dist/parse-perseus-json/perseus-parsers/perseus-answer-area.d.ts +2 -0
- package/dist/utils/random-util.d.ts +5 -0
- package/dist/widgets/dropdown/dropdown-util.d.ts +1 -1
- package/dist/widgets/group/index.d.ts +1 -1
- package/dist/widgets/interactive-graph/interactive-graph-util.d.ts +1 -2
- package/dist/widgets/logic-export.types.d.ts +2 -1
- package/dist/widgets/matcher/matcher-util.d.ts +28 -0
- package/dist/widgets/numeric-input/numeric-input-util.d.ts +3 -2
- package/dist/widgets/sorter/sorter-util.d.ts +1 -0
- package/package.json +33 -32
- /package/dist/{utils → shared-utils}/add-library-version-to-perseus-debug.d.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -2,2079 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* object and ensures that the object is attached to `globalThis` (`window` in
|
|
8
|
-
* browser environments).
|
|
9
|
-
*
|
|
10
|
-
* This allows each library to provide runtime version information to assist in
|
|
11
|
-
* debugging in production environments.
|
|
12
|
-
*/
|
|
13
|
-
const addLibraryVersionToPerseusDebug = (libraryName, libraryVersion) => {
|
|
14
|
-
// If the library version is the default value, then we don't want to
|
|
15
|
-
// prefix it with a "v" to indicate that it is a version number.
|
|
16
|
-
let prefix = "v";
|
|
17
|
-
if (libraryVersion === "__lib_version__") {
|
|
18
|
-
prefix = "";
|
|
19
|
-
}
|
|
20
|
-
const formattedVersion = `${prefix}${libraryVersion}`;
|
|
21
|
-
if (typeof globalThis !== "undefined") {
|
|
22
|
-
globalThis.__perseus_debug__ = globalThis.__perseus_debug__ ?? {};
|
|
23
|
-
const existingVersionEntry = globalThis.__perseus_debug__[libraryName];
|
|
24
|
-
if (existingVersionEntry) {
|
|
25
|
-
// If we already have an entry and it doesn't match the registered
|
|
26
|
-
// version, we morph the entry into an array and log a warning.
|
|
27
|
-
if (existingVersionEntry !== formattedVersion) {
|
|
28
|
-
// Existing entry might be an array already (oops, at least 2
|
|
29
|
-
// versions of the library already loaded!).
|
|
30
|
-
const allVersions = Array.isArray(existingVersionEntry) ? existingVersionEntry : [existingVersionEntry];
|
|
31
|
-
allVersions.push(formattedVersion);
|
|
32
|
-
globalThis.__perseus_debug__[libraryName] = allVersions;
|
|
33
|
-
|
|
34
|
-
// eslint-disable-next-line no-console
|
|
35
|
-
console.warn(`Multiple versions of ${libraryName} loaded on this page: ${allVersions.sort().join(", ")}`);
|
|
36
|
-
}
|
|
37
|
-
} else {
|
|
38
|
-
globalThis.__perseus_debug__[libraryName] = formattedVersion;
|
|
39
|
-
}
|
|
40
|
-
} else {
|
|
41
|
-
// eslint-disable-next-line no-console
|
|
42
|
-
console.warn(`globalThis not found found (${formattedVersion})`);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// Current version.
|
|
47
|
-
var VERSION = '1.13.3';
|
|
48
|
-
|
|
49
|
-
// Establish the root object, `window` (`self`) in the browser, `global`
|
|
50
|
-
// on the server, or `this` in some virtual machines. We use `self`
|
|
51
|
-
// instead of `window` for `WebWorker` support.
|
|
52
|
-
var root = (typeof self == 'object' && self.self === self && self) ||
|
|
53
|
-
(typeof global == 'object' && global.global === global && global) ||
|
|
54
|
-
Function('return this')() ||
|
|
55
|
-
{};
|
|
56
|
-
|
|
57
|
-
// Save bytes in the minified (but not gzipped) version:
|
|
58
|
-
var ArrayProto = Array.prototype, ObjProto = Object.prototype;
|
|
59
|
-
var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
|
|
60
|
-
|
|
61
|
-
// Create quick reference variables for speed access to core prototypes.
|
|
62
|
-
var push = ArrayProto.push,
|
|
63
|
-
slice = ArrayProto.slice,
|
|
64
|
-
toString = ObjProto.toString,
|
|
65
|
-
hasOwnProperty = ObjProto.hasOwnProperty;
|
|
66
|
-
|
|
67
|
-
// Modern feature detection.
|
|
68
|
-
var supportsArrayBuffer = typeof ArrayBuffer !== 'undefined',
|
|
69
|
-
supportsDataView = typeof DataView !== 'undefined';
|
|
70
|
-
|
|
71
|
-
// All **ECMAScript 5+** native function implementations that we hope to use
|
|
72
|
-
// are declared here.
|
|
73
|
-
var nativeIsArray = Array.isArray,
|
|
74
|
-
nativeKeys = Object.keys,
|
|
75
|
-
nativeCreate = Object.create,
|
|
76
|
-
nativeIsView = supportsArrayBuffer && ArrayBuffer.isView;
|
|
77
|
-
|
|
78
|
-
// Create references to these builtin functions because we override them.
|
|
79
|
-
var _isNaN = isNaN,
|
|
80
|
-
_isFinite = isFinite;
|
|
81
|
-
|
|
82
|
-
// Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
|
|
83
|
-
var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
|
|
84
|
-
var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
|
|
85
|
-
'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
|
|
86
|
-
|
|
87
|
-
// The largest integer that can be represented exactly.
|
|
88
|
-
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
|
|
89
|
-
|
|
90
|
-
// Some functions take a variable number of arguments, or a few expected
|
|
91
|
-
// arguments at the beginning and then a variable number of values to operate
|
|
92
|
-
// on. This helper accumulates all remaining arguments past the function’s
|
|
93
|
-
// argument length (or an explicit `startIndex`), into an array that becomes
|
|
94
|
-
// the last argument. Similar to ES6’s "rest parameter".
|
|
95
|
-
function restArguments(func, startIndex) {
|
|
96
|
-
startIndex = startIndex == null ? func.length - 1 : +startIndex;
|
|
97
|
-
return function() {
|
|
98
|
-
var length = Math.max(arguments.length - startIndex, 0),
|
|
99
|
-
rest = Array(length),
|
|
100
|
-
index = 0;
|
|
101
|
-
for (; index < length; index++) {
|
|
102
|
-
rest[index] = arguments[index + startIndex];
|
|
103
|
-
}
|
|
104
|
-
switch (startIndex) {
|
|
105
|
-
case 0: return func.call(this, rest);
|
|
106
|
-
case 1: return func.call(this, arguments[0], rest);
|
|
107
|
-
case 2: return func.call(this, arguments[0], arguments[1], rest);
|
|
108
|
-
}
|
|
109
|
-
var args = Array(startIndex + 1);
|
|
110
|
-
for (index = 0; index < startIndex; index++) {
|
|
111
|
-
args[index] = arguments[index];
|
|
112
|
-
}
|
|
113
|
-
args[startIndex] = rest;
|
|
114
|
-
return func.apply(this, args);
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Is a given variable an object?
|
|
119
|
-
function isObject$1(obj) {
|
|
120
|
-
var type = typeof obj;
|
|
121
|
-
return type === 'function' || (type === 'object' && !!obj);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Is a given value equal to null?
|
|
125
|
-
function isNull(obj) {
|
|
126
|
-
return obj === null;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Is a given variable undefined?
|
|
130
|
-
function isUndefined(obj) {
|
|
131
|
-
return obj === void 0;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Is a given value a boolean?
|
|
135
|
-
function isBoolean(obj) {
|
|
136
|
-
return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Is a given value a DOM element?
|
|
140
|
-
function isElement(obj) {
|
|
141
|
-
return !!(obj && obj.nodeType === 1);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Internal function for creating a `toString`-based type tester.
|
|
145
|
-
function tagTester(name) {
|
|
146
|
-
var tag = '[object ' + name + ']';
|
|
147
|
-
return function(obj) {
|
|
148
|
-
return toString.call(obj) === tag;
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
var isString = tagTester('String');
|
|
153
|
-
|
|
154
|
-
var isNumber = tagTester('Number');
|
|
155
|
-
|
|
156
|
-
var isDate = tagTester('Date');
|
|
157
|
-
|
|
158
|
-
var isRegExp = tagTester('RegExp');
|
|
159
|
-
|
|
160
|
-
var isError = tagTester('Error');
|
|
161
|
-
|
|
162
|
-
var isSymbol = tagTester('Symbol');
|
|
163
|
-
|
|
164
|
-
var isArrayBuffer = tagTester('ArrayBuffer');
|
|
165
|
-
|
|
166
|
-
var isFunction = tagTester('Function');
|
|
167
|
-
|
|
168
|
-
// Optimize `isFunction` if appropriate. Work around some `typeof` bugs in old
|
|
169
|
-
// v8, IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236).
|
|
170
|
-
var nodelist = root.document && root.document.childNodes;
|
|
171
|
-
if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') {
|
|
172
|
-
isFunction = function(obj) {
|
|
173
|
-
return typeof obj == 'function' || false;
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
var isFunction$1 = isFunction;
|
|
178
|
-
|
|
179
|
-
var hasObjectTag = tagTester('Object');
|
|
180
|
-
|
|
181
|
-
// In IE 10 - Edge 13, `DataView` has string tag `'[object Object]'`.
|
|
182
|
-
// In IE 11, the most common among them, this problem also applies to
|
|
183
|
-
// `Map`, `WeakMap` and `Set`.
|
|
184
|
-
var hasStringTagBug = (
|
|
185
|
-
supportsDataView && hasObjectTag(new DataView(new ArrayBuffer(8)))
|
|
186
|
-
),
|
|
187
|
-
isIE11 = (typeof Map !== 'undefined' && hasObjectTag(new Map));
|
|
188
|
-
|
|
189
|
-
var isDataView = tagTester('DataView');
|
|
190
|
-
|
|
191
|
-
// In IE 10 - Edge 13, we need a different heuristic
|
|
192
|
-
// to determine whether an object is a `DataView`.
|
|
193
|
-
function ie10IsDataView(obj) {
|
|
194
|
-
return obj != null && isFunction$1(obj.getInt8) && isArrayBuffer(obj.buffer);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
var isDataView$1 = (hasStringTagBug ? ie10IsDataView : isDataView);
|
|
198
|
-
|
|
199
|
-
// Is a given value an array?
|
|
200
|
-
// Delegates to ECMA5's native `Array.isArray`.
|
|
201
|
-
var isArray = nativeIsArray || tagTester('Array');
|
|
202
|
-
|
|
203
|
-
// Internal function to check whether `key` is an own property name of `obj`.
|
|
204
|
-
function has$1(obj, key) {
|
|
205
|
-
return obj != null && hasOwnProperty.call(obj, key);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
var isArguments = tagTester('Arguments');
|
|
209
|
-
|
|
210
|
-
// Define a fallback version of the method in browsers (ahem, IE < 9), where
|
|
211
|
-
// there isn't any inspectable "Arguments" type.
|
|
212
|
-
(function() {
|
|
213
|
-
if (!isArguments(arguments)) {
|
|
214
|
-
isArguments = function(obj) {
|
|
215
|
-
return has$1(obj, 'callee');
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
}());
|
|
219
|
-
|
|
220
|
-
var isArguments$1 = isArguments;
|
|
221
|
-
|
|
222
|
-
// Is a given object a finite number?
|
|
223
|
-
function isFinite$1(obj) {
|
|
224
|
-
return !isSymbol(obj) && _isFinite(obj) && !isNaN(parseFloat(obj));
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Is the given value `NaN`?
|
|
228
|
-
function isNaN$1(obj) {
|
|
229
|
-
return isNumber(obj) && _isNaN(obj);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Predicate-generating function. Often useful outside of Underscore.
|
|
233
|
-
function constant$1(value) {
|
|
234
|
-
return function() {
|
|
235
|
-
return value;
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Common internal logic for `isArrayLike` and `isBufferLike`.
|
|
240
|
-
function createSizePropertyCheck(getSizeProperty) {
|
|
241
|
-
return function(collection) {
|
|
242
|
-
var sizeProperty = getSizeProperty(collection);
|
|
243
|
-
return typeof sizeProperty == 'number' && sizeProperty >= 0 && sizeProperty <= MAX_ARRAY_INDEX;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Internal helper to generate a function to obtain property `key` from `obj`.
|
|
248
|
-
function shallowProperty(key) {
|
|
249
|
-
return function(obj) {
|
|
250
|
-
return obj == null ? void 0 : obj[key];
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Internal helper to obtain the `byteLength` property of an object.
|
|
255
|
-
var getByteLength = shallowProperty('byteLength');
|
|
256
|
-
|
|
257
|
-
// Internal helper to determine whether we should spend extensive checks against
|
|
258
|
-
// `ArrayBuffer` et al.
|
|
259
|
-
var isBufferLike = createSizePropertyCheck(getByteLength);
|
|
260
|
-
|
|
261
|
-
// Is a given value a typed array?
|
|
262
|
-
var typedArrayPattern = /\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;
|
|
263
|
-
function isTypedArray(obj) {
|
|
264
|
-
// `ArrayBuffer.isView` is the most future-proof, so use it when available.
|
|
265
|
-
// Otherwise, fall back on the above regular expression.
|
|
266
|
-
return nativeIsView ? (nativeIsView(obj) && !isDataView$1(obj)) :
|
|
267
|
-
isBufferLike(obj) && typedArrayPattern.test(toString.call(obj));
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
var isTypedArray$1 = supportsArrayBuffer ? isTypedArray : constant$1(false);
|
|
271
|
-
|
|
272
|
-
// Internal helper to obtain the `length` property of an object.
|
|
273
|
-
var getLength = shallowProperty('length');
|
|
274
|
-
|
|
275
|
-
// Internal helper to create a simple lookup structure.
|
|
276
|
-
// `collectNonEnumProps` used to depend on `_.contains`, but this led to
|
|
277
|
-
// circular imports. `emulatedSet` is a one-off solution that only works for
|
|
278
|
-
// arrays of strings.
|
|
279
|
-
function emulatedSet(keys) {
|
|
280
|
-
var hash = {};
|
|
281
|
-
for (var l = keys.length, i = 0; i < l; ++i) hash[keys[i]] = true;
|
|
282
|
-
return {
|
|
283
|
-
contains: function(key) { return hash[key] === true; },
|
|
284
|
-
push: function(key) {
|
|
285
|
-
hash[key] = true;
|
|
286
|
-
return keys.push(key);
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Internal helper. Checks `keys` for the presence of keys in IE < 9 that won't
|
|
292
|
-
// be iterated by `for key in ...` and thus missed. Extends `keys` in place if
|
|
293
|
-
// needed.
|
|
294
|
-
function collectNonEnumProps(obj, keys) {
|
|
295
|
-
keys = emulatedSet(keys);
|
|
296
|
-
var nonEnumIdx = nonEnumerableProps.length;
|
|
297
|
-
var constructor = obj.constructor;
|
|
298
|
-
var proto = (isFunction$1(constructor) && constructor.prototype) || ObjProto;
|
|
299
|
-
|
|
300
|
-
// Constructor is a special case.
|
|
301
|
-
var prop = 'constructor';
|
|
302
|
-
if (has$1(obj, prop) && !keys.contains(prop)) keys.push(prop);
|
|
303
|
-
|
|
304
|
-
while (nonEnumIdx--) {
|
|
305
|
-
prop = nonEnumerableProps[nonEnumIdx];
|
|
306
|
-
if (prop in obj && obj[prop] !== proto[prop] && !keys.contains(prop)) {
|
|
307
|
-
keys.push(prop);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Retrieve the names of an object's own properties.
|
|
313
|
-
// Delegates to **ECMAScript 5**'s native `Object.keys`.
|
|
314
|
-
function keys(obj) {
|
|
315
|
-
if (!isObject$1(obj)) return [];
|
|
316
|
-
if (nativeKeys) return nativeKeys(obj);
|
|
317
|
-
var keys = [];
|
|
318
|
-
for (var key in obj) if (has$1(obj, key)) keys.push(key);
|
|
319
|
-
// Ahem, IE < 9.
|
|
320
|
-
if (hasEnumBug) collectNonEnumProps(obj, keys);
|
|
321
|
-
return keys;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Is a given array, string, or object empty?
|
|
325
|
-
// An "empty" object has no enumerable own-properties.
|
|
326
|
-
function isEmpty(obj) {
|
|
327
|
-
if (obj == null) return true;
|
|
328
|
-
// Skip the more expensive `toString`-based type checks if `obj` has no
|
|
329
|
-
// `.length`.
|
|
330
|
-
var length = getLength(obj);
|
|
331
|
-
if (typeof length == 'number' && (
|
|
332
|
-
isArray(obj) || isString(obj) || isArguments$1(obj)
|
|
333
|
-
)) return length === 0;
|
|
334
|
-
return getLength(keys(obj)) === 0;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Returns whether an object has a given set of `key:value` pairs.
|
|
338
|
-
function isMatch(object, attrs) {
|
|
339
|
-
var _keys = keys(attrs), length = _keys.length;
|
|
340
|
-
if (object == null) return !length;
|
|
341
|
-
var obj = Object(object);
|
|
342
|
-
for (var i = 0; i < length; i++) {
|
|
343
|
-
var key = _keys[i];
|
|
344
|
-
if (attrs[key] !== obj[key] || !(key in obj)) return false;
|
|
345
|
-
}
|
|
346
|
-
return true;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// If Underscore is called as a function, it returns a wrapped object that can
|
|
350
|
-
// be used OO-style. This wrapper holds altered versions of all functions added
|
|
351
|
-
// through `_.mixin`. Wrapped objects may be chained.
|
|
352
|
-
function _$1(obj) {
|
|
353
|
-
if (obj instanceof _$1) return obj;
|
|
354
|
-
if (!(this instanceof _$1)) return new _$1(obj);
|
|
355
|
-
this._wrapped = obj;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
_$1.VERSION = VERSION;
|
|
359
|
-
|
|
360
|
-
// Extracts the result from a wrapped and chained object.
|
|
361
|
-
_$1.prototype.value = function() {
|
|
362
|
-
return this._wrapped;
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
// Provide unwrapping proxies for some methods used in engine operations
|
|
366
|
-
// such as arithmetic and JSON stringification.
|
|
367
|
-
_$1.prototype.valueOf = _$1.prototype.toJSON = _$1.prototype.value;
|
|
368
|
-
|
|
369
|
-
_$1.prototype.toString = function() {
|
|
370
|
-
return String(this._wrapped);
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
// Internal function to wrap or shallow-copy an ArrayBuffer,
|
|
374
|
-
// typed array or DataView to a new view, reusing the buffer.
|
|
375
|
-
function toBufferView(bufferSource) {
|
|
376
|
-
return new Uint8Array(
|
|
377
|
-
bufferSource.buffer || bufferSource,
|
|
378
|
-
bufferSource.byteOffset || 0,
|
|
379
|
-
getByteLength(bufferSource)
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// We use this string twice, so give it a name for minification.
|
|
384
|
-
var tagDataView = '[object DataView]';
|
|
385
|
-
|
|
386
|
-
// Internal recursive comparison function for `_.isEqual`.
|
|
387
|
-
function eq(a, b, aStack, bStack) {
|
|
388
|
-
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
|
389
|
-
// See the [Harmony `egal` proposal](https://wiki.ecmascript.org/doku.php?id=harmony:egal).
|
|
390
|
-
if (a === b) return a !== 0 || 1 / a === 1 / b;
|
|
391
|
-
// `null` or `undefined` only equal to itself (strict comparison).
|
|
392
|
-
if (a == null || b == null) return false;
|
|
393
|
-
// `NaN`s are equivalent, but non-reflexive.
|
|
394
|
-
if (a !== a) return b !== b;
|
|
395
|
-
// Exhaust primitive checks
|
|
396
|
-
var type = typeof a;
|
|
397
|
-
if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
|
|
398
|
-
return deepEq(a, b, aStack, bStack);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Internal recursive comparison function for `_.isEqual`.
|
|
402
|
-
function deepEq(a, b, aStack, bStack) {
|
|
403
|
-
// Unwrap any wrapped objects.
|
|
404
|
-
if (a instanceof _$1) a = a._wrapped;
|
|
405
|
-
if (b instanceof _$1) b = b._wrapped;
|
|
406
|
-
// Compare `[[Class]]` names.
|
|
407
|
-
var className = toString.call(a);
|
|
408
|
-
if (className !== toString.call(b)) return false;
|
|
409
|
-
// Work around a bug in IE 10 - Edge 13.
|
|
410
|
-
if (hasStringTagBug && className == '[object Object]' && isDataView$1(a)) {
|
|
411
|
-
if (!isDataView$1(b)) return false;
|
|
412
|
-
className = tagDataView;
|
|
413
|
-
}
|
|
414
|
-
switch (className) {
|
|
415
|
-
// These types are compared by value.
|
|
416
|
-
case '[object RegExp]':
|
|
417
|
-
// RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
|
|
418
|
-
case '[object String]':
|
|
419
|
-
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
|
420
|
-
// equivalent to `new String("5")`.
|
|
421
|
-
return '' + a === '' + b;
|
|
422
|
-
case '[object Number]':
|
|
423
|
-
// `NaN`s are equivalent, but non-reflexive.
|
|
424
|
-
// Object(NaN) is equivalent to NaN.
|
|
425
|
-
if (+a !== +a) return +b !== +b;
|
|
426
|
-
// An `egal` comparison is performed for other numeric values.
|
|
427
|
-
return +a === 0 ? 1 / +a === 1 / b : +a === +b;
|
|
428
|
-
case '[object Date]':
|
|
429
|
-
case '[object Boolean]':
|
|
430
|
-
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
|
431
|
-
// millisecond representations. Note that invalid dates with millisecond representations
|
|
432
|
-
// of `NaN` are not equivalent.
|
|
433
|
-
return +a === +b;
|
|
434
|
-
case '[object Symbol]':
|
|
435
|
-
return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);
|
|
436
|
-
case '[object ArrayBuffer]':
|
|
437
|
-
case tagDataView:
|
|
438
|
-
// Coerce to typed array so we can fall through.
|
|
439
|
-
return deepEq(toBufferView(a), toBufferView(b), aStack, bStack);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
var areArrays = className === '[object Array]';
|
|
443
|
-
if (!areArrays && isTypedArray$1(a)) {
|
|
444
|
-
var byteLength = getByteLength(a);
|
|
445
|
-
if (byteLength !== getByteLength(b)) return false;
|
|
446
|
-
if (a.buffer === b.buffer && a.byteOffset === b.byteOffset) return true;
|
|
447
|
-
areArrays = true;
|
|
448
|
-
}
|
|
449
|
-
if (!areArrays) {
|
|
450
|
-
if (typeof a != 'object' || typeof b != 'object') return false;
|
|
451
|
-
|
|
452
|
-
// Objects with different constructors are not equivalent, but `Object`s or `Array`s
|
|
453
|
-
// from different frames are.
|
|
454
|
-
var aCtor = a.constructor, bCtor = b.constructor;
|
|
455
|
-
if (aCtor !== bCtor && !(isFunction$1(aCtor) && aCtor instanceof aCtor &&
|
|
456
|
-
isFunction$1(bCtor) && bCtor instanceof bCtor)
|
|
457
|
-
&& ('constructor' in a && 'constructor' in b)) {
|
|
458
|
-
return false;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
|
462
|
-
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
|
463
|
-
|
|
464
|
-
// Initializing stack of traversed objects.
|
|
465
|
-
// It's done here since we only need them for objects and arrays comparison.
|
|
466
|
-
aStack = aStack || [];
|
|
467
|
-
bStack = bStack || [];
|
|
468
|
-
var length = aStack.length;
|
|
469
|
-
while (length--) {
|
|
470
|
-
// Linear search. Performance is inversely proportional to the number of
|
|
471
|
-
// unique nested structures.
|
|
472
|
-
if (aStack[length] === a) return bStack[length] === b;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Add the first object to the stack of traversed objects.
|
|
476
|
-
aStack.push(a);
|
|
477
|
-
bStack.push(b);
|
|
478
|
-
|
|
479
|
-
// Recursively compare objects and arrays.
|
|
480
|
-
if (areArrays) {
|
|
481
|
-
// Compare array lengths to determine if a deep comparison is necessary.
|
|
482
|
-
length = a.length;
|
|
483
|
-
if (length !== b.length) return false;
|
|
484
|
-
// Deep compare the contents, ignoring non-numeric properties.
|
|
485
|
-
while (length--) {
|
|
486
|
-
if (!eq(a[length], b[length], aStack, bStack)) return false;
|
|
487
|
-
}
|
|
488
|
-
} else {
|
|
489
|
-
// Deep compare objects.
|
|
490
|
-
var _keys = keys(a), key;
|
|
491
|
-
length = _keys.length;
|
|
492
|
-
// Ensure that both objects contain the same number of properties before comparing deep equality.
|
|
493
|
-
if (keys(b).length !== length) return false;
|
|
494
|
-
while (length--) {
|
|
495
|
-
// Deep compare each member
|
|
496
|
-
key = _keys[length];
|
|
497
|
-
if (!(has$1(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
// Remove the first object from the stack of traversed objects.
|
|
501
|
-
aStack.pop();
|
|
502
|
-
bStack.pop();
|
|
503
|
-
return true;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// Perform a deep comparison to check if two objects are equal.
|
|
507
|
-
function isEqual(a, b) {
|
|
508
|
-
return eq(a, b);
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// Retrieve all the enumerable property names of an object.
|
|
512
|
-
function allKeys(obj) {
|
|
513
|
-
if (!isObject$1(obj)) return [];
|
|
514
|
-
var keys = [];
|
|
515
|
-
for (var key in obj) keys.push(key);
|
|
516
|
-
// Ahem, IE < 9.
|
|
517
|
-
if (hasEnumBug) collectNonEnumProps(obj, keys);
|
|
518
|
-
return keys;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// Since the regular `Object.prototype.toString` type tests don't work for
|
|
522
|
-
// some types in IE 11, we use a fingerprinting heuristic instead, based
|
|
523
|
-
// on the methods. It's not great, but it's the best we got.
|
|
524
|
-
// The fingerprint method lists are defined below.
|
|
525
|
-
function ie11fingerprint(methods) {
|
|
526
|
-
var length = getLength(methods);
|
|
527
|
-
return function(obj) {
|
|
528
|
-
if (obj == null) return false;
|
|
529
|
-
// `Map`, `WeakMap` and `Set` have no enumerable keys.
|
|
530
|
-
var keys = allKeys(obj);
|
|
531
|
-
if (getLength(keys)) return false;
|
|
532
|
-
for (var i = 0; i < length; i++) {
|
|
533
|
-
if (!isFunction$1(obj[methods[i]])) return false;
|
|
534
|
-
}
|
|
535
|
-
// If we are testing against `WeakMap`, we need to ensure that
|
|
536
|
-
// `obj` doesn't have a `forEach` method in order to distinguish
|
|
537
|
-
// it from a regular `Map`.
|
|
538
|
-
return methods !== weakMapMethods || !isFunction$1(obj[forEachName]);
|
|
539
|
-
};
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
// In the interest of compact minification, we write
|
|
543
|
-
// each string in the fingerprints only once.
|
|
544
|
-
var forEachName = 'forEach',
|
|
545
|
-
hasName = 'has',
|
|
546
|
-
commonInit = ['clear', 'delete'],
|
|
547
|
-
mapTail = ['get', hasName, 'set'];
|
|
548
|
-
|
|
549
|
-
// `Map`, `WeakMap` and `Set` each have slightly different
|
|
550
|
-
// combinations of the above sublists.
|
|
551
|
-
var mapMethods = commonInit.concat(forEachName, mapTail),
|
|
552
|
-
weakMapMethods = commonInit.concat(mapTail),
|
|
553
|
-
setMethods = ['add'].concat(commonInit, forEachName, hasName);
|
|
554
|
-
|
|
555
|
-
var isMap = isIE11 ? ie11fingerprint(mapMethods) : tagTester('Map');
|
|
556
|
-
|
|
557
|
-
var isWeakMap = isIE11 ? ie11fingerprint(weakMapMethods) : tagTester('WeakMap');
|
|
558
|
-
|
|
559
|
-
var isSet = isIE11 ? ie11fingerprint(setMethods) : tagTester('Set');
|
|
560
|
-
|
|
561
|
-
var isWeakSet = tagTester('WeakSet');
|
|
562
|
-
|
|
563
|
-
// Retrieve the values of an object's properties.
|
|
564
|
-
function values(obj) {
|
|
565
|
-
var _keys = keys(obj);
|
|
566
|
-
var length = _keys.length;
|
|
567
|
-
var values = Array(length);
|
|
568
|
-
for (var i = 0; i < length; i++) {
|
|
569
|
-
values[i] = obj[_keys[i]];
|
|
570
|
-
}
|
|
571
|
-
return values;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// Convert an object into a list of `[key, value]` pairs.
|
|
575
|
-
// The opposite of `_.object` with one argument.
|
|
576
|
-
function pairs(obj) {
|
|
577
|
-
var _keys = keys(obj);
|
|
578
|
-
var length = _keys.length;
|
|
579
|
-
var pairs = Array(length);
|
|
580
|
-
for (var i = 0; i < length; i++) {
|
|
581
|
-
pairs[i] = [_keys[i], obj[_keys[i]]];
|
|
582
|
-
}
|
|
583
|
-
return pairs;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// Invert the keys and values of an object. The values must be serializable.
|
|
587
|
-
function invert(obj) {
|
|
588
|
-
var result = {};
|
|
589
|
-
var _keys = keys(obj);
|
|
590
|
-
for (var i = 0, length = _keys.length; i < length; i++) {
|
|
591
|
-
result[obj[_keys[i]]] = _keys[i];
|
|
592
|
-
}
|
|
593
|
-
return result;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// Return a sorted list of the function names available on the object.
|
|
597
|
-
function functions(obj) {
|
|
598
|
-
var names = [];
|
|
599
|
-
for (var key in obj) {
|
|
600
|
-
if (isFunction$1(obj[key])) names.push(key);
|
|
601
|
-
}
|
|
602
|
-
return names.sort();
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// An internal function for creating assigner functions.
|
|
606
|
-
function createAssigner(keysFunc, defaults) {
|
|
607
|
-
return function(obj) {
|
|
608
|
-
var length = arguments.length;
|
|
609
|
-
if (defaults) obj = Object(obj);
|
|
610
|
-
if (length < 2 || obj == null) return obj;
|
|
611
|
-
for (var index = 1; index < length; index++) {
|
|
612
|
-
var source = arguments[index],
|
|
613
|
-
keys = keysFunc(source),
|
|
614
|
-
l = keys.length;
|
|
615
|
-
for (var i = 0; i < l; i++) {
|
|
616
|
-
var key = keys[i];
|
|
617
|
-
if (!defaults || obj[key] === void 0) obj[key] = source[key];
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
return obj;
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
// Extend a given object with all the properties in passed-in object(s).
|
|
625
|
-
var extend = createAssigner(allKeys);
|
|
626
|
-
|
|
627
|
-
// Assigns a given object with all the own properties in the passed-in
|
|
628
|
-
// object(s).
|
|
629
|
-
// (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
|
|
630
|
-
var extendOwn = createAssigner(keys);
|
|
631
|
-
|
|
632
|
-
// Fill in a given object with default properties.
|
|
633
|
-
var defaults = createAssigner(allKeys, true);
|
|
634
|
-
|
|
635
|
-
// Create a naked function reference for surrogate-prototype-swapping.
|
|
636
|
-
function ctor() {
|
|
637
|
-
return function(){};
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
// An internal function for creating a new object that inherits from another.
|
|
641
|
-
function baseCreate(prototype) {
|
|
642
|
-
if (!isObject$1(prototype)) return {};
|
|
643
|
-
if (nativeCreate) return nativeCreate(prototype);
|
|
644
|
-
var Ctor = ctor();
|
|
645
|
-
Ctor.prototype = prototype;
|
|
646
|
-
var result = new Ctor;
|
|
647
|
-
Ctor.prototype = null;
|
|
648
|
-
return result;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// Creates an object that inherits from the given prototype object.
|
|
652
|
-
// If additional properties are provided then they will be added to the
|
|
653
|
-
// created object.
|
|
654
|
-
function create(prototype, props) {
|
|
655
|
-
var result = baseCreate(prototype);
|
|
656
|
-
if (props) extendOwn(result, props);
|
|
657
|
-
return result;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
// Create a (shallow-cloned) duplicate of an object.
|
|
661
|
-
function clone(obj) {
|
|
662
|
-
if (!isObject$1(obj)) return obj;
|
|
663
|
-
return isArray(obj) ? obj.slice() : extend({}, obj);
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
// Invokes `interceptor` with the `obj` and then returns `obj`.
|
|
667
|
-
// The primary purpose of this method is to "tap into" a method chain, in
|
|
668
|
-
// order to perform operations on intermediate results within the chain.
|
|
669
|
-
function tap(obj, interceptor) {
|
|
670
|
-
interceptor(obj);
|
|
671
|
-
return obj;
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
// Normalize a (deep) property `path` to array.
|
|
675
|
-
// Like `_.iteratee`, this function can be customized.
|
|
676
|
-
function toPath$1(path) {
|
|
677
|
-
return isArray(path) ? path : [path];
|
|
678
|
-
}
|
|
679
|
-
_$1.toPath = toPath$1;
|
|
680
|
-
|
|
681
|
-
// Internal wrapper for `_.toPath` to enable minification.
|
|
682
|
-
// Similar to `cb` for `_.iteratee`.
|
|
683
|
-
function toPath(path) {
|
|
684
|
-
return _$1.toPath(path);
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// Internal function to obtain a nested property in `obj` along `path`.
|
|
688
|
-
function deepGet(obj, path) {
|
|
689
|
-
var length = path.length;
|
|
690
|
-
for (var i = 0; i < length; i++) {
|
|
691
|
-
if (obj == null) return void 0;
|
|
692
|
-
obj = obj[path[i]];
|
|
693
|
-
}
|
|
694
|
-
return length ? obj : void 0;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
// Get the value of the (deep) property on `path` from `object`.
|
|
698
|
-
// If any property in `path` does not exist or if the value is
|
|
699
|
-
// `undefined`, return `defaultValue` instead.
|
|
700
|
-
// The `path` is normalized through `_.toPath`.
|
|
701
|
-
function get(object, path, defaultValue) {
|
|
702
|
-
var value = deepGet(object, toPath(path));
|
|
703
|
-
return isUndefined(value) ? defaultValue : value;
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
// Shortcut function for checking if an object has a given property directly on
|
|
707
|
-
// itself (in other words, not on a prototype). Unlike the internal `has`
|
|
708
|
-
// function, this public version can also traverse nested properties.
|
|
709
|
-
function has(obj, path) {
|
|
710
|
-
path = toPath(path);
|
|
711
|
-
var length = path.length;
|
|
712
|
-
for (var i = 0; i < length; i++) {
|
|
713
|
-
var key = path[i];
|
|
714
|
-
if (!has$1(obj, key)) return false;
|
|
715
|
-
obj = obj[key];
|
|
716
|
-
}
|
|
717
|
-
return !!length;
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
// Keep the identity function around for default iteratees.
|
|
721
|
-
function identity(value) {
|
|
722
|
-
return value;
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
// Returns a predicate for checking whether an object has a given set of
|
|
726
|
-
// `key:value` pairs.
|
|
727
|
-
function matcher(attrs) {
|
|
728
|
-
attrs = extendOwn({}, attrs);
|
|
729
|
-
return function(obj) {
|
|
730
|
-
return isMatch(obj, attrs);
|
|
731
|
-
};
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
// Creates a function that, when passed an object, will traverse that object’s
|
|
735
|
-
// properties down the given `path`, specified as an array of keys or indices.
|
|
736
|
-
function property(path) {
|
|
737
|
-
path = toPath(path);
|
|
738
|
-
return function(obj) {
|
|
739
|
-
return deepGet(obj, path);
|
|
740
|
-
};
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
// Internal function that returns an efficient (for current engines) version
|
|
744
|
-
// of the passed-in callback, to be repeatedly applied in other Underscore
|
|
745
|
-
// functions.
|
|
746
|
-
function optimizeCb(func, context, argCount) {
|
|
747
|
-
if (context === void 0) return func;
|
|
748
|
-
switch (argCount == null ? 3 : argCount) {
|
|
749
|
-
case 1: return function(value) {
|
|
750
|
-
return func.call(context, value);
|
|
751
|
-
};
|
|
752
|
-
// The 2-argument case is omitted because we’re not using it.
|
|
753
|
-
case 3: return function(value, index, collection) {
|
|
754
|
-
return func.call(context, value, index, collection);
|
|
755
|
-
};
|
|
756
|
-
case 4: return function(accumulator, value, index, collection) {
|
|
757
|
-
return func.call(context, accumulator, value, index, collection);
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
return function() {
|
|
761
|
-
return func.apply(context, arguments);
|
|
762
|
-
};
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
// An internal function to generate callbacks that can be applied to each
|
|
766
|
-
// element in a collection, returning the desired result — either `_.identity`,
|
|
767
|
-
// an arbitrary callback, a property matcher, or a property accessor.
|
|
768
|
-
function baseIteratee(value, context, argCount) {
|
|
769
|
-
if (value == null) return identity;
|
|
770
|
-
if (isFunction$1(value)) return optimizeCb(value, context, argCount);
|
|
771
|
-
if (isObject$1(value) && !isArray(value)) return matcher(value);
|
|
772
|
-
return property(value);
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
// External wrapper for our callback generator. Users may customize
|
|
776
|
-
// `_.iteratee` if they want additional predicate/iteratee shorthand styles.
|
|
777
|
-
// This abstraction hides the internal-only `argCount` argument.
|
|
778
|
-
function iteratee(value, context) {
|
|
779
|
-
return baseIteratee(value, context, Infinity);
|
|
780
|
-
}
|
|
781
|
-
_$1.iteratee = iteratee;
|
|
782
|
-
|
|
783
|
-
// The function we call internally to generate a callback. It invokes
|
|
784
|
-
// `_.iteratee` if overridden, otherwise `baseIteratee`.
|
|
785
|
-
function cb(value, context, argCount) {
|
|
786
|
-
if (_$1.iteratee !== iteratee) return _$1.iteratee(value, context);
|
|
787
|
-
return baseIteratee(value, context, argCount);
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// Returns the results of applying the `iteratee` to each element of `obj`.
|
|
791
|
-
// In contrast to `_.map` it returns an object.
|
|
792
|
-
function mapObject$1(obj, iteratee, context) {
|
|
793
|
-
iteratee = cb(iteratee, context);
|
|
794
|
-
var _keys = keys(obj),
|
|
795
|
-
length = _keys.length,
|
|
796
|
-
results = {};
|
|
797
|
-
for (var index = 0; index < length; index++) {
|
|
798
|
-
var currentKey = _keys[index];
|
|
799
|
-
results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
|
|
800
|
-
}
|
|
801
|
-
return results;
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
// Predicate-generating function. Often useful outside of Underscore.
|
|
805
|
-
function noop(){}
|
|
806
|
-
|
|
807
|
-
// Generates a function for a given object that returns a given property.
|
|
808
|
-
function propertyOf(obj) {
|
|
809
|
-
if (obj == null) return noop;
|
|
810
|
-
return function(path) {
|
|
811
|
-
return get(obj, path);
|
|
812
|
-
};
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
// Run a function **n** times.
|
|
816
|
-
function times(n, iteratee, context) {
|
|
817
|
-
var accum = Array(Math.max(0, n));
|
|
818
|
-
iteratee = optimizeCb(iteratee, context, 1);
|
|
819
|
-
for (var i = 0; i < n; i++) accum[i] = iteratee(i);
|
|
820
|
-
return accum;
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
// Return a random integer between `min` and `max` (inclusive).
|
|
824
|
-
function random(min, max) {
|
|
825
|
-
if (max == null) {
|
|
826
|
-
max = min;
|
|
827
|
-
min = 0;
|
|
828
|
-
}
|
|
829
|
-
return min + Math.floor(Math.random() * (max - min + 1));
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
// A (possibly faster) way to get the current timestamp as an integer.
|
|
833
|
-
var now = Date.now || function() {
|
|
834
|
-
return new Date().getTime();
|
|
835
|
-
};
|
|
836
|
-
|
|
837
|
-
// Internal helper to generate functions for escaping and unescaping strings
|
|
838
|
-
// to/from HTML interpolation.
|
|
839
|
-
function createEscaper(map) {
|
|
840
|
-
var escaper = function(match) {
|
|
841
|
-
return map[match];
|
|
842
|
-
};
|
|
843
|
-
// Regexes for identifying a key that needs to be escaped.
|
|
844
|
-
var source = '(?:' + keys(map).join('|') + ')';
|
|
845
|
-
var testRegexp = RegExp(source);
|
|
846
|
-
var replaceRegexp = RegExp(source, 'g');
|
|
847
|
-
return function(string) {
|
|
848
|
-
string = string == null ? '' : '' + string;
|
|
849
|
-
return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
|
|
850
|
-
};
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
// Internal list of HTML entities for escaping.
|
|
854
|
-
var escapeMap = {
|
|
855
|
-
'&': '&',
|
|
856
|
-
'<': '<',
|
|
857
|
-
'>': '>',
|
|
858
|
-
'"': '"',
|
|
859
|
-
"'": ''',
|
|
860
|
-
'`': '`'
|
|
861
|
-
};
|
|
862
|
-
|
|
863
|
-
// Function for escaping strings to HTML interpolation.
|
|
864
|
-
var escape = createEscaper(escapeMap);
|
|
865
|
-
|
|
866
|
-
// Internal list of HTML entities for unescaping.
|
|
867
|
-
var unescapeMap = invert(escapeMap);
|
|
868
|
-
|
|
869
|
-
// Function for unescaping strings from HTML interpolation.
|
|
870
|
-
var unescape = createEscaper(unescapeMap);
|
|
871
|
-
|
|
872
|
-
// By default, Underscore uses ERB-style template delimiters. Change the
|
|
873
|
-
// following template settings to use alternative delimiters.
|
|
874
|
-
var templateSettings = _$1.templateSettings = {
|
|
875
|
-
evaluate: /<%([\s\S]+?)%>/g,
|
|
876
|
-
interpolate: /<%=([\s\S]+?)%>/g,
|
|
877
|
-
escape: /<%-([\s\S]+?)%>/g
|
|
878
|
-
};
|
|
879
|
-
|
|
880
|
-
// When customizing `_.templateSettings`, if you don't want to define an
|
|
881
|
-
// interpolation, evaluation or escaping regex, we need one that is
|
|
882
|
-
// guaranteed not to match.
|
|
883
|
-
var noMatch = /(.)^/;
|
|
884
|
-
|
|
885
|
-
// Certain characters need to be escaped so that they can be put into a
|
|
886
|
-
// string literal.
|
|
887
|
-
var escapes = {
|
|
888
|
-
"'": "'",
|
|
889
|
-
'\\': '\\',
|
|
890
|
-
'\r': 'r',
|
|
891
|
-
'\n': 'n',
|
|
892
|
-
'\u2028': 'u2028',
|
|
893
|
-
'\u2029': 'u2029'
|
|
894
|
-
};
|
|
895
|
-
|
|
896
|
-
var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g;
|
|
897
|
-
|
|
898
|
-
function escapeChar(match) {
|
|
899
|
-
return '\\' + escapes[match];
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
// In order to prevent third-party code injection through
|
|
903
|
-
// `_.templateSettings.variable`, we test it against the following regular
|
|
904
|
-
// expression. It is intentionally a bit more liberal than just matching valid
|
|
905
|
-
// identifiers, but still prevents possible loopholes through defaults or
|
|
906
|
-
// destructuring assignment.
|
|
907
|
-
var bareIdentifier = /^\s*(\w|\$)+\s*$/;
|
|
908
|
-
|
|
909
|
-
// JavaScript micro-templating, similar to John Resig's implementation.
|
|
910
|
-
// Underscore templating handles arbitrary delimiters, preserves whitespace,
|
|
911
|
-
// and correctly escapes quotes within interpolated code.
|
|
912
|
-
// NB: `oldSettings` only exists for backwards compatibility.
|
|
913
|
-
function template(text, settings, oldSettings) {
|
|
914
|
-
if (!settings && oldSettings) settings = oldSettings;
|
|
915
|
-
settings = defaults({}, settings, _$1.templateSettings);
|
|
916
|
-
|
|
917
|
-
// Combine delimiters into one regular expression via alternation.
|
|
918
|
-
var matcher = RegExp([
|
|
919
|
-
(settings.escape || noMatch).source,
|
|
920
|
-
(settings.interpolate || noMatch).source,
|
|
921
|
-
(settings.evaluate || noMatch).source
|
|
922
|
-
].join('|') + '|$', 'g');
|
|
923
|
-
|
|
924
|
-
// Compile the template source, escaping string literals appropriately.
|
|
925
|
-
var index = 0;
|
|
926
|
-
var source = "__p+='";
|
|
927
|
-
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
|
|
928
|
-
source += text.slice(index, offset).replace(escapeRegExp, escapeChar);
|
|
929
|
-
index = offset + match.length;
|
|
930
|
-
|
|
931
|
-
if (escape) {
|
|
932
|
-
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
|
|
933
|
-
} else if (interpolate) {
|
|
934
|
-
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
|
|
935
|
-
} else if (evaluate) {
|
|
936
|
-
source += "';\n" + evaluate + "\n__p+='";
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
// Adobe VMs need the match returned to produce the correct offset.
|
|
940
|
-
return match;
|
|
941
|
-
});
|
|
942
|
-
source += "';\n";
|
|
943
|
-
|
|
944
|
-
var argument = settings.variable;
|
|
945
|
-
if (argument) {
|
|
946
|
-
// Insure against third-party code injection. (CVE-2021-23358)
|
|
947
|
-
if (!bareIdentifier.test(argument)) throw new Error(
|
|
948
|
-
'variable is not a bare identifier: ' + argument
|
|
949
|
-
);
|
|
950
|
-
} else {
|
|
951
|
-
// If a variable is not specified, place data values in local scope.
|
|
952
|
-
source = 'with(obj||{}){\n' + source + '}\n';
|
|
953
|
-
argument = 'obj';
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
source = "var __t,__p='',__j=Array.prototype.join," +
|
|
957
|
-
"print=function(){__p+=__j.call(arguments,'');};\n" +
|
|
958
|
-
source + 'return __p;\n';
|
|
959
|
-
|
|
960
|
-
var render;
|
|
961
|
-
try {
|
|
962
|
-
render = new Function(argument, '_', source);
|
|
963
|
-
} catch (e) {
|
|
964
|
-
e.source = source;
|
|
965
|
-
throw e;
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
var template = function(data) {
|
|
969
|
-
return render.call(this, data, _$1);
|
|
970
|
-
};
|
|
971
|
-
|
|
972
|
-
// Provide the compiled source as a convenience for precompilation.
|
|
973
|
-
template.source = 'function(' + argument + '){\n' + source + '}';
|
|
974
|
-
|
|
975
|
-
return template;
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
// Traverses the children of `obj` along `path`. If a child is a function, it
|
|
979
|
-
// is invoked with its parent as context. Returns the value of the final
|
|
980
|
-
// child, or `fallback` if any child is undefined.
|
|
981
|
-
function result(obj, path, fallback) {
|
|
982
|
-
path = toPath(path);
|
|
983
|
-
var length = path.length;
|
|
984
|
-
if (!length) {
|
|
985
|
-
return isFunction$1(fallback) ? fallback.call(obj) : fallback;
|
|
986
|
-
}
|
|
987
|
-
for (var i = 0; i < length; i++) {
|
|
988
|
-
var prop = obj == null ? void 0 : obj[path[i]];
|
|
989
|
-
if (prop === void 0) {
|
|
990
|
-
prop = fallback;
|
|
991
|
-
i = length; // Ensure we don't continue iterating.
|
|
992
|
-
}
|
|
993
|
-
obj = isFunction$1(prop) ? prop.call(obj) : prop;
|
|
994
|
-
}
|
|
995
|
-
return obj;
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
// Generate a unique integer id (unique within the entire client session).
|
|
999
|
-
// Useful for temporary DOM ids.
|
|
1000
|
-
var idCounter = 0;
|
|
1001
|
-
function uniqueId(prefix) {
|
|
1002
|
-
var id = ++idCounter + '';
|
|
1003
|
-
return prefix ? prefix + id : id;
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
// Start chaining a wrapped Underscore object.
|
|
1007
|
-
function chain(obj) {
|
|
1008
|
-
var instance = _$1(obj);
|
|
1009
|
-
instance._chain = true;
|
|
1010
|
-
return instance;
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
// Internal function to execute `sourceFunc` bound to `context` with optional
|
|
1014
|
-
// `args`. Determines whether to execute a function as a constructor or as a
|
|
1015
|
-
// normal function.
|
|
1016
|
-
function executeBound(sourceFunc, boundFunc, context, callingContext, args) {
|
|
1017
|
-
if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
|
|
1018
|
-
var self = baseCreate(sourceFunc.prototype);
|
|
1019
|
-
var result = sourceFunc.apply(self, args);
|
|
1020
|
-
if (isObject$1(result)) return result;
|
|
1021
|
-
return self;
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
// Partially apply a function by creating a version that has had some of its
|
|
1025
|
-
// arguments pre-filled, without changing its dynamic `this` context. `_` acts
|
|
1026
|
-
// as a placeholder by default, allowing any combination of arguments to be
|
|
1027
|
-
// pre-filled. Set `_.partial.placeholder` for a custom placeholder argument.
|
|
1028
|
-
var partial = restArguments(function(func, boundArgs) {
|
|
1029
|
-
var placeholder = partial.placeholder;
|
|
1030
|
-
var bound = function() {
|
|
1031
|
-
var position = 0, length = boundArgs.length;
|
|
1032
|
-
var args = Array(length);
|
|
1033
|
-
for (var i = 0; i < length; i++) {
|
|
1034
|
-
args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i];
|
|
1035
|
-
}
|
|
1036
|
-
while (position < arguments.length) args.push(arguments[position++]);
|
|
1037
|
-
return executeBound(func, bound, this, this, args);
|
|
1038
|
-
};
|
|
1039
|
-
return bound;
|
|
1040
|
-
});
|
|
1041
|
-
|
|
1042
|
-
partial.placeholder = _$1;
|
|
1043
|
-
|
|
1044
|
-
// Create a function bound to a given object (assigning `this`, and arguments,
|
|
1045
|
-
// optionally).
|
|
1046
|
-
var bind = restArguments(function(func, context, args) {
|
|
1047
|
-
if (!isFunction$1(func)) throw new TypeError('Bind must be called on a function');
|
|
1048
|
-
var bound = restArguments(function(callArgs) {
|
|
1049
|
-
return executeBound(func, bound, context, this, args.concat(callArgs));
|
|
1050
|
-
});
|
|
1051
|
-
return bound;
|
|
1052
|
-
});
|
|
1053
|
-
|
|
1054
|
-
// Internal helper for collection methods to determine whether a collection
|
|
1055
|
-
// should be iterated as an array or as an object.
|
|
1056
|
-
// Related: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
|
|
1057
|
-
// Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
|
|
1058
|
-
var isArrayLike = createSizePropertyCheck(getLength);
|
|
1059
|
-
|
|
1060
|
-
// Internal implementation of a recursive `flatten` function.
|
|
1061
|
-
function flatten$1(input, depth, strict, output) {
|
|
1062
|
-
output = output || [];
|
|
1063
|
-
if (!depth && depth !== 0) {
|
|
1064
|
-
depth = Infinity;
|
|
1065
|
-
} else if (depth <= 0) {
|
|
1066
|
-
return output.concat(input);
|
|
1067
|
-
}
|
|
1068
|
-
var idx = output.length;
|
|
1069
|
-
for (var i = 0, length = getLength(input); i < length; i++) {
|
|
1070
|
-
var value = input[i];
|
|
1071
|
-
if (isArrayLike(value) && (isArray(value) || isArguments$1(value))) {
|
|
1072
|
-
// Flatten current level of array or arguments object.
|
|
1073
|
-
if (depth > 1) {
|
|
1074
|
-
flatten$1(value, depth - 1, strict, output);
|
|
1075
|
-
idx = output.length;
|
|
1076
|
-
} else {
|
|
1077
|
-
var j = 0, len = value.length;
|
|
1078
|
-
while (j < len) output[idx++] = value[j++];
|
|
1079
|
-
}
|
|
1080
|
-
} else if (!strict) {
|
|
1081
|
-
output[idx++] = value;
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
return output;
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
// Bind a number of an object's methods to that object. Remaining arguments
|
|
1088
|
-
// are the method names to be bound. Useful for ensuring that all callbacks
|
|
1089
|
-
// defined on an object belong to it.
|
|
1090
|
-
var bindAll = restArguments(function(obj, keys) {
|
|
1091
|
-
keys = flatten$1(keys, false, false);
|
|
1092
|
-
var index = keys.length;
|
|
1093
|
-
if (index < 1) throw new Error('bindAll must be passed function names');
|
|
1094
|
-
while (index--) {
|
|
1095
|
-
var key = keys[index];
|
|
1096
|
-
obj[key] = bind(obj[key], obj);
|
|
1097
|
-
}
|
|
1098
|
-
return obj;
|
|
1099
|
-
});
|
|
1100
|
-
|
|
1101
|
-
// Memoize an expensive function by storing its results.
|
|
1102
|
-
function memoize(func, hasher) {
|
|
1103
|
-
var memoize = function(key) {
|
|
1104
|
-
var cache = memoize.cache;
|
|
1105
|
-
var address = '' + (hasher ? hasher.apply(this, arguments) : key);
|
|
1106
|
-
if (!has$1(cache, address)) cache[address] = func.apply(this, arguments);
|
|
1107
|
-
return cache[address];
|
|
1108
|
-
};
|
|
1109
|
-
memoize.cache = {};
|
|
1110
|
-
return memoize;
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
// Delays a function for the given number of milliseconds, and then calls
|
|
1114
|
-
// it with the arguments supplied.
|
|
1115
|
-
var delay = restArguments(function(func, wait, args) {
|
|
1116
|
-
return setTimeout(function() {
|
|
1117
|
-
return func.apply(null, args);
|
|
1118
|
-
}, wait);
|
|
1119
|
-
});
|
|
1120
|
-
|
|
1121
|
-
// Defers a function, scheduling it to run after the current call stack has
|
|
1122
|
-
// cleared.
|
|
1123
|
-
var defer = partial(delay, _$1, 1);
|
|
1124
|
-
|
|
1125
|
-
// Returns a function, that, when invoked, will only be triggered at most once
|
|
1126
|
-
// during a given window of time. Normally, the throttled function will run
|
|
1127
|
-
// as much as it can, without ever going more than once per `wait` duration;
|
|
1128
|
-
// but if you'd like to disable the execution on the leading edge, pass
|
|
1129
|
-
// `{leading: false}`. To disable execution on the trailing edge, ditto.
|
|
1130
|
-
function throttle(func, wait, options) {
|
|
1131
|
-
var timeout, context, args, result;
|
|
1132
|
-
var previous = 0;
|
|
1133
|
-
if (!options) options = {};
|
|
1134
|
-
|
|
1135
|
-
var later = function() {
|
|
1136
|
-
previous = options.leading === false ? 0 : now();
|
|
1137
|
-
timeout = null;
|
|
1138
|
-
result = func.apply(context, args);
|
|
1139
|
-
if (!timeout) context = args = null;
|
|
1140
|
-
};
|
|
1141
|
-
|
|
1142
|
-
var throttled = function() {
|
|
1143
|
-
var _now = now();
|
|
1144
|
-
if (!previous && options.leading === false) previous = _now;
|
|
1145
|
-
var remaining = wait - (_now - previous);
|
|
1146
|
-
context = this;
|
|
1147
|
-
args = arguments;
|
|
1148
|
-
if (remaining <= 0 || remaining > wait) {
|
|
1149
|
-
if (timeout) {
|
|
1150
|
-
clearTimeout(timeout);
|
|
1151
|
-
timeout = null;
|
|
1152
|
-
}
|
|
1153
|
-
previous = _now;
|
|
1154
|
-
result = func.apply(context, args);
|
|
1155
|
-
if (!timeout) context = args = null;
|
|
1156
|
-
} else if (!timeout && options.trailing !== false) {
|
|
1157
|
-
timeout = setTimeout(later, remaining);
|
|
1158
|
-
}
|
|
1159
|
-
return result;
|
|
1160
|
-
};
|
|
1161
|
-
|
|
1162
|
-
throttled.cancel = function() {
|
|
1163
|
-
clearTimeout(timeout);
|
|
1164
|
-
previous = 0;
|
|
1165
|
-
timeout = context = args = null;
|
|
1166
|
-
};
|
|
1167
|
-
|
|
1168
|
-
return throttled;
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
// When a sequence of calls of the returned function ends, the argument
|
|
1172
|
-
// function is triggered. The end of a sequence is defined by the `wait`
|
|
1173
|
-
// parameter. If `immediate` is passed, the argument function will be
|
|
1174
|
-
// triggered at the beginning of the sequence instead of at the end.
|
|
1175
|
-
function debounce(func, wait, immediate) {
|
|
1176
|
-
var timeout, previous, args, result, context;
|
|
1177
|
-
|
|
1178
|
-
var later = function() {
|
|
1179
|
-
var passed = now() - previous;
|
|
1180
|
-
if (wait > passed) {
|
|
1181
|
-
timeout = setTimeout(later, wait - passed);
|
|
1182
|
-
} else {
|
|
1183
|
-
timeout = null;
|
|
1184
|
-
if (!immediate) result = func.apply(context, args);
|
|
1185
|
-
// This check is needed because `func` can recursively invoke `debounced`.
|
|
1186
|
-
if (!timeout) args = context = null;
|
|
1187
|
-
}
|
|
1188
|
-
};
|
|
1189
|
-
|
|
1190
|
-
var debounced = restArguments(function(_args) {
|
|
1191
|
-
context = this;
|
|
1192
|
-
args = _args;
|
|
1193
|
-
previous = now();
|
|
1194
|
-
if (!timeout) {
|
|
1195
|
-
timeout = setTimeout(later, wait);
|
|
1196
|
-
if (immediate) result = func.apply(context, args);
|
|
1197
|
-
}
|
|
1198
|
-
return result;
|
|
1199
|
-
});
|
|
1200
|
-
|
|
1201
|
-
debounced.cancel = function() {
|
|
1202
|
-
clearTimeout(timeout);
|
|
1203
|
-
timeout = args = context = null;
|
|
1204
|
-
};
|
|
1205
|
-
|
|
1206
|
-
return debounced;
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
// Returns the first function passed as an argument to the second,
|
|
1210
|
-
// allowing you to adjust arguments, run code before and after, and
|
|
1211
|
-
// conditionally execute the original function.
|
|
1212
|
-
function wrap(func, wrapper) {
|
|
1213
|
-
return partial(wrapper, func);
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
// Returns a negated version of the passed-in predicate.
|
|
1217
|
-
function negate(predicate) {
|
|
1218
|
-
return function() {
|
|
1219
|
-
return !predicate.apply(this, arguments);
|
|
1220
|
-
};
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
// Returns a function that is the composition of a list of functions, each
|
|
1224
|
-
// consuming the return value of the function that follows.
|
|
1225
|
-
function compose() {
|
|
1226
|
-
var args = arguments;
|
|
1227
|
-
var start = args.length - 1;
|
|
1228
|
-
return function() {
|
|
1229
|
-
var i = start;
|
|
1230
|
-
var result = args[start].apply(this, arguments);
|
|
1231
|
-
while (i--) result = args[i].call(this, result);
|
|
1232
|
-
return result;
|
|
1233
|
-
};
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
// Returns a function that will only be executed on and after the Nth call.
|
|
1237
|
-
function after(times, func) {
|
|
1238
|
-
return function() {
|
|
1239
|
-
if (--times < 1) {
|
|
1240
|
-
return func.apply(this, arguments);
|
|
1241
|
-
}
|
|
1242
|
-
};
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
// Returns a function that will only be executed up to (but not including) the
|
|
1246
|
-
// Nth call.
|
|
1247
|
-
function before(times, func) {
|
|
1248
|
-
var memo;
|
|
1249
|
-
return function() {
|
|
1250
|
-
if (--times > 0) {
|
|
1251
|
-
memo = func.apply(this, arguments);
|
|
1252
|
-
}
|
|
1253
|
-
if (times <= 1) func = null;
|
|
1254
|
-
return memo;
|
|
1255
|
-
};
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
// Returns a function that will be executed at most one time, no matter how
|
|
1259
|
-
// often you call it. Useful for lazy initialization.
|
|
1260
|
-
var once = partial(before, 2);
|
|
1261
|
-
|
|
1262
|
-
// Returns the first key on an object that passes a truth test.
|
|
1263
|
-
function findKey(obj, predicate, context) {
|
|
1264
|
-
predicate = cb(predicate, context);
|
|
1265
|
-
var _keys = keys(obj), key;
|
|
1266
|
-
for (var i = 0, length = _keys.length; i < length; i++) {
|
|
1267
|
-
key = _keys[i];
|
|
1268
|
-
if (predicate(obj[key], key, obj)) return key;
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
// Internal function to generate `_.findIndex` and `_.findLastIndex`.
|
|
1273
|
-
function createPredicateIndexFinder(dir) {
|
|
1274
|
-
return function(array, predicate, context) {
|
|
1275
|
-
predicate = cb(predicate, context);
|
|
1276
|
-
var length = getLength(array);
|
|
1277
|
-
var index = dir > 0 ? 0 : length - 1;
|
|
1278
|
-
for (; index >= 0 && index < length; index += dir) {
|
|
1279
|
-
if (predicate(array[index], index, array)) return index;
|
|
1280
|
-
}
|
|
1281
|
-
return -1;
|
|
1282
|
-
};
|
|
1283
|
-
}
|
|
1284
|
-
|
|
1285
|
-
// Returns the first index on an array-like that passes a truth test.
|
|
1286
|
-
var findIndex = createPredicateIndexFinder(1);
|
|
1287
|
-
|
|
1288
|
-
// Returns the last index on an array-like that passes a truth test.
|
|
1289
|
-
var findLastIndex = createPredicateIndexFinder(-1);
|
|
1290
|
-
|
|
1291
|
-
// Use a comparator function to figure out the smallest index at which
|
|
1292
|
-
// an object should be inserted so as to maintain order. Uses binary search.
|
|
1293
|
-
function sortedIndex(array, obj, iteratee, context) {
|
|
1294
|
-
iteratee = cb(iteratee, context, 1);
|
|
1295
|
-
var value = iteratee(obj);
|
|
1296
|
-
var low = 0, high = getLength(array);
|
|
1297
|
-
while (low < high) {
|
|
1298
|
-
var mid = Math.floor((low + high) / 2);
|
|
1299
|
-
if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
|
|
1300
|
-
}
|
|
1301
|
-
return low;
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
// Internal function to generate the `_.indexOf` and `_.lastIndexOf` functions.
|
|
1305
|
-
function createIndexFinder(dir, predicateFind, sortedIndex) {
|
|
1306
|
-
return function(array, item, idx) {
|
|
1307
|
-
var i = 0, length = getLength(array);
|
|
1308
|
-
if (typeof idx == 'number') {
|
|
1309
|
-
if (dir > 0) {
|
|
1310
|
-
i = idx >= 0 ? idx : Math.max(idx + length, i);
|
|
1311
|
-
} else {
|
|
1312
|
-
length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
|
|
1313
|
-
}
|
|
1314
|
-
} else if (sortedIndex && idx && length) {
|
|
1315
|
-
idx = sortedIndex(array, item);
|
|
1316
|
-
return array[idx] === item ? idx : -1;
|
|
1317
|
-
}
|
|
1318
|
-
if (item !== item) {
|
|
1319
|
-
idx = predicateFind(slice.call(array, i, length), isNaN$1);
|
|
1320
|
-
return idx >= 0 ? idx + i : -1;
|
|
1321
|
-
}
|
|
1322
|
-
for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
|
|
1323
|
-
if (array[idx] === item) return idx;
|
|
1324
|
-
}
|
|
1325
|
-
return -1;
|
|
1326
|
-
};
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
// Return the position of the first occurrence of an item in an array,
|
|
1330
|
-
// or -1 if the item is not included in the array.
|
|
1331
|
-
// If the array is large and already in sort order, pass `true`
|
|
1332
|
-
// for **isSorted** to use binary search.
|
|
1333
|
-
var indexOf = createIndexFinder(1, findIndex, sortedIndex);
|
|
1334
|
-
|
|
1335
|
-
// Return the position of the last occurrence of an item in an array,
|
|
1336
|
-
// or -1 if the item is not included in the array.
|
|
1337
|
-
var lastIndexOf = createIndexFinder(-1, findLastIndex);
|
|
1338
|
-
|
|
1339
|
-
// Return the first value which passes a truth test.
|
|
1340
|
-
function find(obj, predicate, context) {
|
|
1341
|
-
var keyFinder = isArrayLike(obj) ? findIndex : findKey;
|
|
1342
|
-
var key = keyFinder(obj, predicate, context);
|
|
1343
|
-
if (key !== void 0 && key !== -1) return obj[key];
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
// Convenience version of a common use case of `_.find`: getting the first
|
|
1347
|
-
// object containing specific `key:value` pairs.
|
|
1348
|
-
function findWhere(obj, attrs) {
|
|
1349
|
-
return find(obj, matcher(attrs));
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
|
-
// The cornerstone for collection functions, an `each`
|
|
1353
|
-
// implementation, aka `forEach`.
|
|
1354
|
-
// Handles raw objects in addition to array-likes. Treats all
|
|
1355
|
-
// sparse array-likes as if they were dense.
|
|
1356
|
-
function each(obj, iteratee, context) {
|
|
1357
|
-
iteratee = optimizeCb(iteratee, context);
|
|
1358
|
-
var i, length;
|
|
1359
|
-
if (isArrayLike(obj)) {
|
|
1360
|
-
for (i = 0, length = obj.length; i < length; i++) {
|
|
1361
|
-
iteratee(obj[i], i, obj);
|
|
1362
|
-
}
|
|
1363
|
-
} else {
|
|
1364
|
-
var _keys = keys(obj);
|
|
1365
|
-
for (i = 0, length = _keys.length; i < length; i++) {
|
|
1366
|
-
iteratee(obj[_keys[i]], _keys[i], obj);
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
return obj;
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
// Return the results of applying the iteratee to each element.
|
|
1373
|
-
function map(obj, iteratee, context) {
|
|
1374
|
-
iteratee = cb(iteratee, context);
|
|
1375
|
-
var _keys = !isArrayLike(obj) && keys(obj),
|
|
1376
|
-
length = (_keys || obj).length,
|
|
1377
|
-
results = Array(length);
|
|
1378
|
-
for (var index = 0; index < length; index++) {
|
|
1379
|
-
var currentKey = _keys ? _keys[index] : index;
|
|
1380
|
-
results[index] = iteratee(obj[currentKey], currentKey, obj);
|
|
1381
|
-
}
|
|
1382
|
-
return results;
|
|
1383
|
-
}
|
|
1384
|
-
|
|
1385
|
-
// Internal helper to create a reducing function, iterating left or right.
|
|
1386
|
-
function createReduce(dir) {
|
|
1387
|
-
// Wrap code that reassigns argument variables in a separate function than
|
|
1388
|
-
// the one that accesses `arguments.length` to avoid a perf hit. (#1991)
|
|
1389
|
-
var reducer = function(obj, iteratee, memo, initial) {
|
|
1390
|
-
var _keys = !isArrayLike(obj) && keys(obj),
|
|
1391
|
-
length = (_keys || obj).length,
|
|
1392
|
-
index = dir > 0 ? 0 : length - 1;
|
|
1393
|
-
if (!initial) {
|
|
1394
|
-
memo = obj[_keys ? _keys[index] : index];
|
|
1395
|
-
index += dir;
|
|
1396
|
-
}
|
|
1397
|
-
for (; index >= 0 && index < length; index += dir) {
|
|
1398
|
-
var currentKey = _keys ? _keys[index] : index;
|
|
1399
|
-
memo = iteratee(memo, obj[currentKey], currentKey, obj);
|
|
1400
|
-
}
|
|
1401
|
-
return memo;
|
|
1402
|
-
};
|
|
1403
|
-
|
|
1404
|
-
return function(obj, iteratee, memo, context) {
|
|
1405
|
-
var initial = arguments.length >= 3;
|
|
1406
|
-
return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial);
|
|
1407
|
-
};
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
// **Reduce** builds up a single result from a list of values, aka `inject`,
|
|
1411
|
-
// or `foldl`.
|
|
1412
|
-
var reduce = createReduce(1);
|
|
1413
|
-
|
|
1414
|
-
// The right-associative version of reduce, also known as `foldr`.
|
|
1415
|
-
var reduceRight = createReduce(-1);
|
|
1416
|
-
|
|
1417
|
-
// Return all the elements that pass a truth test.
|
|
1418
|
-
function filter(obj, predicate, context) {
|
|
1419
|
-
var results = [];
|
|
1420
|
-
predicate = cb(predicate, context);
|
|
1421
|
-
each(obj, function(value, index, list) {
|
|
1422
|
-
if (predicate(value, index, list)) results.push(value);
|
|
1423
|
-
});
|
|
1424
|
-
return results;
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
|
-
// Return all the elements for which a truth test fails.
|
|
1428
|
-
function reject(obj, predicate, context) {
|
|
1429
|
-
return filter(obj, negate(cb(predicate)), context);
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
// Determine whether all of the elements pass a truth test.
|
|
1433
|
-
function every(obj, predicate, context) {
|
|
1434
|
-
predicate = cb(predicate, context);
|
|
1435
|
-
var _keys = !isArrayLike(obj) && keys(obj),
|
|
1436
|
-
length = (_keys || obj).length;
|
|
1437
|
-
for (var index = 0; index < length; index++) {
|
|
1438
|
-
var currentKey = _keys ? _keys[index] : index;
|
|
1439
|
-
if (!predicate(obj[currentKey], currentKey, obj)) return false;
|
|
1440
|
-
}
|
|
1441
|
-
return true;
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
|
-
// Determine if at least one element in the object passes a truth test.
|
|
1445
|
-
function some(obj, predicate, context) {
|
|
1446
|
-
predicate = cb(predicate, context);
|
|
1447
|
-
var _keys = !isArrayLike(obj) && keys(obj),
|
|
1448
|
-
length = (_keys || obj).length;
|
|
1449
|
-
for (var index = 0; index < length; index++) {
|
|
1450
|
-
var currentKey = _keys ? _keys[index] : index;
|
|
1451
|
-
if (predicate(obj[currentKey], currentKey, obj)) return true;
|
|
1452
|
-
}
|
|
1453
|
-
return false;
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
|
-
// Determine if the array or object contains a given item (using `===`).
|
|
1457
|
-
function contains(obj, item, fromIndex, guard) {
|
|
1458
|
-
if (!isArrayLike(obj)) obj = values(obj);
|
|
1459
|
-
if (typeof fromIndex != 'number' || guard) fromIndex = 0;
|
|
1460
|
-
return indexOf(obj, item, fromIndex) >= 0;
|
|
1461
|
-
}
|
|
5
|
+
var _ = require('underscore');
|
|
6
|
+
var perseusCore = require('@khanacademy/perseus-core');
|
|
1462
7
|
|
|
1463
|
-
|
|
1464
|
-
var invoke = restArguments(function(obj, path, args) {
|
|
1465
|
-
var contextPath, func;
|
|
1466
|
-
if (isFunction$1(path)) {
|
|
1467
|
-
func = path;
|
|
1468
|
-
} else {
|
|
1469
|
-
path = toPath(path);
|
|
1470
|
-
contextPath = path.slice(0, -1);
|
|
1471
|
-
path = path[path.length - 1];
|
|
1472
|
-
}
|
|
1473
|
-
return map(obj, function(context) {
|
|
1474
|
-
var method = func;
|
|
1475
|
-
if (!method) {
|
|
1476
|
-
if (contextPath && contextPath.length) {
|
|
1477
|
-
context = deepGet(context, contextPath);
|
|
1478
|
-
}
|
|
1479
|
-
if (context == null) return void 0;
|
|
1480
|
-
method = context[path];
|
|
1481
|
-
}
|
|
1482
|
-
return method == null ? method : method.apply(context, args);
|
|
1483
|
-
});
|
|
1484
|
-
});
|
|
1485
|
-
|
|
1486
|
-
// Convenience version of a common use case of `_.map`: fetching a property.
|
|
1487
|
-
function pluck$1(obj, key) {
|
|
1488
|
-
return map(obj, property(key));
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
// Convenience version of a common use case of `_.filter`: selecting only
|
|
1492
|
-
// objects containing specific `key:value` pairs.
|
|
1493
|
-
function where(obj, attrs) {
|
|
1494
|
-
return filter(obj, matcher(attrs));
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
// Return the maximum element (or element-based computation).
|
|
1498
|
-
function max(obj, iteratee, context) {
|
|
1499
|
-
var result = -Infinity, lastComputed = -Infinity,
|
|
1500
|
-
value, computed;
|
|
1501
|
-
if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null)) {
|
|
1502
|
-
obj = isArrayLike(obj) ? obj : values(obj);
|
|
1503
|
-
for (var i = 0, length = obj.length; i < length; i++) {
|
|
1504
|
-
value = obj[i];
|
|
1505
|
-
if (value != null && value > result) {
|
|
1506
|
-
result = value;
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1509
|
-
} else {
|
|
1510
|
-
iteratee = cb(iteratee, context);
|
|
1511
|
-
each(obj, function(v, index, list) {
|
|
1512
|
-
computed = iteratee(v, index, list);
|
|
1513
|
-
if (computed > lastComputed || (computed === -Infinity && result === -Infinity)) {
|
|
1514
|
-
result = v;
|
|
1515
|
-
lastComputed = computed;
|
|
1516
|
-
}
|
|
1517
|
-
});
|
|
1518
|
-
}
|
|
1519
|
-
return result;
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
// Return the minimum element (or element-based computation).
|
|
1523
|
-
function min(obj, iteratee, context) {
|
|
1524
|
-
var result = Infinity, lastComputed = Infinity,
|
|
1525
|
-
value, computed;
|
|
1526
|
-
if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null)) {
|
|
1527
|
-
obj = isArrayLike(obj) ? obj : values(obj);
|
|
1528
|
-
for (var i = 0, length = obj.length; i < length; i++) {
|
|
1529
|
-
value = obj[i];
|
|
1530
|
-
if (value != null && value < result) {
|
|
1531
|
-
result = value;
|
|
1532
|
-
}
|
|
1533
|
-
}
|
|
1534
|
-
} else {
|
|
1535
|
-
iteratee = cb(iteratee, context);
|
|
1536
|
-
each(obj, function(v, index, list) {
|
|
1537
|
-
computed = iteratee(v, index, list);
|
|
1538
|
-
if (computed < lastComputed || (computed === Infinity && result === Infinity)) {
|
|
1539
|
-
result = v;
|
|
1540
|
-
lastComputed = computed;
|
|
1541
|
-
}
|
|
1542
|
-
});
|
|
1543
|
-
}
|
|
1544
|
-
return result;
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
// Safely create a real, live array from anything iterable.
|
|
1548
|
-
var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;
|
|
1549
|
-
function toArray(obj) {
|
|
1550
|
-
if (!obj) return [];
|
|
1551
|
-
if (isArray(obj)) return slice.call(obj);
|
|
1552
|
-
if (isString(obj)) {
|
|
1553
|
-
// Keep surrogate pair characters together.
|
|
1554
|
-
return obj.match(reStrSymbol);
|
|
1555
|
-
}
|
|
1556
|
-
if (isArrayLike(obj)) return map(obj, identity);
|
|
1557
|
-
return values(obj);
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
// Sample **n** random values from a collection using the modern version of the
|
|
1561
|
-
// [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
|
|
1562
|
-
// If **n** is not specified, returns a single random element.
|
|
1563
|
-
// The internal `guard` argument allows it to work with `_.map`.
|
|
1564
|
-
function sample(obj, n, guard) {
|
|
1565
|
-
if (n == null || guard) {
|
|
1566
|
-
if (!isArrayLike(obj)) obj = values(obj);
|
|
1567
|
-
return obj[random(obj.length - 1)];
|
|
1568
|
-
}
|
|
1569
|
-
var sample = toArray(obj);
|
|
1570
|
-
var length = getLength(sample);
|
|
1571
|
-
n = Math.max(Math.min(n, length), 0);
|
|
1572
|
-
var last = length - 1;
|
|
1573
|
-
for (var index = 0; index < n; index++) {
|
|
1574
|
-
var rand = random(index, last);
|
|
1575
|
-
var temp = sample[index];
|
|
1576
|
-
sample[index] = sample[rand];
|
|
1577
|
-
sample[rand] = temp;
|
|
1578
|
-
}
|
|
1579
|
-
return sample.slice(0, n);
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
// Shuffle a collection.
|
|
1583
|
-
function shuffle(obj) {
|
|
1584
|
-
return sample(obj, Infinity);
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
// Sort the object's values by a criterion produced by an iteratee.
|
|
1588
|
-
function sortBy(obj, iteratee, context) {
|
|
1589
|
-
var index = 0;
|
|
1590
|
-
iteratee = cb(iteratee, context);
|
|
1591
|
-
return pluck$1(map(obj, function(value, key, list) {
|
|
1592
|
-
return {
|
|
1593
|
-
value: value,
|
|
1594
|
-
index: index++,
|
|
1595
|
-
criteria: iteratee(value, key, list)
|
|
1596
|
-
};
|
|
1597
|
-
}).sort(function(left, right) {
|
|
1598
|
-
var a = left.criteria;
|
|
1599
|
-
var b = right.criteria;
|
|
1600
|
-
if (a !== b) {
|
|
1601
|
-
if (a > b || a === void 0) return 1;
|
|
1602
|
-
if (a < b || b === void 0) return -1;
|
|
1603
|
-
}
|
|
1604
|
-
return left.index - right.index;
|
|
1605
|
-
}), 'value');
|
|
1606
|
-
}
|
|
1607
|
-
|
|
1608
|
-
// An internal function used for aggregate "group by" operations.
|
|
1609
|
-
function group(behavior, partition) {
|
|
1610
|
-
return function(obj, iteratee, context) {
|
|
1611
|
-
var result = partition ? [[], []] : {};
|
|
1612
|
-
iteratee = cb(iteratee, context);
|
|
1613
|
-
each(obj, function(value, index) {
|
|
1614
|
-
var key = iteratee(value, index, obj);
|
|
1615
|
-
behavior(result, value, key);
|
|
1616
|
-
});
|
|
1617
|
-
return result;
|
|
1618
|
-
};
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
// Groups the object's values by a criterion. Pass either a string attribute
|
|
1622
|
-
// to group by, or a function that returns the criterion.
|
|
1623
|
-
var groupBy = group(function(result, value, key) {
|
|
1624
|
-
if (has$1(result, key)) result[key].push(value); else result[key] = [value];
|
|
1625
|
-
});
|
|
1626
|
-
|
|
1627
|
-
// Indexes the object's values by a criterion, similar to `_.groupBy`, but for
|
|
1628
|
-
// when you know that your index values will be unique.
|
|
1629
|
-
var indexBy = group(function(result, value, key) {
|
|
1630
|
-
result[key] = value;
|
|
1631
|
-
});
|
|
1632
|
-
|
|
1633
|
-
// Counts instances of an object that group by a certain criterion. Pass
|
|
1634
|
-
// either a string attribute to count by, or a function that returns the
|
|
1635
|
-
// criterion.
|
|
1636
|
-
var countBy = group(function(result, value, key) {
|
|
1637
|
-
if (has$1(result, key)) result[key]++; else result[key] = 1;
|
|
1638
|
-
});
|
|
1639
|
-
|
|
1640
|
-
// Split a collection into two arrays: one whose elements all pass the given
|
|
1641
|
-
// truth test, and one whose elements all do not pass the truth test.
|
|
1642
|
-
var partition = group(function(result, value, pass) {
|
|
1643
|
-
result[pass ? 0 : 1].push(value);
|
|
1644
|
-
}, true);
|
|
1645
|
-
|
|
1646
|
-
// Return the number of elements in a collection.
|
|
1647
|
-
function size(obj) {
|
|
1648
|
-
if (obj == null) return 0;
|
|
1649
|
-
return isArrayLike(obj) ? obj.length : keys(obj).length;
|
|
1650
|
-
}
|
|
1651
|
-
|
|
1652
|
-
// Internal `_.pick` helper function to determine whether `key` is an enumerable
|
|
1653
|
-
// property name of `obj`.
|
|
1654
|
-
function keyInObj(value, key, obj) {
|
|
1655
|
-
return key in obj;
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
|
-
// Return a copy of the object only containing the allowed properties.
|
|
1659
|
-
var pick = restArguments(function(obj, keys) {
|
|
1660
|
-
var result = {}, iteratee = keys[0];
|
|
1661
|
-
if (obj == null) return result;
|
|
1662
|
-
if (isFunction$1(iteratee)) {
|
|
1663
|
-
if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]);
|
|
1664
|
-
keys = allKeys(obj);
|
|
1665
|
-
} else {
|
|
1666
|
-
iteratee = keyInObj;
|
|
1667
|
-
keys = flatten$1(keys, false, false);
|
|
1668
|
-
obj = Object(obj);
|
|
1669
|
-
}
|
|
1670
|
-
for (var i = 0, length = keys.length; i < length; i++) {
|
|
1671
|
-
var key = keys[i];
|
|
1672
|
-
var value = obj[key];
|
|
1673
|
-
if (iteratee(value, key, obj)) result[key] = value;
|
|
1674
|
-
}
|
|
1675
|
-
return result;
|
|
1676
|
-
});
|
|
1677
|
-
|
|
1678
|
-
// Return a copy of the object without the disallowed properties.
|
|
1679
|
-
var omit = restArguments(function(obj, keys) {
|
|
1680
|
-
var iteratee = keys[0], context;
|
|
1681
|
-
if (isFunction$1(iteratee)) {
|
|
1682
|
-
iteratee = negate(iteratee);
|
|
1683
|
-
if (keys.length > 1) context = keys[1];
|
|
1684
|
-
} else {
|
|
1685
|
-
keys = map(flatten$1(keys, false, false), String);
|
|
1686
|
-
iteratee = function(value, key) {
|
|
1687
|
-
return !contains(keys, key);
|
|
1688
|
-
};
|
|
1689
|
-
}
|
|
1690
|
-
return pick(obj, iteratee, context);
|
|
1691
|
-
});
|
|
1692
|
-
|
|
1693
|
-
// Returns everything but the last entry of the array. Especially useful on
|
|
1694
|
-
// the arguments object. Passing **n** will return all the values in
|
|
1695
|
-
// the array, excluding the last N.
|
|
1696
|
-
function initial(array, n, guard) {
|
|
1697
|
-
return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
// Get the first element of an array. Passing **n** will return the first N
|
|
1701
|
-
// values in the array. The **guard** check allows it to work with `_.map`.
|
|
1702
|
-
function first(array, n, guard) {
|
|
1703
|
-
if (array == null || array.length < 1) return n == null || guard ? void 0 : [];
|
|
1704
|
-
if (n == null || guard) return array[0];
|
|
1705
|
-
return initial(array, array.length - n);
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
// Returns everything but the first entry of the `array`. Especially useful on
|
|
1709
|
-
// the `arguments` object. Passing an **n** will return the rest N values in the
|
|
1710
|
-
// `array`.
|
|
1711
|
-
function rest(array, n, guard) {
|
|
1712
|
-
return slice.call(array, n == null || guard ? 1 : n);
|
|
1713
|
-
}
|
|
1714
|
-
|
|
1715
|
-
// Get the last element of an array. Passing **n** will return the last N
|
|
1716
|
-
// values in the array.
|
|
1717
|
-
function last(array, n, guard) {
|
|
1718
|
-
if (array == null || array.length < 1) return n == null || guard ? void 0 : [];
|
|
1719
|
-
if (n == null || guard) return array[array.length - 1];
|
|
1720
|
-
return rest(array, Math.max(0, array.length - n));
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
|
-
// Trim out all falsy values from an array.
|
|
1724
|
-
function compact(array) {
|
|
1725
|
-
return filter(array, Boolean);
|
|
1726
|
-
}
|
|
1727
|
-
|
|
1728
|
-
// Flatten out an array, either recursively (by default), or up to `depth`.
|
|
1729
|
-
// Passing `true` or `false` as `depth` means `1` or `Infinity`, respectively.
|
|
1730
|
-
function flatten(array, depth) {
|
|
1731
|
-
return flatten$1(array, depth, false);
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
// Take the difference between one array and a number of other arrays.
|
|
1735
|
-
// Only the elements present in just the first array will remain.
|
|
1736
|
-
var difference = restArguments(function(array, rest) {
|
|
1737
|
-
rest = flatten$1(rest, true, true);
|
|
1738
|
-
return filter(array, function(value){
|
|
1739
|
-
return !contains(rest, value);
|
|
1740
|
-
});
|
|
1741
|
-
});
|
|
1742
|
-
|
|
1743
|
-
// Return a version of the array that does not contain the specified value(s).
|
|
1744
|
-
var without = restArguments(function(array, otherArrays) {
|
|
1745
|
-
return difference(array, otherArrays);
|
|
1746
|
-
});
|
|
1747
|
-
|
|
1748
|
-
// Produce a duplicate-free version of the array. If the array has already
|
|
1749
|
-
// been sorted, you have the option of using a faster algorithm.
|
|
1750
|
-
// The faster algorithm will not work with an iteratee if the iteratee
|
|
1751
|
-
// is not a one-to-one function, so providing an iteratee will disable
|
|
1752
|
-
// the faster algorithm.
|
|
1753
|
-
function uniq(array, isSorted, iteratee, context) {
|
|
1754
|
-
if (!isBoolean(isSorted)) {
|
|
1755
|
-
context = iteratee;
|
|
1756
|
-
iteratee = isSorted;
|
|
1757
|
-
isSorted = false;
|
|
1758
|
-
}
|
|
1759
|
-
if (iteratee != null) iteratee = cb(iteratee, context);
|
|
1760
|
-
var result = [];
|
|
1761
|
-
var seen = [];
|
|
1762
|
-
for (var i = 0, length = getLength(array); i < length; i++) {
|
|
1763
|
-
var value = array[i],
|
|
1764
|
-
computed = iteratee ? iteratee(value, i, array) : value;
|
|
1765
|
-
if (isSorted && !iteratee) {
|
|
1766
|
-
if (!i || seen !== computed) result.push(value);
|
|
1767
|
-
seen = computed;
|
|
1768
|
-
} else if (iteratee) {
|
|
1769
|
-
if (!contains(seen, computed)) {
|
|
1770
|
-
seen.push(computed);
|
|
1771
|
-
result.push(value);
|
|
1772
|
-
}
|
|
1773
|
-
} else if (!contains(result, value)) {
|
|
1774
|
-
result.push(value);
|
|
1775
|
-
}
|
|
1776
|
-
}
|
|
1777
|
-
return result;
|
|
1778
|
-
}
|
|
1779
|
-
|
|
1780
|
-
// Produce an array that contains the union: each distinct element from all of
|
|
1781
|
-
// the passed-in arrays.
|
|
1782
|
-
var union$1 = restArguments(function(arrays) {
|
|
1783
|
-
return uniq(flatten$1(arrays, true, true));
|
|
1784
|
-
});
|
|
1785
|
-
|
|
1786
|
-
// Produce an array that contains every item shared between all the
|
|
1787
|
-
// passed-in arrays.
|
|
1788
|
-
function intersection(array) {
|
|
1789
|
-
var result = [];
|
|
1790
|
-
var argsLength = arguments.length;
|
|
1791
|
-
for (var i = 0, length = getLength(array); i < length; i++) {
|
|
1792
|
-
var item = array[i];
|
|
1793
|
-
if (contains(result, item)) continue;
|
|
1794
|
-
var j;
|
|
1795
|
-
for (j = 1; j < argsLength; j++) {
|
|
1796
|
-
if (!contains(arguments[j], item)) break;
|
|
1797
|
-
}
|
|
1798
|
-
if (j === argsLength) result.push(item);
|
|
1799
|
-
}
|
|
1800
|
-
return result;
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
// Complement of zip. Unzip accepts an array of arrays and groups
|
|
1804
|
-
// each array's elements on shared indices.
|
|
1805
|
-
function unzip(array) {
|
|
1806
|
-
var length = (array && max(array, getLength).length) || 0;
|
|
1807
|
-
var result = Array(length);
|
|
1808
|
-
|
|
1809
|
-
for (var index = 0; index < length; index++) {
|
|
1810
|
-
result[index] = pluck$1(array, index);
|
|
1811
|
-
}
|
|
1812
|
-
return result;
|
|
1813
|
-
}
|
|
1814
|
-
|
|
1815
|
-
// Zip together multiple lists into a single array -- elements that share
|
|
1816
|
-
// an index go together.
|
|
1817
|
-
var zip = restArguments(unzip);
|
|
1818
|
-
|
|
1819
|
-
// Converts lists into objects. Pass either a single array of `[key, value]`
|
|
1820
|
-
// pairs, or two parallel arrays of the same length -- one of keys, and one of
|
|
1821
|
-
// the corresponding values. Passing by pairs is the reverse of `_.pairs`.
|
|
1822
|
-
function object$1(list, values) {
|
|
1823
|
-
var result = {};
|
|
1824
|
-
for (var i = 0, length = getLength(list); i < length; i++) {
|
|
1825
|
-
if (values) {
|
|
1826
|
-
result[list[i]] = values[i];
|
|
1827
|
-
} else {
|
|
1828
|
-
result[list[i][0]] = list[i][1];
|
|
1829
|
-
}
|
|
1830
|
-
}
|
|
1831
|
-
return result;
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
|
-
// Generate an integer Array containing an arithmetic progression. A port of
|
|
1835
|
-
// the native Python `range()` function. See
|
|
1836
|
-
// [the Python documentation](https://docs.python.org/library/functions.html#range).
|
|
1837
|
-
function range(start, stop, step) {
|
|
1838
|
-
if (stop == null) {
|
|
1839
|
-
stop = start || 0;
|
|
1840
|
-
start = 0;
|
|
1841
|
-
}
|
|
1842
|
-
if (!step) {
|
|
1843
|
-
step = stop < start ? -1 : 1;
|
|
1844
|
-
}
|
|
1845
|
-
|
|
1846
|
-
var length = Math.max(Math.ceil((stop - start) / step), 0);
|
|
1847
|
-
var range = Array(length);
|
|
1848
|
-
|
|
1849
|
-
for (var idx = 0; idx < length; idx++, start += step) {
|
|
1850
|
-
range[idx] = start;
|
|
1851
|
-
}
|
|
1852
|
-
|
|
1853
|
-
return range;
|
|
1854
|
-
}
|
|
1855
|
-
|
|
1856
|
-
// Chunk a single array into multiple arrays, each containing `count` or fewer
|
|
1857
|
-
// items.
|
|
1858
|
-
function chunk(array, count) {
|
|
1859
|
-
if (count == null || count < 1) return [];
|
|
1860
|
-
var result = [];
|
|
1861
|
-
var i = 0, length = array.length;
|
|
1862
|
-
while (i < length) {
|
|
1863
|
-
result.push(slice.call(array, i, i += count));
|
|
1864
|
-
}
|
|
1865
|
-
return result;
|
|
1866
|
-
}
|
|
1867
|
-
|
|
1868
|
-
// Helper function to continue chaining intermediate results.
|
|
1869
|
-
function chainResult(instance, obj) {
|
|
1870
|
-
return instance._chain ? _$1(obj).chain() : obj;
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
// Add your own custom functions to the Underscore object.
|
|
1874
|
-
function mixin(obj) {
|
|
1875
|
-
each(functions(obj), function(name) {
|
|
1876
|
-
var func = _$1[name] = obj[name];
|
|
1877
|
-
_$1.prototype[name] = function() {
|
|
1878
|
-
var args = [this._wrapped];
|
|
1879
|
-
push.apply(args, arguments);
|
|
1880
|
-
return chainResult(this, func.apply(_$1, args));
|
|
1881
|
-
};
|
|
1882
|
-
});
|
|
1883
|
-
return _$1;
|
|
1884
|
-
}
|
|
8
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
1885
9
|
|
|
1886
|
-
|
|
1887
|
-
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
|
1888
|
-
var method = ArrayProto[name];
|
|
1889
|
-
_$1.prototype[name] = function() {
|
|
1890
|
-
var obj = this._wrapped;
|
|
1891
|
-
if (obj != null) {
|
|
1892
|
-
method.apply(obj, arguments);
|
|
1893
|
-
if ((name === 'shift' || name === 'splice') && obj.length === 0) {
|
|
1894
|
-
delete obj[0];
|
|
1895
|
-
}
|
|
1896
|
-
}
|
|
1897
|
-
return chainResult(this, obj);
|
|
1898
|
-
};
|
|
1899
|
-
});
|
|
1900
|
-
|
|
1901
|
-
// Add all accessor `Array` functions to the wrapper.
|
|
1902
|
-
each(['concat', 'join', 'slice'], function(name) {
|
|
1903
|
-
var method = ArrayProto[name];
|
|
1904
|
-
_$1.prototype[name] = function() {
|
|
1905
|
-
var obj = this._wrapped;
|
|
1906
|
-
if (obj != null) obj = method.apply(obj, arguments);
|
|
1907
|
-
return chainResult(this, obj);
|
|
1908
|
-
};
|
|
1909
|
-
});
|
|
1910
|
-
|
|
1911
|
-
// Named Exports
|
|
1912
|
-
|
|
1913
|
-
var allExports = /*#__PURE__*/Object.freeze({
|
|
1914
|
-
__proto__: null,
|
|
1915
|
-
VERSION: VERSION,
|
|
1916
|
-
restArguments: restArguments,
|
|
1917
|
-
isObject: isObject$1,
|
|
1918
|
-
isNull: isNull,
|
|
1919
|
-
isUndefined: isUndefined,
|
|
1920
|
-
isBoolean: isBoolean,
|
|
1921
|
-
isElement: isElement,
|
|
1922
|
-
isString: isString,
|
|
1923
|
-
isNumber: isNumber,
|
|
1924
|
-
isDate: isDate,
|
|
1925
|
-
isRegExp: isRegExp,
|
|
1926
|
-
isError: isError,
|
|
1927
|
-
isSymbol: isSymbol,
|
|
1928
|
-
isArrayBuffer: isArrayBuffer,
|
|
1929
|
-
isDataView: isDataView$1,
|
|
1930
|
-
isArray: isArray,
|
|
1931
|
-
isFunction: isFunction$1,
|
|
1932
|
-
isArguments: isArguments$1,
|
|
1933
|
-
isFinite: isFinite$1,
|
|
1934
|
-
isNaN: isNaN$1,
|
|
1935
|
-
isTypedArray: isTypedArray$1,
|
|
1936
|
-
isEmpty: isEmpty,
|
|
1937
|
-
isMatch: isMatch,
|
|
1938
|
-
isEqual: isEqual,
|
|
1939
|
-
isMap: isMap,
|
|
1940
|
-
isWeakMap: isWeakMap,
|
|
1941
|
-
isSet: isSet,
|
|
1942
|
-
isWeakSet: isWeakSet,
|
|
1943
|
-
keys: keys,
|
|
1944
|
-
allKeys: allKeys,
|
|
1945
|
-
values: values,
|
|
1946
|
-
pairs: pairs,
|
|
1947
|
-
invert: invert,
|
|
1948
|
-
functions: functions,
|
|
1949
|
-
methods: functions,
|
|
1950
|
-
extend: extend,
|
|
1951
|
-
extendOwn: extendOwn,
|
|
1952
|
-
assign: extendOwn,
|
|
1953
|
-
defaults: defaults,
|
|
1954
|
-
create: create,
|
|
1955
|
-
clone: clone,
|
|
1956
|
-
tap: tap,
|
|
1957
|
-
get: get,
|
|
1958
|
-
has: has,
|
|
1959
|
-
mapObject: mapObject$1,
|
|
1960
|
-
identity: identity,
|
|
1961
|
-
constant: constant$1,
|
|
1962
|
-
noop: noop,
|
|
1963
|
-
toPath: toPath$1,
|
|
1964
|
-
property: property,
|
|
1965
|
-
propertyOf: propertyOf,
|
|
1966
|
-
matcher: matcher,
|
|
1967
|
-
matches: matcher,
|
|
1968
|
-
times: times,
|
|
1969
|
-
random: random,
|
|
1970
|
-
now: now,
|
|
1971
|
-
escape: escape,
|
|
1972
|
-
unescape: unescape,
|
|
1973
|
-
templateSettings: templateSettings,
|
|
1974
|
-
template: template,
|
|
1975
|
-
result: result,
|
|
1976
|
-
uniqueId: uniqueId,
|
|
1977
|
-
chain: chain,
|
|
1978
|
-
iteratee: iteratee,
|
|
1979
|
-
partial: partial,
|
|
1980
|
-
bind: bind,
|
|
1981
|
-
bindAll: bindAll,
|
|
1982
|
-
memoize: memoize,
|
|
1983
|
-
delay: delay,
|
|
1984
|
-
defer: defer,
|
|
1985
|
-
throttle: throttle,
|
|
1986
|
-
debounce: debounce,
|
|
1987
|
-
wrap: wrap,
|
|
1988
|
-
negate: negate,
|
|
1989
|
-
compose: compose,
|
|
1990
|
-
after: after,
|
|
1991
|
-
before: before,
|
|
1992
|
-
once: once,
|
|
1993
|
-
findKey: findKey,
|
|
1994
|
-
findIndex: findIndex,
|
|
1995
|
-
findLastIndex: findLastIndex,
|
|
1996
|
-
sortedIndex: sortedIndex,
|
|
1997
|
-
indexOf: indexOf,
|
|
1998
|
-
lastIndexOf: lastIndexOf,
|
|
1999
|
-
find: find,
|
|
2000
|
-
detect: find,
|
|
2001
|
-
findWhere: findWhere,
|
|
2002
|
-
each: each,
|
|
2003
|
-
forEach: each,
|
|
2004
|
-
map: map,
|
|
2005
|
-
collect: map,
|
|
2006
|
-
reduce: reduce,
|
|
2007
|
-
foldl: reduce,
|
|
2008
|
-
inject: reduce,
|
|
2009
|
-
reduceRight: reduceRight,
|
|
2010
|
-
foldr: reduceRight,
|
|
2011
|
-
filter: filter,
|
|
2012
|
-
select: filter,
|
|
2013
|
-
reject: reject,
|
|
2014
|
-
every: every,
|
|
2015
|
-
all: every,
|
|
2016
|
-
some: some,
|
|
2017
|
-
any: some,
|
|
2018
|
-
contains: contains,
|
|
2019
|
-
includes: contains,
|
|
2020
|
-
include: contains,
|
|
2021
|
-
invoke: invoke,
|
|
2022
|
-
pluck: pluck$1,
|
|
2023
|
-
where: where,
|
|
2024
|
-
max: max,
|
|
2025
|
-
min: min,
|
|
2026
|
-
shuffle: shuffle,
|
|
2027
|
-
sample: sample,
|
|
2028
|
-
sortBy: sortBy,
|
|
2029
|
-
groupBy: groupBy,
|
|
2030
|
-
indexBy: indexBy,
|
|
2031
|
-
countBy: countBy,
|
|
2032
|
-
partition: partition,
|
|
2033
|
-
toArray: toArray,
|
|
2034
|
-
size: size,
|
|
2035
|
-
pick: pick,
|
|
2036
|
-
omit: omit,
|
|
2037
|
-
first: first,
|
|
2038
|
-
head: first,
|
|
2039
|
-
take: first,
|
|
2040
|
-
initial: initial,
|
|
2041
|
-
last: last,
|
|
2042
|
-
rest: rest,
|
|
2043
|
-
tail: rest,
|
|
2044
|
-
drop: rest,
|
|
2045
|
-
compact: compact,
|
|
2046
|
-
flatten: flatten,
|
|
2047
|
-
without: without,
|
|
2048
|
-
uniq: uniq,
|
|
2049
|
-
unique: uniq,
|
|
2050
|
-
union: union$1,
|
|
2051
|
-
intersection: intersection,
|
|
2052
|
-
difference: difference,
|
|
2053
|
-
unzip: unzip,
|
|
2054
|
-
transpose: unzip,
|
|
2055
|
-
zip: zip,
|
|
2056
|
-
object: object$1,
|
|
2057
|
-
range: range,
|
|
2058
|
-
chunk: chunk,
|
|
2059
|
-
mixin: mixin,
|
|
2060
|
-
'default': _$1
|
|
2061
|
-
});
|
|
2062
|
-
|
|
2063
|
-
// Default Export
|
|
2064
|
-
|
|
2065
|
-
// Add all of the Underscore functions to the wrapper object.
|
|
2066
|
-
var _ = mixin(allExports);
|
|
2067
|
-
// Legacy Node.js API.
|
|
2068
|
-
_._ = _;
|
|
10
|
+
var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
|
|
2069
11
|
|
|
2070
12
|
function getMatrixSize(matrix) {
|
|
2071
13
|
const matrixSize = [1, 1];
|
|
2072
14
|
|
|
2073
15
|
// We need to find the widest row and tallest column to get the correct
|
|
2074
16
|
// matrix size.
|
|
2075
|
-
|
|
17
|
+
___default["default"](matrix).each((matrixRow, row) => {
|
|
2076
18
|
let rowWidth = 0;
|
|
2077
|
-
|
|
19
|
+
___default["default"](matrixRow).each((matrixCol, col) => {
|
|
2078
20
|
if (matrixCol != null && matrixCol.toString().length) {
|
|
2079
21
|
rowWidth = col + 1;
|
|
2080
22
|
}
|
|
@@ -2111,7 +53,9 @@ const getDecimalSeparator = locale => {
|
|
|
2111
53
|
const match = new Intl.NumberFormat(locale).format(numberWithDecimalSeparator)
|
|
2112
54
|
// 0x661 is ARABIC-INDIC DIGIT ONE
|
|
2113
55
|
// 0x6F1 is EXTENDED ARABIC-INDIC DIGIT ONE
|
|
2114
|
-
|
|
56
|
+
// 0x967 is DEVANAGARI DIGIT ONE
|
|
57
|
+
// 0x9e7 is BENGALI/BANGLA DIGIT ONE
|
|
58
|
+
.match(/[^\d\u0661\u06F1\u0967\u09e7]/);
|
|
2115
59
|
return match?.[0] ?? ".";
|
|
2116
60
|
}
|
|
2117
61
|
};
|
|
@@ -2152,10 +96,10 @@ function approximateDeepEqual(x, y) {
|
|
|
2152
96
|
return false;
|
|
2153
97
|
}
|
|
2154
98
|
if (typeof x === "object" && typeof y === "object" && !!x && !!y) {
|
|
2155
|
-
return x === y ||
|
|
99
|
+
return x === y || ___default["default"].all(x, function (v, k) {
|
|
2156
100
|
// @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
|
|
2157
101
|
return approximateDeepEqual(y[k], v);
|
|
2158
|
-
}) &&
|
|
102
|
+
}) && ___default["default"].all(y, function (v, k) {
|
|
2159
103
|
// @ts-expect-error - TS2536 - Type 'CollectionKey<T>' cannot be used to index type 'T'.
|
|
2160
104
|
return approximateDeepEqual(x[k], v);
|
|
2161
105
|
});
|
|
@@ -2320,11 +264,11 @@ const PlotDefaults = {
|
|
|
2320
264
|
getPropsForCoeffs: function (coeffs) {
|
|
2321
265
|
return {
|
|
2322
266
|
// @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; }'.
|
|
2323
|
-
fn:
|
|
267
|
+
fn: ___default["default"].partial(this.getFunctionForCoeffs, coeffs)
|
|
2324
268
|
};
|
|
2325
269
|
}
|
|
2326
270
|
};
|
|
2327
|
-
const Linear =
|
|
271
|
+
const Linear = ___default["default"].extend({}, PlotDefaults, {
|
|
2328
272
|
url: "https://ka-perseus-graphie.s3.amazonaws.com/67aaf581e6d9ef9038c10558a1f70ac21c11c9f8.png",
|
|
2329
273
|
defaultCoords: [[0.25, 0.75], [0.75, 0.75]],
|
|
2330
274
|
getCoefficients: function (coords) {
|
|
@@ -2351,7 +295,7 @@ const Linear = _.extend({}, PlotDefaults, {
|
|
|
2351
295
|
return "y = " + m.toFixed(3) + "x + " + b.toFixed(3);
|
|
2352
296
|
}
|
|
2353
297
|
});
|
|
2354
|
-
const Quadratic =
|
|
298
|
+
const Quadratic = ___default["default"].extend({}, PlotDefaults, {
|
|
2355
299
|
url: "https://ka-perseus-graphie.s3.amazonaws.com/e23d36e6fc29ee37174e92c9daba2a66677128ab.png",
|
|
2356
300
|
defaultCoords: [[0.5, 0.5], [0.75, 0.75]],
|
|
2357
301
|
movable: MOVABLES.PARABOLA,
|
|
@@ -2390,7 +334,7 @@ const Quadratic = _.extend({}, PlotDefaults, {
|
|
|
2390
334
|
return "y = " + a.toFixed(3) + "x^2 + " + b.toFixed(3) + "x + " + c.toFixed(3);
|
|
2391
335
|
}
|
|
2392
336
|
});
|
|
2393
|
-
const Sinusoid =
|
|
337
|
+
const Sinusoid = ___default["default"].extend({}, PlotDefaults, {
|
|
2394
338
|
url: "https://ka-perseus-graphie.s3.amazonaws.com/3d68e7718498475f53b206c2ab285626baf8857e.png",
|
|
2395
339
|
defaultCoords: [[0.5, 0.5], [0.6, 0.6]],
|
|
2396
340
|
movable: MOVABLES.SINUSOID,
|
|
@@ -2430,7 +374,7 @@ const Sinusoid = _.extend({}, PlotDefaults, {
|
|
|
2430
374
|
return approximateDeepEqual(canonicalSineCoefficients(coeffs1), canonicalSineCoefficients(coeffs2));
|
|
2431
375
|
}
|
|
2432
376
|
});
|
|
2433
|
-
const Tangent =
|
|
377
|
+
const Tangent = ___default["default"].extend({}, PlotDefaults, {
|
|
2434
378
|
url: "https://ka-perseus-graphie.s3.amazonaws.com/7db80d23c35214f98659fe1cf0765811c1bbfbba.png",
|
|
2435
379
|
defaultCoords: [[0.5, 0.5], [0.75, 0.75]],
|
|
2436
380
|
getCoefficients: function (coords) {
|
|
@@ -2461,7 +405,7 @@ const Tangent = _.extend({}, PlotDefaults, {
|
|
|
2461
405
|
return approximateDeepEqual(canonicalTangentCoefficients(coeffs1), canonicalTangentCoefficients(coeffs2));
|
|
2462
406
|
}
|
|
2463
407
|
});
|
|
2464
|
-
const Exponential =
|
|
408
|
+
const Exponential = ___default["default"].extend({}, PlotDefaults, {
|
|
2465
409
|
url: "https://ka-perseus-graphie.s3.amazonaws.com/9cbfad55525e3ce755a31a631b074670a5dad611.png",
|
|
2466
410
|
defaultCoords: [[0.5, 0.55], [0.75, 0.75]],
|
|
2467
411
|
defaultAsymptote: [[0, 0.5], [1.0, 0.5]],
|
|
@@ -2484,23 +428,23 @@ const Exponential = _.extend({}, PlotDefaults, {
|
|
|
2484
428
|
*/
|
|
2485
429
|
extraCoordConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
|
|
2486
430
|
const y = asymptote[0][1];
|
|
2487
|
-
return
|
|
431
|
+
return ___default["default"].all(coords, coord => coord[1] !== y);
|
|
2488
432
|
},
|
|
2489
433
|
extraAsymptoteConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
|
|
2490
434
|
const y = newCoord[1];
|
|
2491
|
-
const isValid =
|
|
435
|
+
const isValid = ___default["default"].all(coords, coord => coord[1] > y) || ___default["default"].all(coords, coord => coord[1] < y);
|
|
2492
436
|
if (isValid) {
|
|
2493
437
|
return [oldCoord[0], y];
|
|
2494
438
|
}
|
|
2495
439
|
// Snap the asymptote as close as possible, i.e., if the user moves
|
|
2496
440
|
// the mouse really quickly into an invalid region
|
|
2497
441
|
const oldY = oldCoord[1];
|
|
2498
|
-
const wasBelow =
|
|
442
|
+
const wasBelow = ___default["default"].all(coords, coord => coord[1] > oldY);
|
|
2499
443
|
if (wasBelow) {
|
|
2500
|
-
const bottomMost =
|
|
444
|
+
const bottomMost = ___default["default"].min(___default["default"].map(coords, coord => coord[1]));
|
|
2501
445
|
return [oldCoord[0], bottomMost - graph.snapStep[1]];
|
|
2502
446
|
}
|
|
2503
|
-
const topMost =
|
|
447
|
+
const topMost = ___default["default"].max(___default["default"].map(coords, coord => coord[1]));
|
|
2504
448
|
return [oldCoord[0], topMost + graph.snapStep[1]];
|
|
2505
449
|
},
|
|
2506
450
|
allowReflectOverAsymptote: true,
|
|
@@ -2529,29 +473,29 @@ const Exponential = _.extend({}, PlotDefaults, {
|
|
|
2529
473
|
return "y = " + a.toFixed(3) + "e^(" + b.toFixed(3) + "x) + " + c.toFixed(3);
|
|
2530
474
|
}
|
|
2531
475
|
});
|
|
2532
|
-
const Logarithm =
|
|
476
|
+
const Logarithm = ___default["default"].extend({}, PlotDefaults, {
|
|
2533
477
|
url: "https://ka-perseus-graphie.s3.amazonaws.com/f6491e99d34af34d924bfe0231728ad912068dc3.png",
|
|
2534
478
|
defaultCoords: [[0.55, 0.5], [0.75, 0.75]],
|
|
2535
479
|
defaultAsymptote: [[0.5, 0], [0.5, 1.0]],
|
|
2536
480
|
extraCoordConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
|
|
2537
481
|
const x = asymptote[0][0];
|
|
2538
|
-
return
|
|
482
|
+
return ___default["default"].all(coords, coord => coord[0] !== x) && coords[0][1] !== coords[1][1];
|
|
2539
483
|
},
|
|
2540
484
|
extraAsymptoteConstraint: function (newCoord, oldCoord, coords, asymptote, graph) {
|
|
2541
485
|
const x = newCoord[0];
|
|
2542
|
-
const isValid =
|
|
486
|
+
const isValid = ___default["default"].all(coords, coord => coord[0] > x) || ___default["default"].all(coords, coord => coord[0] < x);
|
|
2543
487
|
if (isValid) {
|
|
2544
488
|
return [x, oldCoord[1]];
|
|
2545
489
|
}
|
|
2546
490
|
// Snap the asymptote as close as possible, i.e., if the user moves
|
|
2547
491
|
// the mouse really quickly into an invalid region
|
|
2548
492
|
const oldX = oldCoord[0];
|
|
2549
|
-
const wasLeft =
|
|
493
|
+
const wasLeft = ___default["default"].all(coords, coord => coord[0] > oldX);
|
|
2550
494
|
if (wasLeft) {
|
|
2551
|
-
const leftMost =
|
|
495
|
+
const leftMost = ___default["default"].min(___default["default"].map(coords, coord => coord[0]));
|
|
2552
496
|
return [leftMost - graph.snapStep[0], oldCoord[1]];
|
|
2553
497
|
}
|
|
2554
|
-
const rightMost =
|
|
498
|
+
const rightMost = ___default["default"].max(___default["default"].map(coords, coord => coord[0]));
|
|
2555
499
|
return [rightMost + graph.snapStep[0], oldCoord[1]];
|
|
2556
500
|
},
|
|
2557
501
|
allowReflectOverAsymptote: true,
|
|
@@ -2561,7 +505,7 @@ const Logarithm = _.extend({}, PlotDefaults, {
|
|
|
2561
505
|
// perform some algebra on the coefficients. This also unifies the
|
|
2562
506
|
// logic between the two 'models'.
|
|
2563
507
|
const flip = coord => [coord[1], coord[0]];
|
|
2564
|
-
const inverseCoeffs = Exponential.getCoefficients(
|
|
508
|
+
const inverseCoeffs = Exponential.getCoefficients(___default["default"].map(coords, flip), ___default["default"].map(asymptote, flip));
|
|
2565
509
|
if (inverseCoeffs) {
|
|
2566
510
|
const c = -inverseCoeffs[2] / inverseCoeffs[0];
|
|
2567
511
|
const b = 1 / inverseCoeffs[0];
|
|
@@ -2586,7 +530,7 @@ const Logarithm = _.extend({}, PlotDefaults, {
|
|
|
2586
530
|
return "y = ln(" + a.toFixed(3) + "x + " + b.toFixed(3) + ") + " + c.toFixed(3);
|
|
2587
531
|
}
|
|
2588
532
|
});
|
|
2589
|
-
const AbsoluteValue =
|
|
533
|
+
const AbsoluteValue = ___default["default"].extend({}, PlotDefaults, {
|
|
2590
534
|
url: "https://ka-perseus-graphie.s3.amazonaws.com/8256a630175a0cb1d11de223d6de0266daf98721.png",
|
|
2591
535
|
defaultCoords: [[0.5, 0.5], [0.75, 0.75]],
|
|
2592
536
|
getCoefficients: function (coords) {
|
|
@@ -2630,7 +574,7 @@ const functionTypeMapping = {
|
|
|
2630
574
|
logarithm: Logarithm,
|
|
2631
575
|
absolute_value: AbsoluteValue
|
|
2632
576
|
};
|
|
2633
|
-
const allTypes =
|
|
577
|
+
const allTypes = ___default["default"].keys(functionTypeMapping);
|
|
2634
578
|
function functionForType(type) {
|
|
2635
579
|
// @ts-expect-error: TypeScript doesn't know how to use deal with generics
|
|
2636
580
|
// and conditional types in this way.
|
|
@@ -3075,7 +1019,7 @@ function parseWidget(parseType, parseOptions) {
|
|
|
3075
1019
|
graded: optional(boolean),
|
|
3076
1020
|
alignment: optional(string),
|
|
3077
1021
|
options: parseOptions,
|
|
3078
|
-
key: optional(number),
|
|
1022
|
+
key: optional(nullable(number)),
|
|
3079
1023
|
version: optional(object({
|
|
3080
1024
|
major: number,
|
|
3081
1025
|
minor: number
|
|
@@ -3463,14 +1407,15 @@ const imageDimensionToNumber = pipeParsers(union(number).or(string).parser)
|
|
|
3463
1407
|
// string parses to either NaN (using parseInt) or 0 (using unary +) and
|
|
3464
1408
|
// CSS will treat NaN as invalid and default to 0 instead.
|
|
3465
1409
|
.then(convert(emptyToZero)).then(stringToNumber).parser;
|
|
1410
|
+
const dimensionOrUndefined = defaulted(imageDimensionToNumber, () => undefined);
|
|
3466
1411
|
const parsePerseusImageBackground = object({
|
|
3467
1412
|
url: optional(nullable(string)),
|
|
3468
|
-
width:
|
|
3469
|
-
height:
|
|
3470
|
-
top:
|
|
3471
|
-
left:
|
|
3472
|
-
bottom:
|
|
3473
|
-
scale:
|
|
1413
|
+
width: dimensionOrUndefined,
|
|
1414
|
+
height: dimensionOrUndefined,
|
|
1415
|
+
top: dimensionOrUndefined,
|
|
1416
|
+
left: dimensionOrUndefined,
|
|
1417
|
+
bottom: dimensionOrUndefined,
|
|
1418
|
+
scale: dimensionOrUndefined
|
|
3474
1419
|
});
|
|
3475
1420
|
|
|
3476
1421
|
const pairOfNumbers$2 = pair(number, number);
|
|
@@ -4077,13 +2022,16 @@ const parseLockedPolygonType = object({
|
|
|
4077
2022
|
labels: optional(array(parseLockedLabelType)),
|
|
4078
2023
|
ariaLabel: optional(string)
|
|
4079
2024
|
});
|
|
2025
|
+
|
|
2026
|
+
// Exported for testing.
|
|
2027
|
+
const parseLockedFunctionDomain = defaulted(pair(defaulted(number, () => -Infinity), defaulted(number, () => Infinity)), () => [-Infinity, Infinity]);
|
|
4080
2028
|
const parseLockedFunctionType = object({
|
|
4081
2029
|
type: constant("function"),
|
|
4082
2030
|
color: parseLockedFigureColor,
|
|
4083
2031
|
strokeStyle: parseLockedLineStyle,
|
|
4084
2032
|
equation: string,
|
|
4085
2033
|
directionalAxis: enumeration("x", "y"),
|
|
4086
|
-
domain:
|
|
2034
|
+
domain: parseLockedFunctionDomain,
|
|
4087
2035
|
// TODO(benchristel): default labels to empty array?
|
|
4088
2036
|
labels: optional(array(parseLockedLabelType)),
|
|
4089
2037
|
ariaLabel: optional(string)
|
|
@@ -4203,6 +2151,7 @@ const parseNumberLineWidget = parseWidget(constant("number-line"), object({
|
|
|
4203
2151
|
}));
|
|
4204
2152
|
|
|
4205
2153
|
const parseMathFormat = enumeration("integer", "mixed", "improper", "proper", "decimal", "percent", "pi");
|
|
2154
|
+
const parseSimplify = enumeration("required", "correct", "enforced", "optional");
|
|
4206
2155
|
const parseNumericInputWidget = parseWidget(constant("numeric-input"), object({
|
|
4207
2156
|
answers: array(object({
|
|
4208
2157
|
message: string,
|
|
@@ -4211,13 +2160,18 @@ const parseNumericInputWidget = parseWidget(constant("numeric-input"), object({
|
|
|
4211
2160
|
// the data, simplify this.
|
|
4212
2161
|
value: optional(nullable(number)),
|
|
4213
2162
|
status: string,
|
|
4214
|
-
answerForms:
|
|
2163
|
+
answerForms: defaulted(array(parseMathFormat), () => undefined),
|
|
4215
2164
|
strict: boolean,
|
|
4216
2165
|
maxError: optional(nullable(number)),
|
|
4217
2166
|
// TODO(benchristel): simplify should never be a boolean, but we
|
|
4218
2167
|
// have some content where it is anyway. If we ever backfill
|
|
4219
2168
|
// the data, we should simplify `simplify`.
|
|
4220
|
-
simplify: optional(nullable(union(
|
|
2169
|
+
simplify: optional(nullable(union(parseSimplify).or(pipeParsers(boolean).then(convert(value => {
|
|
2170
|
+
if (typeof value === "boolean") {
|
|
2171
|
+
return value ? "required" : "optional";
|
|
2172
|
+
}
|
|
2173
|
+
return value;
|
|
2174
|
+
})).parser).parser))
|
|
4221
2175
|
})),
|
|
4222
2176
|
labelText: optional(string),
|
|
4223
2177
|
size: string,
|
|
@@ -4309,7 +2263,7 @@ const parseRadioWidget = parseWidget(constant("radio"), object({
|
|
|
4309
2263
|
// There is an import cycle between radio-widget.ts and
|
|
4310
2264
|
// widgets-map.ts. The anonymous function below ensures that we
|
|
4311
2265
|
// don't refer to parseWidgetsMap before it's defined.
|
|
4312
|
-
widgets:
|
|
2266
|
+
widgets: defaulted((rawVal, ctx) => parseWidgetsMap(rawVal, ctx), () => undefined)
|
|
4313
2267
|
})),
|
|
4314
2268
|
hasNoneOfTheAbove: optional(boolean),
|
|
4315
2269
|
countChoices: optional(boolean),
|
|
@@ -4463,13 +2417,17 @@ const parseDeprecatedWidget = parseWidget(
|
|
|
4463
2417
|
(_, ctx) => ctx.success("deprecated-standin"),
|
|
4464
2418
|
// Allow any widget options
|
|
4465
2419
|
object({}));
|
|
4466
|
-
const
|
|
4467
|
-
|
|
4468
|
-
|
|
2420
|
+
const parseStringToNonNegativeInt = (rawValue, ctx) => {
|
|
2421
|
+
// The article renderer seems to allow the numeric part of a widget ID to
|
|
2422
|
+
// be 0, at least for image widgets. However, if widget IDs in an exercise
|
|
2423
|
+
// contain 0, the exercise renderer will blow up. We allow 0 here for
|
|
2424
|
+
// compatibility with articles.
|
|
2425
|
+
if (typeof rawValue !== "string" || !/^(0|[1-9][0-9]*)$/.test(rawValue)) {
|
|
2426
|
+
return ctx.failure("a string representing a non-negative integer", rawValue);
|
|
4469
2427
|
}
|
|
4470
2428
|
return ctx.success(+rawValue);
|
|
4471
2429
|
};
|
|
4472
|
-
const parseWidgetIdComponents = pair(string,
|
|
2430
|
+
const parseWidgetIdComponents = pair(string, parseStringToNonNegativeInt);
|
|
4473
2431
|
|
|
4474
2432
|
const parsePerseusRenderer = defaulted(object({
|
|
4475
2433
|
// TODO(benchristel): content is also defaulted to empty string in
|
|
@@ -4480,8 +2438,9 @@ const parsePerseusRenderer = defaulted(object({
|
|
|
4480
2438
|
// The anonymous function below ensures that we don't try to access
|
|
4481
2439
|
// parseWidgetsMap before it's defined.
|
|
4482
2440
|
widgets: defaulted((rawVal, ctx) => parseWidgetsMap(rawVal, ctx), () => ({})),
|
|
4483
|
-
|
|
4484
|
-
|
|
2441
|
+
images: parseImages,
|
|
2442
|
+
// deprecated
|
|
2443
|
+
metadata: any
|
|
4485
2444
|
}),
|
|
4486
2445
|
// Default value
|
|
4487
2446
|
() => ({
|
|
@@ -4493,17 +2452,47 @@ const parsePerseusRenderer = defaulted(object({
|
|
|
4493
2452
|
const parsePerseusArticle = union(parsePerseusRenderer).or(array(parsePerseusRenderer)).parser;
|
|
4494
2453
|
|
|
4495
2454
|
const parseHint = object({
|
|
4496
|
-
replace:
|
|
2455
|
+
replace: defaulted(boolean, () => undefined),
|
|
4497
2456
|
content: string,
|
|
4498
2457
|
widgets: defaulted(parseWidgetsMap, () => ({})),
|
|
4499
|
-
|
|
4500
|
-
|
|
2458
|
+
images: parseImages,
|
|
2459
|
+
// deprecated
|
|
2460
|
+
metadata: any
|
|
4501
2461
|
});
|
|
4502
2462
|
|
|
2463
|
+
const parsePerseusAnswerArea = pipeParsers(defaulted(object({}), () => ({}))).then(convert(toAnswerArea)).parser;
|
|
2464
|
+
|
|
2465
|
+
// Some answerAreas have extra, bogus fields, like:
|
|
2466
|
+
//
|
|
2467
|
+
// "answerArea": {
|
|
2468
|
+
// "type": "multiple",
|
|
2469
|
+
// "options": {},
|
|
2470
|
+
// "version": null,
|
|
2471
|
+
// "static": false,
|
|
2472
|
+
// "graded": false,
|
|
2473
|
+
// "alignment": "",
|
|
2474
|
+
// }
|
|
2475
|
+
//
|
|
2476
|
+
// This function filters the fields of an answerArea object, keeping only the
|
|
2477
|
+
// known ones, and converts `undefined` and `null` values to `false`.
|
|
2478
|
+
function toAnswerArea(raw) {
|
|
2479
|
+
return {
|
|
2480
|
+
zTable: !!raw.zTable,
|
|
2481
|
+
calculator: !!raw.calculator,
|
|
2482
|
+
chi2Table: !!raw.chi2Table,
|
|
2483
|
+
financialCalculatorMonthlyPayment: !!raw.financialCalculatorMonthlyPayment,
|
|
2484
|
+
financialCalculatorTotalAmount: !!raw.financialCalculatorTotalAmount,
|
|
2485
|
+
financialCalculatorTimeToPayOff: !!raw.financialCalculatorTimeToPayOff,
|
|
2486
|
+
periodicTable: !!raw.periodicTable,
|
|
2487
|
+
periodicTableWithKey: !!raw.periodicTableWithKey,
|
|
2488
|
+
tTable: !!raw.tTable
|
|
2489
|
+
};
|
|
2490
|
+
}
|
|
2491
|
+
|
|
4503
2492
|
const parsePerseusItem$1 = object({
|
|
4504
2493
|
question: parsePerseusRenderer,
|
|
4505
2494
|
hints: defaulted(array(parseHint), () => []),
|
|
4506
|
-
answerArea:
|
|
2495
|
+
answerArea: parsePerseusAnswerArea,
|
|
4507
2496
|
itemDataVersion: optional(object({
|
|
4508
2497
|
major: number,
|
|
4509
2498
|
minor: number
|
|
@@ -4512,28 +2501,6 @@ const parsePerseusItem$1 = object({
|
|
|
4512
2501
|
answer: any
|
|
4513
2502
|
});
|
|
4514
2503
|
|
|
4515
|
-
// Some answerAreas have extra fields, like:
|
|
4516
|
-
//
|
|
4517
|
-
// "answerArea": {
|
|
4518
|
-
// "type": "multiple",
|
|
4519
|
-
// "options": {
|
|
4520
|
-
// "content": "",
|
|
4521
|
-
// "images": {},
|
|
4522
|
-
// "widgets": {}
|
|
4523
|
-
// }
|
|
4524
|
-
// }
|
|
4525
|
-
//
|
|
4526
|
-
// The "type" and "options" fields don't seem to be used anywhere. This
|
|
4527
|
-
// migration function removes them.
|
|
4528
|
-
function migrateAnswerArea(rawValue, ctx) {
|
|
4529
|
-
const {
|
|
4530
|
-
type: _,
|
|
4531
|
-
options: __,
|
|
4532
|
-
...rest
|
|
4533
|
-
} = rawValue;
|
|
4534
|
-
return ctx.success(rest);
|
|
4535
|
-
}
|
|
4536
|
-
|
|
4537
2504
|
/**
|
|
4538
2505
|
* Helper to parse PerseusItem JSON
|
|
4539
2506
|
* Why not just use JSON.parse? We want:
|
|
@@ -4606,9 +2573,50 @@ function throwErrorIfCheatingDetected() {
|
|
|
4606
2573
|
}
|
|
4607
2574
|
}
|
|
4608
2575
|
|
|
2576
|
+
/**
|
|
2577
|
+
* Adds the given perseus library version information to the __perseus_debug__
|
|
2578
|
+
* object and ensures that the object is attached to `globalThis` (`window` in
|
|
2579
|
+
* browser environments).
|
|
2580
|
+
*
|
|
2581
|
+
* This allows each library to provide runtime version information to assist in
|
|
2582
|
+
* debugging in production environments.
|
|
2583
|
+
*/
|
|
2584
|
+
const addLibraryVersionToPerseusDebug = (libraryName, libraryVersion) => {
|
|
2585
|
+
// If the library version is the default value, then we don't want to
|
|
2586
|
+
// prefix it with a "v" to indicate that it is a version number.
|
|
2587
|
+
let prefix = "v";
|
|
2588
|
+
if (libraryVersion === "__lib_version__") {
|
|
2589
|
+
prefix = "";
|
|
2590
|
+
}
|
|
2591
|
+
const formattedVersion = `${prefix}${libraryVersion}`;
|
|
2592
|
+
if (typeof globalThis !== "undefined") {
|
|
2593
|
+
globalThis.__perseus_debug__ = globalThis.__perseus_debug__ ?? {};
|
|
2594
|
+
const existingVersionEntry = globalThis.__perseus_debug__[libraryName];
|
|
2595
|
+
if (existingVersionEntry) {
|
|
2596
|
+
// If we already have an entry and it doesn't match the registered
|
|
2597
|
+
// version, we morph the entry into an array and log a warning.
|
|
2598
|
+
if (existingVersionEntry !== formattedVersion) {
|
|
2599
|
+
// Existing entry might be an array already (oops, at least 2
|
|
2600
|
+
// versions of the library already loaded!).
|
|
2601
|
+
const allVersions = Array.isArray(existingVersionEntry) ? existingVersionEntry : [existingVersionEntry];
|
|
2602
|
+
allVersions.push(formattedVersion);
|
|
2603
|
+
globalThis.__perseus_debug__[libraryName] = allVersions;
|
|
2604
|
+
|
|
2605
|
+
// eslint-disable-next-line no-console
|
|
2606
|
+
console.warn(`Multiple versions of ${libraryName} loaded on this page: ${allVersions.sort().join(", ")}`);
|
|
2607
|
+
}
|
|
2608
|
+
} else {
|
|
2609
|
+
globalThis.__perseus_debug__[libraryName] = formattedVersion;
|
|
2610
|
+
}
|
|
2611
|
+
} else {
|
|
2612
|
+
// eslint-disable-next-line no-console
|
|
2613
|
+
console.warn(`globalThis not found found (${formattedVersion})`);
|
|
2614
|
+
}
|
|
2615
|
+
};
|
|
2616
|
+
|
|
4609
2617
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
4610
2618
|
const libName = "@khanacademy/perseus-core";
|
|
4611
|
-
const libVersion = "
|
|
2619
|
+
const libVersion = "4.0.0";
|
|
4612
2620
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
4613
2621
|
|
|
4614
2622
|
/**
|
|
@@ -4685,7 +2693,7 @@ class PerseusError extends Error {
|
|
|
4685
2693
|
* }
|
|
4686
2694
|
*/
|
|
4687
2695
|
const pluck = function (table, subKey) {
|
|
4688
|
-
return
|
|
2696
|
+
return ___default["default"].object(___default["default"].map(table, function (value, key) {
|
|
4689
2697
|
return [key, value[subKey]];
|
|
4690
2698
|
}));
|
|
4691
2699
|
};
|
|
@@ -4930,10 +2938,7 @@ const grapherWidgetLogic = {
|
|
|
4930
2938
|
const defaultWidgetOptions$m = {
|
|
4931
2939
|
content: "",
|
|
4932
2940
|
widgets: {},
|
|
4933
|
-
images: {}
|
|
4934
|
-
// `undefined` instead of `null` so that getDefaultProps works for
|
|
4935
|
-
// `the GroupMetadataEditor`
|
|
4936
|
-
metadata: undefined
|
|
2941
|
+
images: {}
|
|
4937
2942
|
};
|
|
4938
2943
|
const groupWidgetLogic = {
|
|
4939
2944
|
name: "group",
|
|
@@ -5079,6 +3084,64 @@ const labelImageWidgetLogic = {
|
|
|
5079
3084
|
getPublicWidgetOptions: getLabelImagePublicWidgetOptions
|
|
5080
3085
|
};
|
|
5081
3086
|
|
|
3087
|
+
// TODO(LEMS-2841): Should be able to remove once getPublicWidgetOptions is hooked up
|
|
3088
|
+
|
|
3089
|
+
// TODO(LEMS-2841): Should be able to remove once getPublicWidgetOptions is hooked up
|
|
3090
|
+
const shuffleMatcher = props => {
|
|
3091
|
+
// Use the same random() function to shuffle both columns sequentially
|
|
3092
|
+
const rng = perseusCore.seededRNG(props.problemNum);
|
|
3093
|
+
let left;
|
|
3094
|
+
if (!props.orderMatters) {
|
|
3095
|
+
// If the order doesn't matter, don't shuffle the left column
|
|
3096
|
+
left = props.left;
|
|
3097
|
+
} else {
|
|
3098
|
+
left = perseusCore.shuffle(props.left, rng, /* ensurePermuted */true);
|
|
3099
|
+
}
|
|
3100
|
+
const right = perseusCore.shuffle(props.right, rng, /* ensurePermuted */true);
|
|
3101
|
+
return {
|
|
3102
|
+
left,
|
|
3103
|
+
right
|
|
3104
|
+
};
|
|
3105
|
+
};
|
|
3106
|
+
|
|
3107
|
+
// TODO(LEMS-2841): Can shorten to shuffleMatcher after above function removed
|
|
3108
|
+
function shuffleMatcherWithRandom(data) {
|
|
3109
|
+
// Use the same random() function to shuffle both columns sequentially
|
|
3110
|
+
let left;
|
|
3111
|
+
if (!data.orderMatters) {
|
|
3112
|
+
// If the order doesn't matter, don't shuffle the left column
|
|
3113
|
+
left = data.left;
|
|
3114
|
+
} else {
|
|
3115
|
+
left = perseusCore.shuffle(data.left, Math.random, /* ensurePermuted */true);
|
|
3116
|
+
}
|
|
3117
|
+
const right = perseusCore.shuffle(data.right, Math.random, /* ensurePermuted */true);
|
|
3118
|
+
return {
|
|
3119
|
+
left,
|
|
3120
|
+
right
|
|
3121
|
+
};
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
/**
|
|
3125
|
+
* For details on the individual options, see the
|
|
3126
|
+
* PerseusMatcherWidgetOptions type
|
|
3127
|
+
*/
|
|
3128
|
+
|
|
3129
|
+
/**
|
|
3130
|
+
* Given a PerseusMatcherWidgetOptions object, return a new object with only
|
|
3131
|
+
* the public options that should be exposed to the client.
|
|
3132
|
+
*/
|
|
3133
|
+
function getMatcherPublicWidgetOptions(options) {
|
|
3134
|
+
const {
|
|
3135
|
+
left,
|
|
3136
|
+
right
|
|
3137
|
+
} = shuffleMatcherWithRandom(options);
|
|
3138
|
+
return {
|
|
3139
|
+
...options,
|
|
3140
|
+
left: left,
|
|
3141
|
+
right: right
|
|
3142
|
+
};
|
|
3143
|
+
}
|
|
3144
|
+
|
|
5082
3145
|
const defaultWidgetOptions$f = {
|
|
5083
3146
|
left: ["$x$", "$y$", "$z$"],
|
|
5084
3147
|
right: ["$1$", "$2$", "$3$"],
|
|
@@ -5088,7 +3151,8 @@ const defaultWidgetOptions$f = {
|
|
|
5088
3151
|
};
|
|
5089
3152
|
const matcherWidgetLogic = {
|
|
5090
3153
|
name: "matcher",
|
|
5091
|
-
defaultWidgetOptions: defaultWidgetOptions$f
|
|
3154
|
+
defaultWidgetOptions: defaultWidgetOptions$f,
|
|
3155
|
+
getPublicWidgetOptions: getMatcherPublicWidgetOptions
|
|
5092
3156
|
};
|
|
5093
3157
|
|
|
5094
3158
|
function getMatrixPublicWidgetOptions(options) {
|
|
@@ -5186,16 +3250,36 @@ const numberLineWidgetLogic = {
|
|
|
5186
3250
|
* PerseusNumericInputWidgetOptions type
|
|
5187
3251
|
*/
|
|
5188
3252
|
|
|
3253
|
+
/**
|
|
3254
|
+
* This data from `answers` is used pre-scoring to give hints
|
|
3255
|
+
* to the learner regarding the format of accepted answers
|
|
3256
|
+
*/
|
|
3257
|
+
function getNumericInputAnswerPublicData(answer) {
|
|
3258
|
+
const {
|
|
3259
|
+
answerForms,
|
|
3260
|
+
simplify,
|
|
3261
|
+
status
|
|
3262
|
+
} = answer;
|
|
3263
|
+
return {
|
|
3264
|
+
answerForms,
|
|
3265
|
+
simplify,
|
|
3266
|
+
status
|
|
3267
|
+
};
|
|
3268
|
+
}
|
|
3269
|
+
|
|
5189
3270
|
/**
|
|
5190
3271
|
* Given a PerseusNumericInputWidgetOptions object, return a new object with only
|
|
5191
3272
|
* the public options that should be exposed to the client.
|
|
5192
3273
|
*/
|
|
5193
3274
|
function getNumericInputPublicWidgetOptions(options) {
|
|
5194
3275
|
const {
|
|
5195
|
-
answers
|
|
3276
|
+
answers,
|
|
5196
3277
|
...publicWidgetOptions
|
|
5197
3278
|
} = options;
|
|
5198
|
-
return
|
|
3279
|
+
return {
|
|
3280
|
+
...publicWidgetOptions,
|
|
3281
|
+
answers: answers.map(getNumericInputAnswerPublicData)
|
|
3282
|
+
};
|
|
5199
3283
|
}
|
|
5200
3284
|
|
|
5201
3285
|
const defaultWidgetOptions$b = {
|
|
@@ -5430,13 +3514,17 @@ const radioWidgetLogic = {
|
|
|
5430
3514
|
* the public options that should be exposed to the client.
|
|
5431
3515
|
*/
|
|
5432
3516
|
function getSorterPublicWidgetOptions(options) {
|
|
3517
|
+
const shuffledCorrect = perseusCore.shuffle(options.correct, Math.random, /* ensurePermuted */true);
|
|
5433
3518
|
return {
|
|
3519
|
+
...options,
|
|
5434
3520
|
// Note(Tamara): This does not provide correct answer information any longer.
|
|
5435
3521
|
// To maintain compatibility with the original widget options, we are
|
|
5436
3522
|
// keeping the key the same. Represents initial state of the cards here.
|
|
5437
|
-
correct:
|
|
5438
|
-
|
|
5439
|
-
|
|
3523
|
+
correct: shuffledCorrect,
|
|
3524
|
+
// Note(Tamara): This new key is only added here with "true". There isn't
|
|
3525
|
+
// a place where it is set to false. It indicates that the correct field
|
|
3526
|
+
// has been shuffled and no longer contains correct answer info.
|
|
3527
|
+
isCorrectShuffled: true
|
|
5440
3528
|
};
|
|
5441
3529
|
}
|
|
5442
3530
|
|
|
@@ -5606,7 +3694,7 @@ const upgradeWidgetInfoToLatestVersion = oldWidgetInfo => {
|
|
|
5606
3694
|
// that `type` is non-optional. But we're seeing this in Sentry today so I
|
|
5607
3695
|
// suspect we have legacy data (potentially unpublished) and we should
|
|
5608
3696
|
// figure that out before depending solely on types.
|
|
5609
|
-
if (!
|
|
3697
|
+
if (!___default["default"].isString(type)) {
|
|
5610
3698
|
throw new PerseusError("widget type must be a string, but was: " + type, Errors.Internal);
|
|
5611
3699
|
}
|
|
5612
3700
|
if (!isWidgetRegistered(type)) {
|
|
@@ -5632,14 +3720,14 @@ const upgradeWidgetInfoToLatestVersion = oldWidgetInfo => {
|
|
|
5632
3720
|
// We do a clone here so that it's safe to mutate the input parameter
|
|
5633
3721
|
// in propUpgrades functions (which I will probably accidentally do at
|
|
5634
3722
|
// some point, and we would like to not break when that happens).
|
|
5635
|
-
let newEditorOptions =
|
|
3723
|
+
let newEditorOptions = ___default["default"].clone(oldWidgetInfo.options) || {};
|
|
5636
3724
|
const upgradePropsMap = getWidgetOptionsUpgrades(type);
|
|
5637
3725
|
|
|
5638
3726
|
// Empty props usually mean a newly created widget by the editor,
|
|
5639
3727
|
// and are always considerered up-to-date.
|
|
5640
3728
|
// Mostly, we'd rather not run upgrade functions on props that are
|
|
5641
3729
|
// not complete.
|
|
5642
|
-
if (
|
|
3730
|
+
if (___default["default"].keys(newEditorOptions).length !== 0) {
|
|
5643
3731
|
// We loop through all the versions after the current version of
|
|
5644
3732
|
// the loaded widget, up to and including the latest version of the
|
|
5645
3733
|
// loaded widget, and run the upgrade function to bring our loaded
|
|
@@ -5726,7 +3814,7 @@ function getUpgradedWidgetOptions(oldWidgetOptions) {
|
|
|
5726
3814
|
}
|
|
5727
3815
|
|
|
5728
3816
|
function splitPerseusItem(originalItem) {
|
|
5729
|
-
const item =
|
|
3817
|
+
const item = ___default["default"].clone(originalItem);
|
|
5730
3818
|
const originalWidgets = item.widgets ?? {};
|
|
5731
3819
|
const upgradedWidgets = getUpgradedWidgetOptions(originalWidgets);
|
|
5732
3820
|
const splitWidgets = {};
|
|
@@ -5743,13 +3831,66 @@ function splitPerseusItem(originalItem) {
|
|
|
5743
3831
|
};
|
|
5744
3832
|
}
|
|
5745
3833
|
|
|
3834
|
+
/* Note(tamara): Brought over from the perseus package packages/perseus/src/util.ts file.
|
|
3835
|
+
May be useful to bring other perseus package utilities here. Contains utility functions
|
|
3836
|
+
and types used across multiple widgets for randomization and shuffling. */
|
|
3837
|
+
const seededRNG = function (seed) {
|
|
3838
|
+
let randomSeed = seed;
|
|
3839
|
+
return function () {
|
|
3840
|
+
// Robert Jenkins' 32 bit integer hash function.
|
|
3841
|
+
let seed = randomSeed;
|
|
3842
|
+
seed = seed + 0x7ed55d16 + (seed << 12) & 0xffffffff;
|
|
3843
|
+
seed = (seed ^ 0xc761c23c ^ seed >>> 19) & 0xffffffff;
|
|
3844
|
+
seed = seed + 0x165667b1 + (seed << 5) & 0xffffffff;
|
|
3845
|
+
seed = (seed + 0xd3a2646c ^ seed << 9) & 0xffffffff;
|
|
3846
|
+
seed = seed + 0xfd7046c5 + (seed << 3) & 0xffffffff;
|
|
3847
|
+
seed = (seed ^ 0xb55a4f09 ^ seed >>> 16) & 0xffffffff;
|
|
3848
|
+
return (randomSeed = seed & 0xfffffff) / 0x10000000;
|
|
3849
|
+
};
|
|
3850
|
+
};
|
|
3851
|
+
|
|
3852
|
+
// Shuffle an array using a given random seed or function.
|
|
3853
|
+
// If `ensurePermuted` is true, the input and output are guaranteed to be
|
|
3854
|
+
// distinct permutations.
|
|
3855
|
+
function shuffle(array, randomSeed) {
|
|
3856
|
+
let ensurePermuted = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
3857
|
+
// Always return a copy of the input array
|
|
3858
|
+
const shuffled = ___default["default"].clone(array);
|
|
3859
|
+
|
|
3860
|
+
// Handle edge cases (input array is empty or uniform)
|
|
3861
|
+
if (!shuffled.length || ___default["default"].all(shuffled, function (value) {
|
|
3862
|
+
return ___default["default"].isEqual(value, shuffled[0]);
|
|
3863
|
+
})) {
|
|
3864
|
+
return shuffled;
|
|
3865
|
+
}
|
|
3866
|
+
let random;
|
|
3867
|
+
if (typeof randomSeed === "function") {
|
|
3868
|
+
random = randomSeed;
|
|
3869
|
+
} else {
|
|
3870
|
+
random = seededRNG(randomSeed);
|
|
3871
|
+
}
|
|
3872
|
+
do {
|
|
3873
|
+
// Fischer-Yates shuffle
|
|
3874
|
+
for (let top = shuffled.length; top > 0; top--) {
|
|
3875
|
+
const newEnd = Math.floor(random() * top);
|
|
3876
|
+
const temp = shuffled[newEnd];
|
|
3877
|
+
|
|
3878
|
+
// @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
|
|
3879
|
+
shuffled[newEnd] = shuffled[top - 1];
|
|
3880
|
+
// @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
|
|
3881
|
+
shuffled[top - 1] = temp;
|
|
3882
|
+
}
|
|
3883
|
+
} while (ensurePermuted && ___default["default"].isEqual(array, shuffled));
|
|
3884
|
+
return shuffled;
|
|
3885
|
+
}
|
|
3886
|
+
const random = seededRNG(new Date().getTime() & 0xffffffff);
|
|
3887
|
+
|
|
5746
3888
|
exports.CoreWidgetRegistry = coreWidgetRegistry;
|
|
5747
3889
|
exports.Errors = Errors;
|
|
5748
3890
|
exports.GrapherUtil = grapherUtil;
|
|
5749
3891
|
exports.ItemExtras = ItemExtras;
|
|
5750
3892
|
exports.PerseusError = PerseusError;
|
|
5751
3893
|
exports.PerseusExpressionAnswerFormConsidered = PerseusExpressionAnswerFormConsidered;
|
|
5752
|
-
exports.addLibraryVersionToPerseusDebug = addLibraryVersionToPerseusDebug;
|
|
5753
3894
|
exports.addWidget = addWidget;
|
|
5754
3895
|
exports.approximateDeepEqual = approximateDeepEqual;
|
|
5755
3896
|
exports.approximateEqual = approximateEqual;
|
|
@@ -5769,6 +3910,7 @@ exports.getGrapherPublicWidgetOptions = getGrapherPublicWidgetOptions;
|
|
|
5769
3910
|
exports.getIFramePublicWidgetOptions = getIFramePublicWidgetOptions;
|
|
5770
3911
|
exports.getInteractiveGraphPublicWidgetOptions = getInteractiveGraphPublicWidgetOptions;
|
|
5771
3912
|
exports.getLabelImagePublicWidgetOptions = getLabelImagePublicWidgetOptions;
|
|
3913
|
+
exports.getMatcherPublicWidgetOptions = getMatcherPublicWidgetOptions;
|
|
5772
3914
|
exports.getMatrixPublicWidgetOptions = getMatrixPublicWidgetOptions;
|
|
5773
3915
|
exports.getMatrixSize = getMatrixSize;
|
|
5774
3916
|
exports.getNumberLinePublicWidgetOptions = getNumberLinePublicWidgetOptions;
|
|
@@ -5816,6 +3958,10 @@ exports.plotterPlotTypes = plotterPlotTypes;
|
|
|
5816
3958
|
exports.pluck = pluck;
|
|
5817
3959
|
exports.pythonProgramLogic = pythonProgramWidgetLogic;
|
|
5818
3960
|
exports.radioLogic = radioWidgetLogic;
|
|
3961
|
+
exports.random = random;
|
|
3962
|
+
exports.seededRNG = seededRNG;
|
|
3963
|
+
exports.shuffle = shuffle;
|
|
3964
|
+
exports.shuffleMatcher = shuffleMatcher;
|
|
5819
3965
|
exports.sorterLogic = sorterWidgetLogic;
|
|
5820
3966
|
exports.splitPerseusItem = splitPerseusItem;
|
|
5821
3967
|
exports.tableLogic = tableWidgetLogic;
|