@dxyl/utils 1.1.2 → 1.1.5

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.
Files changed (2) hide show
  1. package/lib/_30s.js +1931 -0
  2. package/package.json +7 -1
package/lib/_30s.js ADDED
@@ -0,0 +1,1931 @@
1
+
2
+ const fs = typeof require !== "undefined" && require('fs');
3
+ const crypto = typeof require !== "undefined" && require('crypto');
4
+
5
+ const all = (arr, fn = Boolean) => arr.every(fn);
6
+ const allEqual = arr => arr.every(val => val === arr[0]);
7
+ const any = (arr, fn = Boolean) => arr.some(fn);
8
+ const approximatelyEqual = (v1, v2, epsilon = 0.001) => Math.abs(v1 - v2) < epsilon;
9
+ const arrayToCSV = (arr, delimiter = ',') =>
10
+ arr
11
+ .map(v => v.map(x => (isNaN(x) ? `"${x.replace(/"/g, '""')}"` : x)).join(delimiter))
12
+ .join('\n');
13
+ const arrayToHtmlList = (arr, listID) =>
14
+ (el => (
15
+ (el = document.querySelector('#' + listID)),
16
+ (el.innerHTML += arr.map(item => `<li>${item}</li>`).join(''))
17
+ ))();
18
+ const ary = (fn, n) => (...args) => fn(...args.slice(0, n));
19
+ const atob = str => Buffer.from(str, 'base64').toString('binary');
20
+ const attempt = (fn, ...args) => {
21
+ try {
22
+ return fn(...args);
23
+ } catch (e) {
24
+ return e instanceof Error ? e : new Error(e);
25
+ }
26
+ };
27
+ const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.length;
28
+ const averageBy = (arr, fn) =>
29
+ arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0) /
30
+ arr.length;
31
+ const bifurcate = (arr, filter) =>
32
+ arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [[], []]);
33
+ const bifurcateBy = (arr, fn) =>
34
+ arr.reduce((acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc), [[], []]);
35
+ const bind = (fn, context, ...boundArgs) => (...args) => fn.apply(context, [...boundArgs, ...args]);
36
+ const bindAll = (obj, ...fns) =>
37
+ fns.forEach(
38
+ fn => (
39
+ (f = obj[fn]),
40
+ (obj[fn] = function() {
41
+ return f.apply(obj);
42
+ })
43
+ )
44
+ );
45
+ const bindKey = (context, fn, ...boundArgs) => (...args) =>
46
+ context[fn].apply(context, [...boundArgs, ...args]);
47
+ const binomialCoefficient = (n, k) => {
48
+ if (Number.isNaN(n) || Number.isNaN(k)) return NaN;
49
+ if (k < 0 || k > n) return 0;
50
+ if (k === 0 || k === n) return 1;
51
+ if (k === 1 || k === n - 1) return n;
52
+ if (n - k < k) k = n - k;
53
+ let res = n;
54
+ for (let j = 2; j <= k; j++) res *= (n - j + 1) / j;
55
+ return Math.round(res);
56
+ };
57
+ const bottomVisible = () =>
58
+ document.documentElement.clientHeight + window.scrollY >=
59
+ (document.documentElement.scrollHeight || document.documentElement.clientHeight);
60
+ const btoa = str => Buffer.from(str, 'binary').toString('base64');
61
+ const byteSize = str => new Blob([str]).size;
62
+ const call = (key, ...args) => context => context[key](...args);
63
+ const capitalize = ([first, ...rest], lowerRest = false) =>
64
+ first.toUpperCase() + (lowerRest ? rest.join('').toLowerCase() : rest.join(''));
65
+ const capitalizeEveryWord = str => str.replace(/\b[a-z]/g, char => char.toUpperCase());
66
+ const castArray = val => (Array.isArray(val) ? val : [val]);
67
+ const chainAsync = fns => {
68
+ let curr = 0;
69
+ const last = fns[fns.length - 1];
70
+ const next = () => {
71
+ const fn = fns[curr++];
72
+ fn === last ? fn() : fn(next);
73
+ };
74
+ next();
75
+ };
76
+ const checkProp = (predicate, prop) => obj => !!predicate(obj[prop]);
77
+ const chunk = (arr, size) =>
78
+ Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
79
+ arr.slice(i * size, i * size + size)
80
+ );
81
+ const clampNumber = (num, a, b) => Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));
82
+ const cloneRegExp = regExp => new RegExp(regExp.source, regExp.flags);
83
+ const coalesce = (...args) => args.find(_ => ![undefined, null].includes(_));
84
+ const coalesceFactory = valid => (...args) => args.find(valid);
85
+ const collectInto = fn => (...args) => fn(args);
86
+ const colorize = (...args) => ({
87
+ black: `\x1b[30m${args.join(' ')}`,
88
+ red: `\x1b[31m${args.join(' ')}`,
89
+ green: `\x1b[32m${args.join(' ')}`,
90
+ yellow: `\x1b[33m${args.join(' ')}`,
91
+ blue: `\x1b[34m${args.join(' ')}`,
92
+ magenta: `\x1b[35m${args.join(' ')}`,
93
+ cyan: `\x1b[36m${args.join(' ')}`,
94
+ white: `\x1b[37m${args.join(' ')}`,
95
+ bgBlack: `\x1b[40m${args.join(' ')}\x1b[0m`,
96
+ bgRed: `\x1b[41m${args.join(' ')}\x1b[0m`,
97
+ bgGreen: `\x1b[42m${args.join(' ')}\x1b[0m`,
98
+ bgYellow: `\x1b[43m${args.join(' ')}\x1b[0m`,
99
+ bgBlue: `\x1b[44m${args.join(' ')}\x1b[0m`,
100
+ bgMagenta: `\x1b[45m${args.join(' ')}\x1b[0m`,
101
+ bgCyan: `\x1b[46m${args.join(' ')}\x1b[0m`,
102
+ bgWhite: `\x1b[47m${args.join(' ')}\x1b[0m`
103
+ });
104
+ const compact = arr => arr.filter(Boolean);
105
+ const compactWhitespace = str => str.replace(/\s{2,}/g, ' ');
106
+ const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)));
107
+ const composeRight = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));
108
+ const converge = (converger, fns) => (...args) => converger(...fns.map(fn => fn.apply(null, args)));
109
+ const copyToClipboard = str => {
110
+ const el = document.createElement('textarea');
111
+ el.value = str;
112
+ el.setAttribute('readonly', '');
113
+ el.style.position = 'absolute';
114
+ el.style.left = '-9999px';
115
+ document.body.appendChild(el);
116
+ const selected =
117
+ document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false;
118
+ el.select();
119
+ document.execCommand('copy');
120
+ document.body.removeChild(el);
121
+ if (selected) {
122
+ document.getSelection().removeAllRanges();
123
+ document.getSelection().addRange(selected);
124
+ }
125
+ };
126
+ const countBy = (arr, fn) =>
127
+ arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => {
128
+ acc[val] = (acc[val] || 0) + 1;
129
+ return acc;
130
+ }, {});
131
+ const counter = (selector, start, end, step = 1, duration = 2000) => {
132
+ let current = start,
133
+ _step = (end - start) * step < 0 ? -step : step,
134
+ timer = setInterval(() => {
135
+ current += _step;
136
+ document.querySelector(selector).innerHTML = current;
137
+ if (current >= end) document.querySelector(selector).innerHTML = end;
138
+ if (current >= end) clearInterval(timer);
139
+ }, Math.abs(Math.floor(duration / (end - start))));
140
+ return timer;
141
+ };
142
+ const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);
143
+ const createDirIfNotExists = dir => (!fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined);
144
+ const createElement = str => {
145
+ const el = document.createElement('div');
146
+ el.innerHTML = str;
147
+ return el.firstElementChild;
148
+ };
149
+ const createEventHub = () => ({
150
+ hub: Object.create(null),
151
+ emit(event, data) {
152
+ (this.hub[event] || []).forEach(handler => handler(data));
153
+ },
154
+ on(event, handler) {
155
+ if (!this.hub[event]) this.hub[event] = [];
156
+ this.hub[event].push(handler);
157
+ },
158
+ off(event, handler) {
159
+ const i = (this.hub[event] || []).findIndex(h => h === handler);
160
+ if (i > -1) this.hub[event].splice(i, 1);
161
+ if (this.hub[event].length === 0) delete this.hub[event];
162
+ }
163
+ });
164
+ const CSVToArray = (data, delimiter = ',', omitFirstRow = false) =>
165
+ data
166
+ .slice(omitFirstRow ? data.indexOf('\n') + 1 : 0)
167
+ .split('\n')
168
+ .map(v => v.split(delimiter));
169
+ const CSVToJSON = (data, delimiter = ',') => {
170
+ const titles = data.slice(0, data.indexOf('\n')).split(delimiter);
171
+ return data
172
+ .slice(data.indexOf('\n') + 1)
173
+ .split('\n')
174
+ .map(v => {
175
+ const values = v.split(delimiter);
176
+ return titles.reduce((obj, title, index) => ((obj[title] = values[index]), obj), {});
177
+ });
178
+ };
179
+ const currentURL = () => window.location.href;
180
+ const curry = (fn, arity = fn.length, ...args) =>
181
+ arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args);
182
+ const dayOfYear = date =>
183
+ Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);
184
+ const debounce = (fn, ms = 0) => {
185
+ let timeoutId;
186
+ return function(...args) {
187
+ clearTimeout(timeoutId);
188
+ timeoutId = setTimeout(() => fn.apply(this, args), ms);
189
+ };
190
+ };
191
+ const decapitalize = ([first, ...rest], upperRest = false) =>
192
+ first.toLowerCase() + (upperRest ? rest.join('').toUpperCase() : rest.join(''));
193
+ const deepClone = obj => {
194
+ let clone = Object.assign({}, obj);
195
+ Object.keys(clone).forEach(
196
+ key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
197
+ );
198
+ return Array.isArray(obj) && obj.length
199
+ ? (clone.length = obj.length) && Array.from(clone)
200
+ : Array.isArray(obj)
201
+ ? Array.from(obj)
202
+ : clone;
203
+ };
204
+ const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));
205
+ const deepFreeze = obj =>
206
+ Object.keys(obj).forEach(prop =>
207
+ !(obj[prop] instanceof Object) || Object.isFrozen(obj[prop]) ? null : deepFreeze(obj[prop])
208
+ ) || Object.freeze(obj);
209
+ const deepGet = (obj, keys) => keys.reduce((xs, x) => (xs && xs[x] ? xs[x] : null), obj);
210
+ const deepMapKeys = (obj, f) =>
211
+ Array.isArray(obj)
212
+ ? obj.map(val => deepMapKeys(val, f))
213
+ : typeof obj === 'object'
214
+ ? Object.keys(obj).reduce((acc, current) => {
215
+ const val = obj[current];
216
+ acc[f(current)] =
217
+ val !== null && typeof val === 'object' ? deepMapKeys(val, f) : (acc[f(current)] = val);
218
+ return acc;
219
+ }, {})
220
+ : obj;
221
+ const defaults = (obj, ...defs) => Object.assign({}, obj, ...defs.reverse(), obj);
222
+ const defer = (fn, ...args) => setTimeout(fn, 1, ...args);
223
+ const degreesToRads = deg => (deg * Math.PI) / 180.0;
224
+ const delay = (fn, wait, ...args) => setTimeout(fn, wait, ...args);
225
+ const detectDeviceType = () =>
226
+ /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
227
+ ? 'Mobile'
228
+ : 'Desktop';
229
+ const difference = (a, b) => {
230
+ const s = new Set(b);
231
+ return a.filter(x => !s.has(x));
232
+ };
233
+ const differenceBy = (a, b, fn) => {
234
+ const s = new Set(b.map(fn));
235
+ return a.map(fn).filter(el => !s.has(el));
236
+ };
237
+ const differenceWith = (arr, val, comp) => arr.filter(a => val.findIndex(b => comp(a, b)) === -1);
238
+ // new add
239
+ // xor 返回两个集合不存在
240
+ const xor = (a, b) => {
241
+ const s = new Set(a.concat(b));
242
+ return a.concat(b).filter(el=>!s.has(el))
243
+ };
244
+ const xorBy = (a, b, fn) => {
245
+ const s = new Set(a.map(fn).concat(b.map(fn)));
246
+ return a.concat(b).map(fn).filter(el=>!s.has(el))
247
+ };
248
+ const xorWith = (arr, val, comp) => {
249
+ return arr.filter(el=>!val.some(d=>comp(el,d)))
250
+ }
251
+ const dig = (obj, target) =>
252
+ target in obj
253
+ ? obj[target]
254
+ : Object.values(obj).reduce((acc, val) => {
255
+ if (acc !== undefined) return acc;
256
+ if (typeof val === 'object') return dig(val, target);
257
+ }, undefined);
258
+ const digitize = n => [...`${n}`].map(i => parseInt(i));
259
+ const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0);
260
+ const drop = (arr, n = 1) => arr.slice(n);
261
+ const dropRight = (arr, n = 1) => arr.slice(0, -n);
262
+ const dropRightWhile = (arr, func) => {
263
+ let rightIndex = arr.length;
264
+ while (rightIndex-- && !func(arr[rightIndex]));
265
+ return arr.slice(0, rightIndex + 1);
266
+ };
267
+ const dropWhile = (arr, func) => {
268
+ while (arr.length > 0 && !func(arr[0])) arr = arr.slice(1);
269
+ return arr;
270
+ };
271
+ const elementContains = (parent, child) => parent !== child && parent.contains(child);
272
+ const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
273
+ const { top, left, bottom, right } = el.getBoundingClientRect();
274
+ const { innerHeight, innerWidth } = window;
275
+ return partiallyVisible
276
+ ? ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) &&
277
+ ((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
278
+ : top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
279
+ };
280
+ const elo = ([...ratings], kFactor = 32, selfRating) => {
281
+ const [a, b] = ratings;
282
+ const expectedScore = (self, opponent) => 1 / (1 + 10 ** ((opponent - self) / 400));
283
+ const newRating = (rating, i) =>
284
+ (selfRating || rating) + kFactor * (i - expectedScore(i ? a : b, i ? b : a));
285
+ if (ratings.length === 2) return [newRating(a, 1), newRating(b, 0)];
286
+
287
+ for (let i = 0, len = ratings.length; i < len; i++) {
288
+ let j = i;
289
+ while (j < len - 1) {
290
+ j++;
291
+ [ratings[i], ratings[j]] = elo([ratings[i], ratings[j]], kFactor);
292
+ }
293
+ }
294
+ return ratings;
295
+ };
296
+ const equals = (a, b) => {
297
+ if (a === b) return true;
298
+ if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
299
+ if (!a || !b || (typeof a !== 'object' && typeof b !== 'object')) return a === b;
300
+ if (a === null || a === undefined || b === null || b === undefined) return false;
301
+ if (a.prototype !== b.prototype) return false;
302
+ let keys = Object.keys(a);
303
+ if (keys.length !== Object.keys(b).length) return false;
304
+ return keys.every(k => equals(a[k], b[k]));
305
+ };
306
+ const escapeHTML = str =>
307
+ str.replace(
308
+ /[&<>'"]/g,
309
+ tag =>
310
+ ({
311
+ '&': '&amp;',
312
+ '<': '&lt;',
313
+ '>': '&gt;',
314
+ "'": '&#39;',
315
+ '"': '&quot;'
316
+ }[tag] || tag)
317
+ );
318
+ const escapeRegExp = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
319
+ const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1);
320
+ const extendHex = shortHex =>
321
+ '#' +
322
+ shortHex
323
+ .slice(shortHex.startsWith('#') ? 1 : 0)
324
+ .split('')
325
+ .map(x => x + x)
326
+ .join('');
327
+ const factorial = n =>
328
+ n < 0
329
+ ? (() => {
330
+ throw new TypeError('Negative numbers are not allowed!');
331
+ })()
332
+ : n <= 1
333
+ ? 1
334
+ : n * factorial(n - 1);
335
+ const fibonacci = n =>
336
+ Array.from({ length: n }).reduce(
337
+ (acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i),
338
+ []
339
+ );
340
+ const filterFalsy = arr => arr.filter(Boolean);
341
+ const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i));
342
+ const filterNonUniqueBy = (arr, fn) =>
343
+ arr.filter((v, i) => arr.every((x, j) => (i === j) === fn(v, x, i, j)));
344
+ const findKey = (obj, fn) => Object.keys(obj).find(key => fn(obj[key], key, obj));
345
+ const findLast = (arr, fn) => arr.filter(fn).pop();
346
+ const findLastIndex = (arr, fn) =>
347
+ (arr
348
+ .map((val, i) => [i, val])
349
+ .filter(([i, val]) => fn(val, i, arr))
350
+ .pop() || [-1])[0];
351
+ const findLastKey = (obj, fn) =>
352
+ Object.keys(obj)
353
+ .reverse()
354
+ .find(key => fn(obj[key], key, obj));
355
+ const flatten = (arr, depth = 1) =>
356
+ arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), []);
357
+ const flattenObject = (obj, prefix = '') =>
358
+ Object.keys(obj).reduce((acc, k) => {
359
+ const pre = prefix.length ? prefix + '.' : '';
360
+ if (typeof obj[k] === 'object') Object.assign(acc, flattenObject(obj[k], pre + k));
361
+ else acc[pre + k] = obj[k];
362
+ return acc;
363
+ }, {});
364
+ const flip = fn => (first, ...rest) => fn(...rest, first);
365
+ const forEachRight = (arr, callback) =>
366
+ arr
367
+ .slice(0)
368
+ .reverse()
369
+ .forEach(callback);
370
+ const formatDuration = ms => {
371
+ if (ms < 0) ms = -ms;
372
+ const time = {
373
+ day: Math.floor(ms / 86400000),
374
+ hour: Math.floor(ms / 3600000) % 24,
375
+ minute: Math.floor(ms / 60000) % 60,
376
+ second: Math.floor(ms / 1000) % 60,
377
+ millisecond: Math.floor(ms) % 1000
378
+ };
379
+ return Object.entries(time)
380
+ .filter(val => val[1] !== 0)
381
+ .map(([key, val]) => `${val} ${key}${val !== 1 ? 's' : ''}`)
382
+ .join(', ');
383
+ };
384
+ const formToObject = form =>
385
+ Array.from(new FormData(form)).reduce(
386
+ (acc, [key, value]) => ({
387
+ ...acc,
388
+ [key]: value
389
+ }),
390
+ {}
391
+ );
392
+ const forOwn = (obj, fn) => Object.keys(obj).forEach(key => fn(obj[key], key, obj));
393
+ const forOwnRight = (obj, fn) =>
394
+ Object.keys(obj)
395
+ .reverse()
396
+ .forEach(key => fn(obj[key], key, obj));
397
+ const fromCamelCase = (str, separator = '_') =>
398
+ str
399
+ .replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2')
400
+ .replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2')
401
+ .toLowerCase();
402
+ const functionName = fn => (console.debug(fn.name), fn);
403
+ const functions = (obj, inherited = false) =>
404
+ (inherited
405
+ ? [...Object.keys(obj), ...Object.keys(Object.getPrototypeOf(obj))]
406
+ : Object.keys(obj)
407
+ ).filter(key => typeof obj[key] === 'function');
408
+ const gcd = (...arr) => {
409
+ const _gcd = (x, y) => (!y ? x : gcd(y, x % y));
410
+ return [...arr].reduce((a, b) => _gcd(a, b));
411
+ };
412
+ const geometricProgression = (end, start = 1, step = 2) =>
413
+ Array.from({ length: Math.floor(Math.log(end / start) / Math.log(step)) + 1 }).map(
414
+ (v, i) => start * step ** i
415
+ );
416
+ const get = (from, ...selectors) =>
417
+ [...selectors].map(s =>
418
+ s
419
+ .replace(/\[([^\[\]]*)\]/g, '.$1.')
420
+ .split('.')
421
+ .filter(t => t !== '')
422
+ .reduce((prev, cur) => prev && prev[cur], from)
423
+ );
424
+ const getColonTimeFromDate = date => date.toTimeString().slice(0, 8);
425
+ const getDaysDiffBetweenDates = (dateInitial, dateFinal) =>
426
+ (dateFinal - dateInitial) / (1000 * 3600 * 24);
427
+ const getImages = (el, includeDuplicates = false) => {
428
+ const images = [...el.getElementsByTagName('img')].map(img => img.getAttribute('src'));
429
+ return includeDuplicates ? images : [...new Set(images)];
430
+ };
431
+ const getMeridiemSuffixOfInteger = num =>
432
+ num === 0 || num === 24
433
+ ? 12 + 'am'
434
+ : num === 12
435
+ ? 12 + 'pm'
436
+ : num < 12
437
+ ? (num % 12) + 'am'
438
+ : (num % 12) + 'pm';
439
+ const getScrollPosition = (el = window) => ({
440
+ x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
441
+ y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
442
+ });
443
+ const getStyle = (el, ruleName) => getComputedStyle(el)[ruleName];
444
+ const getType = v =>
445
+ v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name.toLowerCase();
446
+ const getURLParameters = url =>
447
+ (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(
448
+ (a, v) => ((a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a),
449
+ {}
450
+ );
451
+ const groupBy = (arr, fn) =>
452
+ arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val, i) => {
453
+ acc[val] = (acc[val] || []).concat(arr[i]);
454
+ return acc;
455
+ }, {});
456
+ const hammingDistance = (num1, num2) => ((num1 ^ num2).toString(2).match(/1/g) || '').length;
457
+ const hasClass = (el, className) => el.classList.contains(className);
458
+ const hasFlags = (...flags) =>
459
+ flags.every(flag => process.argv.includes(/^-{1,2}/.test(flag) ? flag : '--' + flag));
460
+ const hashBrowser = val =>
461
+ crypto.subtle.digest('SHA-256', new TextEncoder('utf-8').encode(val)).then(h => {
462
+ let hexes = [],
463
+ view = new DataView(h);
464
+ for (let i = 0; i < view.byteLength; i += 4)
465
+ hexes.push(('00000000' + view.getUint32(i).toString(16)).slice(-8));
466
+ return hexes.join('');
467
+ });
468
+ const hashNode = val =>
469
+ new Promise(resolve =>
470
+ setTimeout(
471
+ () =>
472
+ resolve(
473
+ crypto
474
+ .createHash('sha256')
475
+ .update(val)
476
+ .digest('hex')
477
+ ),
478
+ 0
479
+ )
480
+ );
481
+ const head = arr => arr[0];
482
+ const hexToRGB = hex => {
483
+ let alpha = false,
484
+ h = hex.slice(hex.startsWith('#') ? 1 : 0);
485
+ if (h.length === 3) h = [...h].map(x => x + x).join('');
486
+ else if (h.length === 8) alpha = true;
487
+ h = parseInt(h, 16);
488
+ return (
489
+ 'rgb' +
490
+ (alpha ? 'a' : '') +
491
+ '(' +
492
+ (h >>> (alpha ? 24 : 16)) +
493
+ ', ' +
494
+ ((h & (alpha ? 0x00ff0000 : 0x00ff00)) >>> (alpha ? 16 : 8)) +
495
+ ', ' +
496
+ ((h & (alpha ? 0x0000ff00 : 0x0000ff)) >>> (alpha ? 8 : 0)) +
497
+ (alpha ? `, ${h & 0x000000ff}` : '') +
498
+ ')'
499
+ );
500
+ };
501
+ const hide = (...el) => [...el].forEach(e => (e.style.display = 'none'));
502
+ const httpGet = (url, callback, err = console.error) => {
503
+ const request = new XMLHttpRequest();
504
+ request.open('GET', url, true);
505
+ request.onload = () => callback(request.responseText);
506
+ request.onerror = () => err(request);
507
+ request.send();
508
+ };
509
+ const httpPost = (url, data, callback, err = console.error) => {
510
+ const request = new XMLHttpRequest();
511
+ request.open('POST', url, true);
512
+ request.setRequestHeader('Content-type', 'application/json; charset=utf-8');
513
+ request.onload = () => callback(request.responseText);
514
+ request.onerror = () => err(request);
515
+ request.send(data);
516
+ };
517
+ const httpsRedirect = () => {
518
+ if (location.protocol !== 'https:') location.replace('https://' + location.href.split('//')[1]);
519
+ };
520
+ const hz = (fn, iterations = 100) => {
521
+ const before = performance.now();
522
+ for (let i = 0; i < iterations; i++) fn();
523
+ return (1000 * iterations) / (performance.now() - before);
524
+ };
525
+ const indentString = (str, count, indent = ' ') => str.replace(/^/gm, indent.repeat(count));
526
+ const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);
527
+ const initial = arr => arr.slice(0, -1);
528
+ const initialize2DArray = (w, h, val = null) =>
529
+ Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val));
530
+ const initializeArrayWithRange = (end, start = 0, step = 1) =>
531
+ Array.from({ length: Math.ceil((end - start + 1) / step) }, (v, i) => i * step + start);
532
+ const initializeArrayWithRangeRight = (end, start = 0, step = 1) =>
533
+ Array.from({ length: Math.ceil((end + 1 - start) / step) }).map(
534
+ (v, i, arr) => (arr.length - i - 1) * step + start
535
+ );
536
+ const initializeArrayWithValues = (n, val = 0) => Array(n).fill(val);
537
+ const initializeNDArray = (val, ...args) =>
538
+ args.length === 0
539
+ ? val
540
+ : Array.from({ length: args[0] }).map(() => initializeNDArray(val, ...args.slice(1)));
541
+ const inRange = (n, start, end = null) => {
542
+ if (end && start > end) [end, start] = [start, end];
543
+ return end == null ? n >= 0 && n < start : n >= start && n < end;
544
+ };
545
+ const insertAfter = (el, htmlString) => el.insertAdjacentHTML('afterend', htmlString);
546
+ const insertBefore = (el, htmlString) => el.insertAdjacentHTML('beforebegin', htmlString);
547
+ const intersection = (a, b) => {
548
+ const s = new Set(b);
549
+ return a.filter(x => s.has(x));
550
+ };
551
+ const intersectionBy = (a, b, fn) => {
552
+ const s = new Set(b.map(fn));
553
+ return a.filter(x => s.has(fn(x)));
554
+ };
555
+ const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, y)) !== -1);
556
+ const invertKeyValues = (obj, fn) =>
557
+ Object.keys(obj).reduce((acc, key) => {
558
+ const val = fn ? fn(obj[key]) : obj[key];
559
+ acc[val] = acc[val] || [];
560
+ acc[val].push(key);
561
+ return acc;
562
+ }, {});
563
+ const is = (type, val) => ![, null].includes(val) && val.constructor === type;
564
+ const isAbsoluteURL = str => /^[a-z][a-z0-9+.-]*:/.test(str);
565
+ const isAfterDate = (dateA, dateB) => dateA > dateB;
566
+ const isAnagram = (str1, str2) => {
567
+ const normalize = str =>
568
+ str
569
+ .toLowerCase()
570
+ .replace(/[^a-z0-9]/gi, '')
571
+ .split('')
572
+ .sort()
573
+ .join('');
574
+ return normalize(str1) === normalize(str2);
575
+ };
576
+ const isArrayLike = obj => obj != null && typeof obj[Symbol.iterator] === 'function';
577
+ const isBeforeDate = (dateA, dateB) => dateA < dateB;
578
+ const isBoolean = val => typeof val === 'boolean';
579
+ const isBrowser = () => ![typeof window, typeof document].includes('undefined');
580
+ const isBrowserTabFocused = () => !document.hidden;
581
+ const isDivisible = (dividend, divisor) => dividend % divisor === 0;
582
+ const isDuplexStream = val =>
583
+ val !== null &&
584
+ typeof val === 'object' &&
585
+ typeof val.pipe === 'function' &&
586
+ typeof val._read === 'function' &&
587
+ typeof val._readableState === 'object' &&
588
+ typeof val._write === 'function' &&
589
+ typeof val._writableState === 'object';
590
+ const isEmpty = val => val == null || !(Object.keys(val) || val).length;
591
+ const isEven = num => num % 2 === 0;
592
+ const isFunction = val => typeof val === 'function';
593
+ const isLowerCase = str => str === str.toLowerCase();
594
+ const isNegativeZero = val => val === 0 && 1 / val === -Infinity;
595
+ const isNil = val => val === undefined || val === null;
596
+ const isNull = val => val === null;
597
+ const isNumber = val => typeof val === 'number' && val === val;
598
+ const isObject = obj => obj === Object(obj);
599
+ const isObjectLike = val => val !== null && typeof val === 'object';
600
+ const isPlainObject = val => !!val && typeof val === 'object' && val.constructor === Object;
601
+ const isPrime = num => {
602
+ const boundary = Math.floor(Math.sqrt(num));
603
+ for (var i = 2; i <= boundary; i++) if (num % i === 0) return false;
604
+ return num >= 2;
605
+ };
606
+ const isPrimitive = val => Object(val) !== val;
607
+ const isPromiseLike = obj =>
608
+ obj !== null &&
609
+ (typeof obj === 'object' || typeof obj === 'function') &&
610
+ typeof obj.then === 'function';
611
+ const isReadableStream = val =>
612
+ val !== null &&
613
+ typeof val === 'object' &&
614
+ typeof val.pipe === 'function' &&
615
+ typeof val._read === 'function' &&
616
+ typeof val._readableState === 'object';
617
+ const isSameDate = (dateA, dateB) => dateA.toISOString() === dateB.toISOString();
618
+ const isSorted = arr => {
619
+ let direction = -(arr[0] - arr[1]);
620
+ for (let [i, val] of arr.entries()) {
621
+ direction = !direction ? -(arr[i - 1] - arr[i]) : direction;
622
+ if (i === arr.length - 1) return !direction ? 0 : direction;
623
+ else if ((val - arr[i + 1]) * direction > 0) return 0;
624
+ }
625
+ };
626
+ const isStream = val => val !== null && typeof val === 'object' && typeof val.pipe === 'function';
627
+ const isString = val => typeof val === 'string';
628
+ const isSymbol = val => typeof val === 'symbol';
629
+ const isTravisCI = () => 'TRAVIS' in process.env && 'CI' in process.env;
630
+ const isUndefined = val => val === undefined;
631
+ const isUpperCase = str => str === str.toUpperCase();
632
+ const isValidJSON = str => {
633
+ try {
634
+ JSON.parse(str);
635
+ return true;
636
+ } catch (e) {
637
+ return false;
638
+ }
639
+ };
640
+ const isWeekday = (t = new Date()) => {
641
+ return t.getDay() % 6 !== 0;
642
+ };
643
+ const isWeekend = (t = new Date()) => {
644
+ return t.getDay() % 6 === 0;
645
+ };
646
+ const isWritableStream = val =>
647
+ val !== null &&
648
+ typeof val === 'object' &&
649
+ typeof val.pipe === 'function' &&
650
+ typeof val._write === 'function' &&
651
+ typeof val._writableState === 'object';
652
+ const join = (arr, separator = ',', end = separator) =>
653
+ arr.reduce(
654
+ (acc, val, i) =>
655
+ i === arr.length - 2
656
+ ? acc + val + end
657
+ : i === arr.length - 1
658
+ ? acc + val
659
+ : acc + val + separator,
660
+ ''
661
+ );
662
+ const JSONtoCSV = (arr, columns, delimiter = ',') =>
663
+ [
664
+ columns.join(delimiter),
665
+ ...arr.map(obj =>
666
+ columns.reduce(
667
+ (acc, key) => `${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`,
668
+ ''
669
+ )
670
+ )
671
+ ].join('\n');
672
+ const JSONToFile = (obj, filename) =>
673
+ fs.writeFile(`${filename}.json`, JSON.stringify(obj, null, 2));
674
+ const last = arr => arr[arr.length - 1];
675
+ const lcm = (...arr) => {
676
+ const gcd = (x, y) => (!y ? x : gcd(y, x % y));
677
+ const _lcm = (x, y) => (x * y) / gcd(x, y);
678
+ return [...arr].reduce((a, b) => _lcm(a, b));
679
+ };
680
+ const longestItem = (...vals) => vals.reduce((a, x) => (x.length > a.length ? x : a));
681
+ const lowercaseKeys = obj =>
682
+ Object.keys(obj).reduce((acc, key) => {
683
+ acc[key.toLowerCase()] = obj[key];
684
+ return acc;
685
+ }, {});
686
+ const luhnCheck = num => {
687
+ let arr = (num + '')
688
+ .split('')
689
+ .reverse()
690
+ .map(x => parseInt(x));
691
+ let lastDigit = arr.splice(0, 1)[0];
692
+ let sum = arr.reduce((acc, val, i) => (i % 2 !== 0 ? acc + val : acc + ((val * 2) % 9) || 9), 0);
693
+ sum += lastDigit;
694
+ return sum % 10 === 0;
695
+ };
696
+ const mapKeys = (obj, fn) =>
697
+ Object.keys(obj).reduce((acc, k) => {
698
+ acc[fn(obj[k], k, obj)] = obj[k];
699
+ return acc;
700
+ }, {});
701
+ const mapNumRange = (num, inMin, inMax, outMin, outMax) =>
702
+ ((num - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
703
+ const mapObject = (arr, fn) =>
704
+ (a => (
705
+ (a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {})
706
+ ))();
707
+ const mapString = (str, fn) =>
708
+ str
709
+ .split('')
710
+ .map((c, i) => fn(c, i, str))
711
+ .join('');
712
+ const mapValues = (obj, fn) =>
713
+ Object.keys(obj).reduce((acc, k) => {
714
+ acc[k] = fn(obj[k], k, obj);
715
+ return acc;
716
+ }, {});
717
+ const mask = (cc, num = 4, mask = '*') => `${cc}`.slice(-num).padStart(`${cc}`.length, mask);
718
+ const matches = (obj, source) =>
719
+ Object.keys(source).every(key => obj.hasOwnProperty(key) && obj[key] === source[key]);
720
+ const matchesWith = (obj, source, fn) =>
721
+ Object.keys(source).every(key =>
722
+ obj.hasOwnProperty(key) && fn
723
+ ? fn(obj[key], source[key], key, obj, source)
724
+ : obj[key] == source[key]
725
+ );
726
+ const maxBy = (arr, fn) => Math.max(...arr.map(typeof fn === 'function' ? fn : val => val[fn]));
727
+ const maxDate = dates => new Date(Math.max(...dates));
728
+ const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n);
729
+ const median = arr => {
730
+ const mid = Math.floor(arr.length / 2),
731
+ nums = [...arr].sort((a, b) => a - b);
732
+ return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
733
+ };
734
+ const memoize = fn => {
735
+ const cache = new Map();
736
+ const cached = function(val) {
737
+ return cache.has(val) ? cache.get(val) : cache.set(val, fn.call(this, val)) && cache.get(val);
738
+ };
739
+ cached.cache = cache;
740
+ return cached;
741
+ };
742
+ const merge = (...objs) =>
743
+ [...objs].reduce(
744
+ (acc, obj) =>
745
+ Object.keys(obj).reduce((a, k) => {
746
+ acc[k] = acc.hasOwnProperty(k) ? [].concat(acc[k]).concat(obj[k]) : obj[k];
747
+ return acc;
748
+ }, {}),
749
+ {}
750
+ );
751
+ const midpoint = ([x1, y1], [x2, y2]) => [(x1 + x2) / 2, (y1 + y2) / 2];
752
+ const minBy = (arr, fn) => Math.min(...arr.map(typeof fn === 'function' ? fn : val => val[fn]));
753
+ const minDate = dates => new Date(Math.min(...dates));
754
+ const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n);
755
+ const mostPerformant = (fns, iterations = 10000) => {
756
+ const times = fns.map(fn => {
757
+ const before = performance.now();
758
+ for (let i = 0; i < iterations; i++) fn();
759
+ return performance.now() - before;
760
+ });
761
+ return times.indexOf(Math.min(...times));
762
+ };
763
+ const negate = func => (...args) => !func(...args);
764
+ const nest = (items, id = null, link = 'parent_id') =>
765
+ items
766
+ .filter(item => item[link] === id)
767
+ .map(item => ({ ...item, children: nest(items, item.id) }));
768
+ const nodeListToArray = nodeList => [...nodeList];
769
+ const none = (arr, fn = Boolean) => !arr.some(fn);
770
+ const nthArg = n => (...args) => args.slice(n)[0];
771
+ const nthElement = (arr, n = 0) => (n === -1 ? arr.slice(n) : arr.slice(n, n + 1))[0];
772
+ const objectFromPairs = arr => arr.reduce((a, [key, val]) => ((a[key] = val), a), {});
773
+ const objectToPairs = obj => Object.keys(obj).map(k => [k, obj[k]]);
774
+ const observeMutations = (element, callback, options) => {
775
+ const observer = new MutationObserver(mutations => mutations.forEach(m => callback(m)));
776
+ observer.observe(
777
+ element,
778
+ Object.assign(
779
+ {
780
+ childList: true,
781
+ attributes: true,
782
+ attributeOldValue: true,
783
+ characterData: true,
784
+ characterDataOldValue: true,
785
+ subtree: true
786
+ },
787
+ options
788
+ )
789
+ );
790
+ return observer;
791
+ };
792
+ const off = (el, evt, fn, opts = false) => el.removeEventListener(evt, fn, opts);
793
+ const offset = (arr, offset) => [...arr.slice(offset), ...arr.slice(0, offset)];
794
+ const omit = (obj, arr) =>
795
+ Object.keys(obj)
796
+ .filter(k => !arr.includes(k))
797
+ .reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
798
+ const omitBy = (obj, fn) =>
799
+ Object.keys(obj)
800
+ .filter(k => !fn(obj[k], k))
801
+ .reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
802
+ const on = (el, evt, fn, opts = {}) => {
803
+ const delegatorFn = e => e.target.matches(opts.target) && fn.call(e.target, e);
804
+ el.addEventListener(evt, opts.target ? delegatorFn : fn, opts.options || false);
805
+ if (opts.target) return delegatorFn;
806
+ };
807
+ const once = fn => {
808
+ let called = false;
809
+ return function(...args) {
810
+ if (called) return;
811
+ called = true;
812
+ return fn.apply(this, args);
813
+ };
814
+ };
815
+ const onUserInputChange = callback => {
816
+ let type = 'mouse',
817
+ lastTime = 0;
818
+ const mousemoveHandler = () => {
819
+ const now = performance.now();
820
+ if (now - lastTime < 20)
821
+ (type = 'mouse'), callback(type), document.removeEventListener('mousemove', mousemoveHandler);
822
+ lastTime = now;
823
+ };
824
+ document.addEventListener('touchstart', () => {
825
+ if (type === 'touch') return;
826
+ (type = 'touch'), callback(type), document.addEventListener('mousemove', mousemoveHandler);
827
+ });
828
+ };
829
+ const orderBy = (arr, props, orders) =>
830
+ [...arr].sort((a, b) =>
831
+ props.reduce((acc, prop, i) => {
832
+ if (acc === 0) {
833
+ const [p1, p2] = orders && orders[i] === 'desc' ? [b[prop], a[prop]] : [a[prop], b[prop]];
834
+ acc = p1 > p2 ? 1 : p1 < p2 ? -1 : 0;
835
+ }
836
+ return acc;
837
+ }, 0)
838
+ );
839
+ const over = (...fns) => (...args) => fns.map(fn => fn.apply(null, args));
840
+ const overArgs = (fn, transforms) => (...args) => fn(...args.map((val, i) => transforms[i](val)));
841
+ const pad = (str, length, char = ' ') =>
842
+ str.padStart((str.length + length) / 2, char).padEnd(length, char);
843
+ const palindrome = str => {
844
+ const s = str.toLowerCase().replace(/[\W_]/g, '');
845
+ return s === [...s].reverse().join('');
846
+ };
847
+ const parseCookie = str =>
848
+ str
849
+ .split(';')
850
+ .map(v => v.split('='))
851
+ .reduce((acc, v) => {
852
+ acc[decodeURIComponent(v[0].trim())] = decodeURIComponent(v[1].trim());
853
+ return acc;
854
+ }, {});
855
+ const partial = (fn, ...partials) => (...args) => fn(...partials, ...args);
856
+ const partialRight = (fn, ...partials) => (...args) => fn(...args, ...partials);
857
+ const partition = (arr, fn) =>
858
+ arr.reduce(
859
+ (acc, val, i, arr) => {
860
+ acc[fn(val, i, arr) ? 0 : 1].push(val);
861
+ return acc;
862
+ },
863
+ [[], []]
864
+ );
865
+ const percentile = (arr, val) =>
866
+ (100 * arr.reduce((acc, v) => acc + (v < val ? 1 : 0) + (v === val ? 0.5 : 0), 0)) / arr.length;
867
+ const permutations = arr => {
868
+ if (arr.length <= 2) return arr.length === 2 ? [arr, [arr[1], arr[0]]] : arr;
869
+ return arr.reduce(
870
+ (acc, item, i) =>
871
+ acc.concat(
872
+ permutations([...arr.slice(0, i), ...arr.slice(i + 1)]).map(val => [item, ...val])
873
+ ),
874
+ []
875
+ );
876
+ };
877
+ const pick = (obj, arr) =>
878
+ arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {});
879
+ const pickBy = (obj, fn) =>
880
+ Object.keys(obj)
881
+ .filter(k => fn(obj[k], k))
882
+ .reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
883
+ const pipeAsyncFunctions = (...fns) => arg => fns.reduce((p, f) => p.then(f), Promise.resolve(arg));
884
+ const pipeFunctions = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));
885
+ const pluralize = (val, word, plural = word + 's') => {
886
+ const _pluralize = (num, word, plural = word + 's') =>
887
+ [1, -1].includes(Number(num)) ? word : plural;
888
+ if (typeof val === 'object') return (num, word) => _pluralize(num, word, val[word]);
889
+ return _pluralize(val, word, plural);
890
+ };
891
+ const powerset = arr => arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]);
892
+ const prefix = prop => {
893
+ const capitalizedProp = prop.charAt(0).toUpperCase() + prop.slice(1);
894
+ const prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
895
+ const i = prefixes.findIndex(
896
+ prefix => typeof document.body.style[prefix ? prefix + capitalizedProp : prop] !== 'undefined'
897
+ );
898
+ return i !== -1 ? (i === 0 ? prop : prefixes[i] + capitalizedProp) : null;
899
+ };
900
+ const prettyBytes = (num, precision = 3, addSpace = true) => {
901
+ const UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
902
+ if (Math.abs(num) < 1) return num + (addSpace ? ' ' : '') + UNITS[0];
903
+ const exponent = Math.min(Math.floor(Math.log10(num < 0 ? -num : num) / 3), UNITS.length - 1);
904
+ const n = Number(((num < 0 ? -num : num) / 1000 ** exponent).toPrecision(precision));
905
+ return (num < 0 ? '-' : '') + n + (addSpace ? ' ' : '') + UNITS[exponent];
906
+ };
907
+ const primes = num => {
908
+ let arr = Array.from({ length: num - 1 }).map((x, i) => i + 2),
909
+ sqroot = Math.floor(Math.sqrt(num)),
910
+ numsTillSqroot = Array.from({ length: sqroot - 1 }).map((x, i) => i + 2);
911
+ numsTillSqroot.forEach(x => (arr = arr.filter(y => y % x !== 0 || y === x)));
912
+ return arr;
913
+ };
914
+ const promisify = func => (...args) =>
915
+ new Promise((resolve, reject) =>
916
+ func(...args, (err, result) => (err ? reject(err) : resolve(result)))
917
+ );
918
+ const pull = (arr, ...args) => {
919
+ let argState = Array.isArray(args[0]) ? args[0] : args;
920
+ let pulled = arr.filter((v, i) => !argState.includes(v));
921
+ arr.length = 0;
922
+ pulled.forEach(v => arr.push(v));
923
+ };
924
+ const pullAtIndex = (arr, pullArr) => {
925
+ let removed = [];
926
+ let pulled = arr
927
+ .map((v, i) => (pullArr.includes(i) ? removed.push(v) : v))
928
+ .filter((v, i) => !pullArr.includes(i));
929
+ arr.length = 0;
930
+ pulled.forEach(v => arr.push(v));
931
+ return removed;
932
+ };
933
+ const pullAtValue = (arr, pullArr) => {
934
+ let removed = [],
935
+ pushToRemove = arr.forEach((v, i) => (pullArr.includes(v) ? removed.push(v) : v)),
936
+ mutateTo = arr.filter((v, i) => !pullArr.includes(v));
937
+ arr.length = 0;
938
+ mutateTo.forEach(v => arr.push(v));
939
+ return removed;
940
+ };
941
+ const pullBy = (arr, ...args) => {
942
+ const length = args.length;
943
+ let fn = length > 1 ? args[length - 1] : undefined;
944
+ fn = typeof fn == 'function' ? (args.pop(), fn) : undefined;
945
+ let argState = (Array.isArray(args[0]) ? args[0] : args).map(val => fn(val));
946
+ let pulled = arr.filter((v, i) => !argState.includes(fn(v)));
947
+ arr.length = 0;
948
+ pulled.forEach(v => arr.push(v));
949
+ };
950
+ const radsToDegrees = rad => (rad * 180.0) / Math.PI;
951
+ const randomHexColorCode = () => {
952
+ let n = (Math.random() * 0xfffff * 1000000).toString(16);
953
+ return '#' + n.slice(0, 6);
954
+ };
955
+ const randomIntArrayInRange = (min, max, n = 1) =>
956
+ Array.from({ length: n }, () => Math.floor(Math.random() * (max - min + 1)) + min);
957
+ const randomIntegerInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
958
+ const randomNumberInRange = (min, max) => Math.random() * (max - min) + min;
959
+ const readFileLines = filename =>
960
+ fs
961
+ .readFileSync(filename)
962
+ .toString('UTF8')
963
+ .split('\n');
964
+ const rearg = (fn, indexes) => (...args) => fn(...indexes.map(i => args[i]));
965
+ const recordAnimationFrames = (callback, autoStart = true) => {
966
+ let running = true,
967
+ raf;
968
+ const stop = () => {
969
+ running = false;
970
+ cancelAnimationFrame(raf);
971
+ };
972
+ const start = () => {
973
+ running = true;
974
+ run();
975
+ };
976
+ const run = () => {
977
+ raf = requestAnimationFrame(() => {
978
+ callback();
979
+ if (running) run();
980
+ });
981
+ };
982
+ if (autoStart) start();
983
+ return { start, stop };
984
+ };
985
+ const redirect = (url, asLink = true) =>
986
+ asLink ? (window.location.href = url) : window.location.replace(url);
987
+ const reducedFilter = (data, keys, fn) =>
988
+ data.filter(fn).map(el =>
989
+ keys.reduce((acc, key) => {
990
+ acc[key] = el[key];
991
+ return acc;
992
+ }, {})
993
+ );
994
+ const reduceSuccessive = (arr, fn, acc) =>
995
+ arr.reduce((res, val, i, arr) => (res.push(fn(res.slice(-1)[0], val, i, arr)), res), [acc]);
996
+ const reduceWhich = (arr, comparator = (a, b) => a - b) =>
997
+ arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a));
998
+ const reject = (pred, array) => array.filter((...args) => !pred(...args));
999
+ const remove = (arr, func) =>
1000
+ Array.isArray(arr)
1001
+ ? arr.filter(func).reduce((acc, val) => {
1002
+ arr.splice(arr.indexOf(val), 1);
1003
+ return acc.concat(val);
1004
+ }, [])
1005
+ : [];
1006
+ const removeNonASCII = str => str.replace(/[^\x20-\x7E]/g, '');
1007
+ const renameKeys = (keysMap, obj) =>
1008
+ Object.keys(obj).reduce(
1009
+ (acc, key) => ({
1010
+ ...acc,
1011
+ ...{ [keysMap[key] || key]: obj[key] }
1012
+ }),
1013
+ {}
1014
+ );
1015
+ const reverseString = str => [...str].reverse().join('');
1016
+ const RGBToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0');
1017
+ const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);
1018
+ const runAsync = fn => {
1019
+ const worker = new Worker(
1020
+ URL.createObjectURL(new Blob([`postMessage((${fn})());`]), {
1021
+ type: 'application/javascript; charset=utf-8'
1022
+ })
1023
+ );
1024
+ return new Promise((res, rej) => {
1025
+ worker.onmessage = ({ data }) => {
1026
+ res(data), worker.terminate();
1027
+ };
1028
+ worker.onerror = err => {
1029
+ rej(err), worker.terminate();
1030
+ };
1031
+ });
1032
+ };
1033
+ const runPromisesInSeries = ps => ps.reduce((p, next) => p.then(next), Promise.resolve());
1034
+ const sample = arr => arr[Math.floor(Math.random() * arr.length)];
1035
+ const sampleSize = ([...arr], n = 1) => {
1036
+ let m = arr.length;
1037
+ while (m) {
1038
+ const i = Math.floor(Math.random() * m--);
1039
+ [arr[m], arr[i]] = [arr[i], arr[m]];
1040
+ }
1041
+ return arr.slice(0, n);
1042
+ };
1043
+ const scrollToTop = () => {
1044
+ const c = document.documentElement.scrollTop || document.body.scrollTop;
1045
+ if (c > 0) {
1046
+ window.requestAnimationFrame(scrollToTop);
1047
+ window.scrollTo(0, c - c / 8);
1048
+ }
1049
+ };
1050
+ const sdbm = str => {
1051
+ let arr = str.split('');
1052
+ return arr.reduce(
1053
+ (hashCode, currentVal) =>
1054
+ (hashCode = currentVal.charCodeAt(0) + (hashCode << 6) + (hashCode << 16) - hashCode),
1055
+ 0
1056
+ );
1057
+ };
1058
+ const serializeCookie = (name, val) => `${encodeURIComponent(name)}=${encodeURIComponent(val)}`;
1059
+ const serializeForm = form =>
1060
+ Array.from(new FormData(form), field => field.map(encodeURIComponent).join('=')).join('&');
1061
+ const setStyle = (el, ruleName, val) => (el.style[ruleName] = val);
1062
+ const shallowClone = obj => Object.assign({}, obj);
1063
+ const shank = (arr, index = 0, delCount = 0, ...elements) =>
1064
+ arr
1065
+ .slice(0, index)
1066
+ .concat(elements)
1067
+ .concat(arr.slice(index + delCount));
1068
+ const show = (...el) => [...el].forEach(e => (e.style.display = ''));
1069
+ const shuffle = ([...arr]) => {
1070
+ let m = arr.length;
1071
+ while (m) {
1072
+ const i = Math.floor(Math.random() * m--);
1073
+ [arr[m], arr[i]] = [arr[i], arr[m]];
1074
+ }
1075
+ return arr;
1076
+ };
1077
+ const similarity = (arr, values) => arr.filter(v => values.includes(v));
1078
+ const size = val =>
1079
+ Array.isArray(val)
1080
+ ? val.length
1081
+ : val && typeof val === 'object'
1082
+ ? val.size || val.length || Object.keys(val).length
1083
+ : typeof val === 'string'
1084
+ ? new Blob([val]).size
1085
+ : 0;
1086
+ const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
1087
+ const smoothScroll = element =>
1088
+ document.querySelector(element).scrollIntoView({
1089
+ behavior: 'smooth'
1090
+ });
1091
+ const sortCharactersInString = str => [...str].sort((a, b) => a.localeCompare(b)).join('');
1092
+ const sortedIndex = (arr, n) => {
1093
+ const isDescending = arr[0] > arr[arr.length - 1];
1094
+ const index = arr.findIndex(el => (isDescending ? n >= el : n <= el));
1095
+ return index === -1 ? arr.length : index;
1096
+ };
1097
+ const sortedIndexBy = (arr, n, fn) => {
1098
+ const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
1099
+ const val = fn(n);
1100
+ const index = arr.findIndex(el => (isDescending ? val >= fn(el) : val <= fn(el)));
1101
+ return index === -1 ? arr.length : index;
1102
+ };
1103
+ const sortedLastIndex = (arr, n) => {
1104
+ const isDescending = arr[0] > arr[arr.length - 1];
1105
+ const index = arr.reverse().findIndex(el => (isDescending ? n <= el : n >= el));
1106
+ return index === -1 ? 0 : arr.length - index;
1107
+ };
1108
+ const sortedLastIndexBy = (arr, n, fn) => {
1109
+ const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
1110
+ const val = fn(n);
1111
+ const index = arr
1112
+ .map(fn)
1113
+ .reverse()
1114
+ .findIndex(el => (isDescending ? val <= el : val >= el));
1115
+ return index === -1 ? 0 : arr.length - index;
1116
+ };
1117
+ const splitLines = str => str.split(/\r?\n/);
1118
+ const spreadOver = fn => argsArr => fn(...argsArr);
1119
+ const stableSort = (arr, compare) =>
1120
+ arr
1121
+ .map((item, index) => ({ item, index }))
1122
+ .sort((a, b) => compare(a.item, b.item) || a.index - b.index)
1123
+ .map(({ item }) => item);
1124
+ const standardDeviation = (arr, usePopulation = false) => {
1125
+ const mean = arr.reduce((acc, val) => acc + val, 0) / arr.length;
1126
+ return Math.sqrt(
1127
+ arr.reduce((acc, val) => acc.concat((val - mean) ** 2), []).reduce((acc, val) => acc + val, 0) /
1128
+ (arr.length - (usePopulation ? 0 : 1))
1129
+ );
1130
+ };
1131
+ const stringPermutations = str => {
1132
+ if (str.length <= 2) return str.length === 2 ? [str, str[1] + str[0]] : [str];
1133
+ return str
1134
+ .split('')
1135
+ .reduce(
1136
+ (acc, letter, i) =>
1137
+ acc.concat(stringPermutations(str.slice(0, i) + str.slice(i + 1)).map(val => letter + val)),
1138
+ []
1139
+ );
1140
+ };
1141
+ const stripHTMLTags = str => str.replace(/<[^>]*>/g, '');
1142
+ const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0);
1143
+ const sumBy = (arr, fn) =>
1144
+ arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0);
1145
+ const sumPower = (end, power = 2, start = 1) =>
1146
+ Array(end + 1 - start)
1147
+ .fill(0)
1148
+ .map((x, i) => (i + start) ** power)
1149
+ .reduce((a, b) => a + b, 0);
1150
+ const symmetricDifference = (a, b) => {
1151
+ const sA = new Set(a),
1152
+ sB = new Set(b);
1153
+ return [...a.filter(x => !sB.has(x)), ...b.filter(x => !sA.has(x))];
1154
+ };
1155
+ const symmetricDifferenceBy = (a, b, fn) => {
1156
+ const sA = new Set(a.map(v => fn(v))),
1157
+ sB = new Set(b.map(v => fn(v)));
1158
+ return [...a.filter(x => !sB.has(fn(x))), ...b.filter(x => !sA.has(fn(x)))];
1159
+ };
1160
+ const symmetricDifferenceWith = (arr, val, comp) => [
1161
+ ...arr.filter(a => val.findIndex(b => comp(a, b)) === -1),
1162
+ ...val.filter(a => arr.findIndex(b => comp(a, b)) === -1)
1163
+ ];
1164
+ const tail = arr => (arr.length > 1 ? arr.slice(1) : arr);
1165
+ const take = (arr, n = 1) => arr.slice(0, n);
1166
+ const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length);
1167
+ const takeRightWhile = (arr, func) =>
1168
+ arr.reduceRight((acc, el) => (func(el) ? acc : [el, ...acc]), []);
1169
+ const takeWhile = (arr, func) => {
1170
+ for (const [i, val] of arr.entries()) if (func(val)) return arr.slice(0, i);
1171
+ return arr;
1172
+ };
1173
+ const throttle = (fn, wait) => {
1174
+ let inThrottle, lastFn, lastTime;
1175
+ return function() {
1176
+ const context = this,
1177
+ args = arguments;
1178
+ if (!inThrottle) {
1179
+ fn.apply(context, args);
1180
+ lastTime = Date.now();
1181
+ inThrottle = true;
1182
+ } else {
1183
+ clearTimeout(lastFn);
1184
+ lastFn = setTimeout(function() {
1185
+ if (Date.now() - lastTime >= wait) {
1186
+ fn.apply(context, args);
1187
+ lastTime = Date.now();
1188
+ }
1189
+ }, Math.max(wait - (Date.now() - lastTime), 0));
1190
+ }
1191
+ };
1192
+ };
1193
+ const times = (n, fn, context = undefined) => {
1194
+ let i = 0;
1195
+ while (fn.call(context, i) !== false && ++i < n) {}
1196
+ };
1197
+ const timeTaken = callback => {
1198
+ console.time('timeTaken');
1199
+ const r = callback();
1200
+ console.timeEnd('timeTaken');
1201
+ return r;
1202
+ };
1203
+ const toCamelCase = str => {
1204
+ let s =
1205
+ str &&
1206
+ str
1207
+ .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
1208
+ .map(x => x.slice(0, 1).toUpperCase() + x.slice(1).toLowerCase())
1209
+ .join('');
1210
+ return s.slice(0, 1).toLowerCase() + s.slice(1);
1211
+ };
1212
+ const toCurrency = (n, curr, LanguageFormat = undefined) =>
1213
+ Intl.NumberFormat(LanguageFormat, { style: 'currency', currency: curr }).format(n);
1214
+ const toDecimalMark = num => num.toLocaleString('en-US');
1215
+ const toggleClass = (el, className) => el.classList.toggle(className);
1216
+ const toHash = (object, key) =>
1217
+ Array.prototype.reduce.call(
1218
+ object,
1219
+ (acc, data, index) => ((acc[!key ? index : data[key]] = data), acc),
1220
+ {}
1221
+ );
1222
+ const toKebabCase = str =>
1223
+ str &&
1224
+ str
1225
+ .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
1226
+ .map(x => x.toLowerCase())
1227
+ .join('-');
1228
+ const tomorrow = () => {
1229
+ let t = new Date();
1230
+ t.setDate(t.getDate() + 1);
1231
+ return t.toISOString().split('T')[0];
1232
+ };
1233
+ const toOrdinalSuffix = num => {
1234
+ const int = parseInt(num),
1235
+ digits = [int % 10, int % 100],
1236
+ ordinals = ['st', 'nd', 'rd', 'th'],
1237
+ oPattern = [1, 2, 3, 4],
1238
+ tPattern = [11, 12, 13, 14, 15, 16, 17, 18, 19];
1239
+ return oPattern.includes(digits[0]) && !tPattern.includes(digits[1])
1240
+ ? int + ordinals[digits[0] - 1]
1241
+ : int + ordinals[3];
1242
+ };
1243
+ const toSafeInteger = num =>
1244
+ Math.round(Math.max(Math.min(num, Number.MAX_SAFE_INTEGER), Number.MIN_SAFE_INTEGER));
1245
+ const toSnakeCase = str =>
1246
+ str &&
1247
+ str
1248
+ .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
1249
+ .map(x => x.toLowerCase())
1250
+ .join('_');
1251
+ const toTitleCase = str =>
1252
+ str
1253
+ .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
1254
+ .map(x => x.charAt(0).toUpperCase() + x.slice(1))
1255
+ .join(' ');
1256
+ const transform = (obj, fn, acc) => Object.keys(obj).reduce((a, k) => fn(a, obj[k], k, obj), acc);
1257
+ const triggerEvent = (el, eventType, detail) =>
1258
+ el.dispatchEvent(new CustomEvent(eventType, { detail }));
1259
+ const truncateString = (str, num) =>
1260
+ str.length > num ? str.slice(0, num > 3 ? num - 3 : num) + '...' : str;
1261
+ const truthCheckCollection = (collection, pre) => collection.every(obj => obj[pre]);
1262
+ const unary = fn => val => fn(val);
1263
+ const uncurry = (fn, n = 1) => (...args) => {
1264
+ const next = acc => args => args.reduce((x, y) => x(y), acc);
1265
+ if (n > args.length) throw new RangeError('Arguments too few!');
1266
+ return next(fn)(args.slice(0, n));
1267
+ };
1268
+ const unescapeHTML = str =>
1269
+ str.replace(
1270
+ /&amp;|&lt;|&gt;|&#39;|&quot;/g,
1271
+ tag =>
1272
+ ({
1273
+ '&amp;': '&',
1274
+ '&lt;': '<',
1275
+ '&gt;': '>',
1276
+ '&#39;': "'",
1277
+ '&quot;': '"'
1278
+ }[tag] || tag)
1279
+ );
1280
+ const unflattenObject = obj =>
1281
+ Object.keys(obj).reduce((acc, k) => {
1282
+ if (k.indexOf('.') !== -1) {
1283
+ const keys = k.split('.');
1284
+ Object.assign(
1285
+ acc,
1286
+ JSON.parse(
1287
+ '{' +
1288
+ keys.map((v, i) => (i !== keys.length - 1 ? `"${v}":{` : `"${v}":`)).join('') +
1289
+ obj[k] +
1290
+ '}'.repeat(keys.length)
1291
+ )
1292
+ );
1293
+ } else acc[k] = obj[k];
1294
+ return acc;
1295
+ }, {});
1296
+ const unfold = (fn, seed) => {
1297
+ let result = [],
1298
+ val = [null, seed];
1299
+ while ((val = fn(val[1]))) result.push(val[0]);
1300
+ return result;
1301
+ };
1302
+ const union = (a, b) => Array.from(new Set([...a, ...b]));
1303
+ const unionBy = (a, b, fn) => {
1304
+ const s = new Set(a.map(fn));
1305
+ return Array.from(new Set([...a, ...b.filter(x => !s.has(fn(x)))]));
1306
+ };
1307
+ const unionWith = (a, b, comp) =>
1308
+ Array.from(new Set([...a, ...b.filter(x => a.findIndex(y => comp(x, y)) === -1)]));
1309
+ const uniqueElements = arr => [...new Set(arr)];
1310
+ const uniqueElementsBy = (arr, fn) =>
1311
+ arr.reduce((acc, v) => {
1312
+ if (!acc.some(x => fn(v, x))) acc.push(v);
1313
+ return acc;
1314
+ }, []);
1315
+ const uniqueElementsByRight = (arr, fn) =>
1316
+ arr.reduceRight((acc, v) => {
1317
+ if (!acc.some(x => fn(v, x))) acc.push(v);
1318
+ return acc;
1319
+ }, []);
1320
+ const uniqueSymmetricDifference = (a, b) => [
1321
+ ...new Set([...a.filter(v => !b.includes(v)), ...b.filter(v => !a.includes(v))])
1322
+ ];
1323
+ const untildify = str => str.replace(/^~($|\/|\\)/, `${require('os').homedir()}$1`);
1324
+ const unzip = arr =>
1325
+ arr.reduce(
1326
+ (acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc),
1327
+ Array.from({
1328
+ length: Math.max(...arr.map(x => x.length))
1329
+ }).map(x => [])
1330
+ );
1331
+ const unzipWith = (arr, fn) =>
1332
+ arr
1333
+ .reduce(
1334
+ (acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc),
1335
+ Array.from({
1336
+ length: Math.max(...arr.map(x => x.length))
1337
+ }).map(x => [])
1338
+ )
1339
+ .map(val => fn(...val));
1340
+ const URLJoin = (...args) =>
1341
+ args
1342
+ .join('/')
1343
+ .replace(/[\/]+/g, '/')
1344
+ .replace(/^(.+):\//, '$1://')
1345
+ .replace(/^file:/, 'file:/')
1346
+ .replace(/\/(\?|&|#[^!])/g, '$1')
1347
+ .replace(/\?/g, '&')
1348
+ .replace('&', '?');
1349
+ const UUIDGeneratorBrowser = () =>
1350
+ ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
1351
+ (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
1352
+ );
1353
+ const UUIDGeneratorNode = () =>
1354
+ ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
1355
+ (c ^ (crypto.randomBytes(1)[0] & (15 >> (c / 4)))).toString(16)
1356
+ );
1357
+ const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n;
1358
+ const vectorDistance = (...coords) => {
1359
+ let pointLength = Math.trunc(coords.length / 2);
1360
+ let sum = coords
1361
+ .slice(0, pointLength)
1362
+ .reduce((acc, val, i) => acc + Math.pow(val - coords[pointLength + i], 2), 0);
1363
+ return Math.sqrt(sum);
1364
+ };
1365
+ const when = (pred, whenTrue) => x => (pred(x) ? whenTrue(x) : x);
1366
+ const without = (arr, ...args) => arr.filter(v => !args.includes(v));
1367
+ const words = (str, pattern = /[^a-zA-Z-]+/) => str.split(pattern).filter(Boolean);
1368
+ const xProd = (a, b) => a.reduce((acc, x) => acc.concat(b.map(y => [x, y])), []);
1369
+ const yesNo = (val, def = false) =>
1370
+ /^(y|yes)$/i.test(val) ? true : /^(n|no)$/i.test(val) ? false : def;
1371
+ const yesterday = () => {
1372
+ let t = new Date();
1373
+ t.setDate(t.getDate() - 1);
1374
+ return t.toISOString().split('T')[0];
1375
+ };
1376
+ const zip = (...arrays) => {
1377
+ const maxLength = Math.max(...arrays.map(x => x.length));
1378
+ return Array.from({ length: maxLength }).map((_, i) => {
1379
+ return Array.from({ length: arrays.length }, (_, k) => arrays[k][i]);
1380
+ });
1381
+ };
1382
+ const zipObject = (props, values) =>
1383
+ props.reduce((obj, prop, index) => ((obj[prop] = values[index]), obj), {});
1384
+ const zipWith = (...array) => {
1385
+ const fn = typeof array[array.length - 1] === 'function' ? array.pop() : undefined;
1386
+ return Array.from({ length: Math.max(...array.map(a => a.length)) }, (_, i) =>
1387
+ fn ? fn(...array.map(a => a[i])) : array.map(a => a[i])
1388
+ );
1389
+ };
1390
+ const binarySearch = (arr, val, start = 0, end = arr.length - 1) => {
1391
+ if (start > end) return -1;
1392
+ const mid = Math.floor((start + end) / 2);
1393
+ if (arr[mid] > val) return binarySearch(arr, val, start, mid - 1);
1394
+ if (arr[mid] < val) return binarySearch(arr, val, mid + 1, end);
1395
+ return mid;
1396
+ };
1397
+ const celsiusToFahrenheit = degrees => 1.8 * degrees + 32;
1398
+ const cleanObj = (obj, keysToKeep = [], childIndicator) => {
1399
+ Object.keys(obj).forEach(key => {
1400
+ if (key === childIndicator) {
1401
+ cleanObj(obj[key], keysToKeep, childIndicator);
1402
+ } else if (!keysToKeep.includes(key)) {
1403
+ delete obj[key];
1404
+ }
1405
+ });
1406
+ return obj;
1407
+ };
1408
+ const collatz = n => (n % 2 === 0 ? n / 2 : 3 * n + 1);
1409
+ const countVowels = str => (str.match(/[aeiou]/gi) || []).length;
1410
+ const factors = (num, primes = false) => {
1411
+ const isPrime = num => {
1412
+ const boundary = Math.floor(Math.sqrt(num));
1413
+ for (var i = 2; i <= boundary; i++) if (num % i === 0) return false;
1414
+ return num >= 2;
1415
+ };
1416
+ const isNeg = num < 0;
1417
+ num = isNeg ? -num : num;
1418
+ let array = Array.from({ length: num - 1 })
1419
+ .map((val, i) => (num % (i + 2) === 0 ? i + 2 : false))
1420
+ .filter(val => val);
1421
+ if (isNeg)
1422
+ array = array.reduce((acc, val) => {
1423
+ acc.push(val);
1424
+ acc.push(-val);
1425
+ return acc;
1426
+ }, []);
1427
+ return primes ? array.filter(isPrime) : array;
1428
+ };
1429
+ const fahrenheitToCelsius = degrees => (degrees - 32) * 5/9;
1430
+ const fibonacciCountUntilNum = num =>
1431
+ Math.ceil(Math.log(num * Math.sqrt(5) + 1 / 2) / Math.log((Math.sqrt(5) + 1) / 2));
1432
+ const fibonacciUntilNum = num => {
1433
+ let n = Math.ceil(Math.log(num * Math.sqrt(5) + 1 / 2) / Math.log((Math.sqrt(5) + 1) / 2));
1434
+ return Array.from({ length: n }).reduce(
1435
+ (acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i),
1436
+ []
1437
+ );
1438
+ };
1439
+ const heronArea = (side_a, side_b, side_c) => {
1440
+ const p = (side_a + side_b + side_c) / 2;
1441
+ return Math.sqrt(p * (p-side_a) * (p-side_b) * (p-side_c))
1442
+ };
1443
+ const howManyTimes = (num, divisor) => {
1444
+ if (divisor === 1 || divisor === -1) return Infinity;
1445
+ if (divisor === 0) return 0;
1446
+ let i = 0;
1447
+ while (Number.isInteger(num / divisor)) {
1448
+ i++;
1449
+ num = num / divisor;
1450
+ }
1451
+ return i;
1452
+ };
1453
+ const httpDelete = (url, callback, err = console.error) => {
1454
+ const request = new XMLHttpRequest();
1455
+ request.open('DELETE', url, true);
1456
+ request.onload = () => callback(request);
1457
+ request.onerror = () => err(request);
1458
+ request.send();
1459
+ };
1460
+ const httpPut = (url, data, callback, err = console.error) => {
1461
+ const request = new XMLHttpRequest();
1462
+ request.open("PUT", url, true);
1463
+ request.setRequestHeader('Content-type','application/json; charset=utf-8');
1464
+ request.onload = () => callback(request);
1465
+ request.onerror = () => err(request);
1466
+ request.send(data);
1467
+ };
1468
+ const isArmstrongNumber = digits =>
1469
+ (arr => arr.reduce((a, d) => a + parseInt(d) ** arr.length, 0) == digits)(
1470
+ (digits + '').split('')
1471
+ );
1472
+ const isSimilar = (pattern, str) =>
1473
+ [...str].reduce(
1474
+ (matchIndex, char) =>
1475
+ char.toLowerCase() === (pattern[matchIndex] || '').toLowerCase()
1476
+ ? matchIndex + 1
1477
+ : matchIndex,
1478
+ 0
1479
+ ) === pattern.length;
1480
+ const JSONToDate = arr => {
1481
+ const dt = new Date(parseInt(arr.toString().substr(6)));
1482
+ return `${dt.getDate()}/${dt.getMonth() + 1}/${dt.getFullYear()}`;
1483
+ };
1484
+ const kmphToMph = (kmph) => 0.621371192 * kmph;
1485
+ const levenshteinDistance = (string1, string2) => {
1486
+ if (string1.length === 0) return string2.length;
1487
+ if (string2.length === 0) return string1.length;
1488
+ let matrix = Array(string2.length + 1)
1489
+ .fill(0)
1490
+ .map((x, i) => [i]);
1491
+ matrix[0] = Array(string1.length + 1)
1492
+ .fill(0)
1493
+ .map((x, i) => i);
1494
+ for (let i = 1; i <= string2.length; i++) {
1495
+ for (let j = 1; j <= string1.length; j++) {
1496
+ if (string2[i - 1] === string1[j - 1]) {
1497
+ matrix[i][j] = matrix[i - 1][j - 1];
1498
+ } else {
1499
+ matrix[i][j] = Math.min(
1500
+ matrix[i - 1][j - 1] + 1,
1501
+ matrix[i][j - 1] + 1,
1502
+ matrix[i - 1][j] + 1
1503
+ );
1504
+ }
1505
+ }
1506
+ }
1507
+ return matrix[string2.length][string1.length];
1508
+ };
1509
+ const mphToKmph = (mph) => 1.6093440006146922 * mph;
1510
+ const pipeLog = data => console.log(data) || data;
1511
+ const quickSort = ([n, ...nums], desc) =>
1512
+ isNaN(n)
1513
+ ? []
1514
+ : [
1515
+ ...quickSort(nums.filter(v => (desc ? v > n : v <= n)), desc),
1516
+ n,
1517
+ ...quickSort(nums.filter(v => (!desc ? v > n : v <= n)), desc)
1518
+ ];
1519
+ const removeVowels = (str, repl = '') => str.replace(/[aeiou]/gi, repl);
1520
+ const solveRPN = rpn => {
1521
+ const OPERATORS = {
1522
+ '*': (a, b) => a * b,
1523
+ '+': (a, b) => a + b,
1524
+ '-': (a, b) => a - b,
1525
+ '/': (a, b) => a / b,
1526
+ '**': (a, b) => a ** b
1527
+ };
1528
+ const [stack, solve] = [
1529
+ [],
1530
+ rpn
1531
+ .replace(/\^/g, '**')
1532
+ .split(/\s+/g)
1533
+ .filter(el => !/\s+/.test(el) && el !== '')
1534
+ ];
1535
+ solve.forEach(symbol => {
1536
+ if (!isNaN(parseFloat(symbol)) && isFinite(symbol)) {
1537
+ stack.push(symbol);
1538
+ } else if (Object.keys(OPERATORS).includes(symbol)) {
1539
+ const [a, b] = [stack.pop(), stack.pop()];
1540
+ stack.push(OPERATORS[symbol](parseFloat(b), parseFloat(a)));
1541
+ } else {
1542
+ throw `${symbol} is not a recognized symbol`;
1543
+ }
1544
+ });
1545
+ if (stack.length === 1) return stack.pop();
1546
+ else throw `${rpn} is not a proper RPN. Please check it and try again`;
1547
+ };
1548
+ const speechSynthesis = message => {
1549
+ const msg = new SpeechSynthesisUtterance(message);
1550
+ msg.voice = window.speechSynthesis.getVoices()[0];
1551
+ window.speechSynthesis.speak(msg);
1552
+ };
1553
+ const squareSum = (...args) => args.reduce((squareSum, number) => squareSum + Math.pow(number, 2), 0);
1554
+ const exports={}
1555
+ exports.all = all;
1556
+ exports.allEqual = allEqual;
1557
+ exports.any = any;
1558
+ exports.approximatelyEqual = approximatelyEqual;
1559
+ exports.arrayToCSV = arrayToCSV;
1560
+ exports.arrayToHtmlList = arrayToHtmlList;
1561
+ exports.ary = ary;
1562
+ exports.atob = atob;
1563
+ exports.attempt = attempt;
1564
+ exports.average = average;
1565
+ exports.averageBy = averageBy;
1566
+ exports.bifurcate = bifurcate;
1567
+ exports.bifurcateBy = bifurcateBy;
1568
+ exports.bind = bind;
1569
+ exports.bindAll = bindAll;
1570
+ exports.bindKey = bindKey;
1571
+ exports.binomialCoefficient = binomialCoefficient;
1572
+ exports.bottomVisible = bottomVisible;
1573
+ exports.btoa = btoa;
1574
+ exports.byteSize = byteSize;
1575
+ exports.call = call;
1576
+ exports.capitalize = capitalize;
1577
+ exports.capitalizeEveryWord = capitalizeEveryWord;
1578
+ exports.castArray = castArray;
1579
+ exports.chainAsync = chainAsync;
1580
+ exports.checkProp = checkProp;
1581
+ exports.chunk = chunk;
1582
+ exports.clampNumber = clampNumber;
1583
+ exports.cloneRegExp = cloneRegExp;
1584
+ exports.coalesce = coalesce;
1585
+ exports.coalesceFactory = coalesceFactory;
1586
+ exports.collectInto = collectInto;
1587
+ exports.colorize = colorize;
1588
+ exports.compact = compact;
1589
+ exports.compactWhitespace = compactWhitespace;
1590
+ exports.compose = compose;
1591
+ exports.composeRight = composeRight;
1592
+ exports.converge = converge;
1593
+ exports.copyToClipboard = copyToClipboard;
1594
+ exports.countBy = countBy;
1595
+ exports.counter = counter;
1596
+ exports.countOccurrences = countOccurrences;
1597
+ exports.createDirIfNotExists = createDirIfNotExists;
1598
+ exports.createElement = createElement;
1599
+ exports.createEventHub = createEventHub;
1600
+ exports.CSVToArray = CSVToArray;
1601
+ exports.CSVToJSON = CSVToJSON;
1602
+ exports.currentURL = currentURL;
1603
+ exports.curry = curry;
1604
+ exports.dayOfYear = dayOfYear;
1605
+ exports.debounce = debounce;
1606
+ exports.decapitalize = decapitalize;
1607
+ exports.deepClone = deepClone;
1608
+ exports.deepFlatten = deepFlatten;
1609
+ exports.deepFreeze = deepFreeze;
1610
+ exports.deepGet = deepGet;
1611
+ exports.deepMapKeys = deepMapKeys;
1612
+ exports.defaults = defaults;
1613
+ exports.defer = defer;
1614
+ exports.degreesToRads = degreesToRads;
1615
+ exports.delay = delay;
1616
+ exports.detectDeviceType = detectDeviceType;
1617
+ exports.difference = difference;
1618
+ exports.differenceBy = differenceBy;
1619
+ exports.differenceWith = differenceWith;
1620
+ exports.dig = dig;
1621
+ exports.digitize = digitize;
1622
+ exports.distance = distance;
1623
+ exports.drop = drop;
1624
+ exports.dropRight = dropRight;
1625
+ exports.dropRightWhile = dropRightWhile;
1626
+ exports.dropWhile = dropWhile;
1627
+ exports.elementContains = elementContains;
1628
+ exports.elementIsVisibleInViewport = elementIsVisibleInViewport;
1629
+ exports.elo = elo;
1630
+ exports.equals = equals;
1631
+ exports.escapeHTML = escapeHTML;
1632
+ exports.escapeRegExp = escapeRegExp;
1633
+ exports.everyNth = everyNth;
1634
+ exports.extendHex = extendHex;
1635
+ exports.factorial = factorial;
1636
+ exports.fibonacci = fibonacci;
1637
+ exports.filterFalsy = filterFalsy;
1638
+ exports.filterNonUnique = filterNonUnique;
1639
+ exports.filterNonUniqueBy = filterNonUniqueBy;
1640
+ exports.findKey = findKey;
1641
+ exports.findLast = findLast;
1642
+ exports.findLastIndex = findLastIndex;
1643
+ exports.findLastKey = findLastKey;
1644
+ exports.flatten = flatten;
1645
+ exports.flattenObject = flattenObject;
1646
+ exports.flip = flip;
1647
+ exports.forEachRight = forEachRight;
1648
+ exports.formatDuration = formatDuration;
1649
+ exports.formToObject = formToObject;
1650
+ exports.forOwn = forOwn;
1651
+ exports.forOwnRight = forOwnRight;
1652
+ exports.fromCamelCase = fromCamelCase;
1653
+ exports.functionName = functionName;
1654
+ exports.functions = functions;
1655
+ exports.gcd = gcd;
1656
+ exports.geometricProgression = geometricProgression;
1657
+ exports.get = get;
1658
+ exports.getColonTimeFromDate = getColonTimeFromDate;
1659
+ exports.getDaysDiffBetweenDates = getDaysDiffBetweenDates;
1660
+ exports.getImages = getImages;
1661
+ exports.getMeridiemSuffixOfInteger = getMeridiemSuffixOfInteger;
1662
+ exports.getScrollPosition = getScrollPosition;
1663
+ exports.getStyle = getStyle;
1664
+ exports.getType = getType;
1665
+ exports.getURLParameters = getURLParameters;
1666
+ exports.groupBy = groupBy;
1667
+ exports.hammingDistance = hammingDistance;
1668
+ exports.hasClass = hasClass;
1669
+ exports.hasFlags = hasFlags;
1670
+ exports.hashBrowser = hashBrowser;
1671
+ exports.hashNode = hashNode;
1672
+ exports.head = head;
1673
+ exports.hexToRGB = hexToRGB;
1674
+ exports.hide = hide;
1675
+ exports.httpGet = httpGet;
1676
+ exports.httpPost = httpPost;
1677
+ exports.httpsRedirect = httpsRedirect;
1678
+ exports.hz = hz;
1679
+ exports.indentString = indentString;
1680
+ exports.indexOfAll = indexOfAll;
1681
+ exports.initial = initial;
1682
+ exports.initialize2DArray = initialize2DArray;
1683
+ exports.initializeArrayWithRange = initializeArrayWithRange;
1684
+ exports.initializeArrayWithRangeRight = initializeArrayWithRangeRight;
1685
+ exports.initializeArrayWithValues = initializeArrayWithValues;
1686
+ exports.initializeNDArray = initializeNDArray;
1687
+ exports.inRange = inRange;
1688
+ exports.insertAfter = insertAfter;
1689
+ exports.insertBefore = insertBefore;
1690
+ exports.intersection = intersection;
1691
+ exports.intersectionBy = intersectionBy;
1692
+ exports.intersectionWith = intersectionWith;
1693
+ exports.invertKeyValues = invertKeyValues;
1694
+ exports.is = is;
1695
+ exports.isAbsoluteURL = isAbsoluteURL;
1696
+ exports.isAfterDate = isAfterDate;
1697
+ exports.isAnagram = isAnagram;
1698
+ exports.isArrayLike = isArrayLike;
1699
+ exports.isBeforeDate = isBeforeDate;
1700
+ exports.isBoolean = isBoolean;
1701
+ exports.isBrowser = isBrowser;
1702
+ exports.isBrowserTabFocused = isBrowserTabFocused;
1703
+ exports.isDivisible = isDivisible;
1704
+ exports.isDuplexStream = isDuplexStream;
1705
+ exports.isEmpty = isEmpty;
1706
+ exports.isEven = isEven;
1707
+ exports.isFunction = isFunction;
1708
+ exports.isLowerCase = isLowerCase;
1709
+ exports.isNegativeZero = isNegativeZero;
1710
+ exports.isNil = isNil;
1711
+ exports.isNull = isNull;
1712
+ exports.isNumber = isNumber;
1713
+ exports.isObject = isObject;
1714
+ exports.isObjectLike = isObjectLike;
1715
+ exports.isPlainObject = isPlainObject;
1716
+ exports.isPrime = isPrime;
1717
+ exports.isPrimitive = isPrimitive;
1718
+ exports.isPromiseLike = isPromiseLike;
1719
+ exports.isReadableStream = isReadableStream;
1720
+ exports.isSameDate = isSameDate;
1721
+ exports.isSorted = isSorted;
1722
+ exports.isStream = isStream;
1723
+ exports.isString = isString;
1724
+ exports.isSymbol = isSymbol;
1725
+ exports.isTravisCI = isTravisCI;
1726
+ exports.isUndefined = isUndefined;
1727
+ exports.isUpperCase = isUpperCase;
1728
+ exports.isValidJSON = isValidJSON;
1729
+ exports.isWeekday = isWeekday;
1730
+ exports.isWeekend = isWeekend;
1731
+ exports.isWritableStream = isWritableStream;
1732
+ exports.join = join;
1733
+ exports.JSONtoCSV = JSONtoCSV;
1734
+ exports.JSONToFile = JSONToFile;
1735
+ exports.last = last;
1736
+ exports.lcm = lcm;
1737
+ exports.longestItem = longestItem;
1738
+ exports.lowercaseKeys = lowercaseKeys;
1739
+ exports.luhnCheck = luhnCheck;
1740
+ exports.mapKeys = mapKeys;
1741
+ exports.mapNumRange = mapNumRange;
1742
+ exports.mapObject = mapObject;
1743
+ exports.mapString = mapString;
1744
+ exports.mapValues = mapValues;
1745
+ exports.mask = mask;
1746
+ exports.matches = matches;
1747
+ exports.matchesWith = matchesWith;
1748
+ exports.maxBy = maxBy;
1749
+ exports.maxDate = maxDate;
1750
+ exports.maxN = maxN;
1751
+ exports.median = median;
1752
+ exports.memoize = memoize;
1753
+ exports.merge = merge;
1754
+ exports.midpoint = midpoint;
1755
+ exports.minBy = minBy;
1756
+ exports.minDate = minDate;
1757
+ exports.minN = minN;
1758
+ exports.mostPerformant = mostPerformant;
1759
+ exports.negate = negate;
1760
+ exports.nest = nest;
1761
+ exports.nodeListToArray = nodeListToArray;
1762
+ exports.none = none;
1763
+ exports.nthArg = nthArg;
1764
+ exports.nthElement = nthElement;
1765
+ exports.objectFromPairs = objectFromPairs;
1766
+ exports.objectToPairs = objectToPairs;
1767
+ exports.observeMutations = observeMutations;
1768
+ exports.off = off;
1769
+ exports.offset = offset;
1770
+ exports.omit = omit;
1771
+ exports.omitBy = omitBy;
1772
+ exports.on = on;
1773
+ exports.once = once;
1774
+ exports.onUserInputChange = onUserInputChange;
1775
+ exports.orderBy = orderBy;
1776
+ exports.over = over;
1777
+ exports.overArgs = overArgs;
1778
+ exports.pad = pad;
1779
+ exports.palindrome = palindrome;
1780
+ exports.parseCookie = parseCookie;
1781
+ exports.partial = partial;
1782
+ exports.partialRight = partialRight;
1783
+ exports.partition = partition;
1784
+ exports.percentile = percentile;
1785
+ exports.permutations = permutations;
1786
+ exports.pick = pick;
1787
+ exports.pickBy = pickBy;
1788
+ exports.pipeAsyncFunctions = pipeAsyncFunctions;
1789
+ exports.pipeFunctions = pipeFunctions;
1790
+ exports.pluralize = pluralize;
1791
+ exports.powerset = powerset;
1792
+ exports.prefix = prefix;
1793
+ exports.prettyBytes = prettyBytes;
1794
+ exports.primes = primes;
1795
+ exports.promisify = promisify;
1796
+ exports.pull = pull;
1797
+ exports.pullAtIndex = pullAtIndex;
1798
+ exports.pullAtValue = pullAtValue;
1799
+ exports.pullBy = pullBy;
1800
+ exports.radsToDegrees = radsToDegrees;
1801
+ exports.randomHexColorCode = randomHexColorCode;
1802
+ exports.randomIntArrayInRange = randomIntArrayInRange;
1803
+ exports.randomIntegerInRange = randomIntegerInRange;
1804
+ exports.randomNumberInRange = randomNumberInRange;
1805
+ exports.readFileLines = readFileLines;
1806
+ exports.rearg = rearg;
1807
+ exports.recordAnimationFrames = recordAnimationFrames;
1808
+ exports.redirect = redirect;
1809
+ exports.reducedFilter = reducedFilter;
1810
+ exports.reduceSuccessive = reduceSuccessive;
1811
+ exports.reduceWhich = reduceWhich;
1812
+ exports.reject = reject;
1813
+ exports.remove = remove;
1814
+ exports.removeNonASCII = removeNonASCII;
1815
+ exports.renameKeys = renameKeys;
1816
+ exports.reverseString = reverseString;
1817
+ exports.RGBToHex = RGBToHex;
1818
+ exports.round = round;
1819
+ exports.runAsync = runAsync;
1820
+ exports.runPromisesInSeries = runPromisesInSeries;
1821
+ exports.sample = sample;
1822
+ exports.sampleSize = sampleSize;
1823
+ exports.scrollToTop = scrollToTop;
1824
+ exports.sdbm = sdbm;
1825
+ exports.serializeCookie = serializeCookie;
1826
+ exports.serializeForm = serializeForm;
1827
+ exports.setStyle = setStyle;
1828
+ exports.shallowClone = shallowClone;
1829
+ exports.shank = shank;
1830
+ exports.show = show;
1831
+ exports.shuffle = shuffle;
1832
+ exports.similarity = similarity;
1833
+ exports.size = size;
1834
+ exports.sleep = sleep;
1835
+ exports.smoothScroll = smoothScroll;
1836
+ exports.sortCharactersInString = sortCharactersInString;
1837
+ exports.sortedIndex = sortedIndex;
1838
+ exports.sortedIndexBy = sortedIndexBy;
1839
+ exports.sortedLastIndex = sortedLastIndex;
1840
+ exports.sortedLastIndexBy = sortedLastIndexBy;
1841
+ exports.splitLines = splitLines;
1842
+ exports.spreadOver = spreadOver;
1843
+ exports.stableSort = stableSort;
1844
+ exports.standardDeviation = standardDeviation;
1845
+ exports.stringPermutations = stringPermutations;
1846
+ exports.stripHTMLTags = stripHTMLTags;
1847
+ exports.sum = sum;
1848
+ exports.sumBy = sumBy;
1849
+ exports.sumPower = sumPower;
1850
+ exports.symmetricDifference = symmetricDifference;
1851
+ exports.symmetricDifferenceBy = symmetricDifferenceBy;
1852
+ exports.symmetricDifferenceWith = symmetricDifferenceWith;
1853
+ exports.tail = tail;
1854
+ exports.take = take;
1855
+ exports.takeRight = takeRight;
1856
+ exports.takeRightWhile = takeRightWhile;
1857
+ exports.takeWhile = takeWhile;
1858
+ exports.throttle = throttle;
1859
+ exports.times = times;
1860
+ exports.timeTaken = timeTaken;
1861
+ exports.toCamelCase = toCamelCase;
1862
+ exports.toCurrency = toCurrency;
1863
+ exports.toDecimalMark = toDecimalMark;
1864
+ exports.toggleClass = toggleClass;
1865
+ exports.toHash = toHash;
1866
+ exports.toKebabCase = toKebabCase;
1867
+ exports.tomorrow = tomorrow;
1868
+ exports.toOrdinalSuffix = toOrdinalSuffix;
1869
+ exports.toSafeInteger = toSafeInteger;
1870
+ exports.toSnakeCase = toSnakeCase;
1871
+ exports.toTitleCase = toTitleCase;
1872
+ exports.transform = transform;
1873
+ exports.triggerEvent = triggerEvent;
1874
+ exports.truncateString = truncateString;
1875
+ exports.truthCheckCollection = truthCheckCollection;
1876
+ exports.unary = unary;
1877
+ exports.uncurry = uncurry;
1878
+ exports.unescapeHTML = unescapeHTML;
1879
+ exports.unflattenObject = unflattenObject;
1880
+ exports.unfold = unfold;
1881
+ exports.union = union;
1882
+ exports.unionBy = unionBy;
1883
+ exports.unionWith = unionWith;
1884
+ exports.uniqueElements = uniqueElements;
1885
+ exports.uniqueElementsBy = uniqueElementsBy;
1886
+ exports.uniqueElementsByRight = uniqueElementsByRight;
1887
+ exports.uniqueSymmetricDifference = uniqueSymmetricDifference;
1888
+ exports.untildify = untildify;
1889
+ exports.unzip = unzip;
1890
+ exports.unzipWith = unzipWith;
1891
+ exports.URLJoin = URLJoin;
1892
+ exports.UUIDGeneratorBrowser = UUIDGeneratorBrowser;
1893
+ exports.UUIDGeneratorNode = UUIDGeneratorNode;
1894
+ exports.validateNumber = validateNumber;
1895
+ exports.vectorDistance = vectorDistance;
1896
+ exports.when = when;
1897
+ exports.without = without;
1898
+ exports.words = words;
1899
+ exports.xProd = xProd;
1900
+ exports.yesNo = yesNo;
1901
+ exports.yesterday = yesterday;
1902
+ exports.zip = zip;
1903
+ exports.zipObject = zipObject;
1904
+ exports.zipWith = zipWith;
1905
+ exports.binarySearch = binarySearch;
1906
+ exports.celsiusToFahrenheit = celsiusToFahrenheit;
1907
+ exports.cleanObj = cleanObj;
1908
+ exports.collatz = collatz;
1909
+ exports.countVowels = countVowels;
1910
+ exports.factors = factors;
1911
+ exports.fahrenheitToCelsius = fahrenheitToCelsius;
1912
+ exports.fibonacciCountUntilNum = fibonacciCountUntilNum;
1913
+ exports.fibonacciUntilNum = fibonacciUntilNum;
1914
+ exports.heronArea = heronArea;
1915
+ exports.howManyTimes = howManyTimes;
1916
+ exports.httpDelete = httpDelete;
1917
+ exports.httpPut = httpPut;
1918
+ exports.isArmstrongNumber = isArmstrongNumber;
1919
+ exports.isSimilar = isSimilar;
1920
+ exports.JSONToDate = JSONToDate;
1921
+ exports.kmphToMph = kmphToMph;
1922
+ exports.levenshteinDistance = levenshteinDistance;
1923
+ exports.mphToKmph = mphToKmph;
1924
+ exports.pipeLog = pipeLog;
1925
+ exports.quickSort = quickSort;
1926
+ exports.removeVowels = removeVowels;
1927
+ exports.solveRPN = solveRPN;
1928
+ exports.speechSynthesis = speechSynthesis;
1929
+ exports.squareSum = squareSum;
1930
+
1931
+ export default exports