1. import { tag } from "./helpers.js"
  2. import { _Set, Vec } from "./classes.js"
  3. /** @namespace */
  4. const type_checks = {}
  5. /**
  6. * **[Global]** Checks if a value is a number or a big int
  7. * @function
  8. * @param {any} value Value to check
  9. * @returns {boolean}
  10. */
  11. type_checks.isnum = tag({ keep_global: true }, x => typeof x === "number" || typeof x === "bigint")
  12. /**
  13. * **[Global]** Same as the built in [Number.isInteger](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger)
  14. * @function
  15. * @param {any} value Value to check
  16. * @returns {boolean}
  17. */
  18. type_checks.isint = tag({ keep_global: true }, Number.isInteger)
  19. /**
  20. * **[Global]** Checks if a value is a string
  21. * @function
  22. * @param {any} value Value to check
  23. * @returns {boolean}
  24. */
  25. type_checks.isstr = tag({ keep_global: true }, x => typeof x === "string")
  26. /**
  27. * **[Global]** Checks if a value is an array (alias for Array.isArray)
  28. * @function
  29. * @param {any} value Value to check
  30. * @returns {boolean}
  31. */
  32. // Can't use Array.isArray directly because the regex won't pick up on it being niladic
  33. type_checks.isarr = tag({ keep_global: true }, x => Array.isArray(x))
  34. /**
  35. * **[Global]** Checks if a value is a boolean
  36. * @function
  37. * @param {any} value Value to check
  38. * @returns {boolean}
  39. */
  40. type_checks.isbool = tag({ keep_global: true }, x => typeof x === "boolean")
  41. /**
  42. * **[Global]** Checks if a value is a function
  43. * @function
  44. * @param {any} value Value to check
  45. * @returns {boolean}
  46. */
  47. type_checks.isfunc = tag({ keep_global: true }, x => typeof x === "function")
  48. /**
  49. * **[Global]** Checks if a value is an object
  50. * @function
  51. * @param {any} value Value to check
  52. * @returns {boolean}
  53. */
  54. type_checks.isobj = tag({ keep_global: true }, x => typeof x === "object")
  55. /**
  56. * **[Global]** Gets the type of a value using typeof
  57. * @function
  58. * @param {any} value Value to get the type of
  59. * @returns {boolean}
  60. */
  61. type_checks.type = tag({ keep_global: true }, x => typeof x)
  62. /**
  63. * **[Global]** Checks if a type is iterable
  64. * @function
  65. * @param {any} value Value to check
  66. * @returns {boolean}
  67. */
  68. type_checks.isiter = tag({ keep_global: true }, x => typeof x[Symbol.iterator] === "function")
  69. /** @namespace */
  70. const type_casts = {}
  71. /**
  72. * Casts a value to a number using the `Number` constructor. If `value` is a string
  73. * then a number will be extracted with regex before casting.
  74. * @param {any} value
  75. * @returns {number}
  76. */
  77. type_casts.num = value => {
  78. if (type_checks.isstr(value)) {
  79. const match = value.match(/-?\d+(\.\d+)?/)[0]
  80. return match ? Number(match) : null
  81. }
  82. return Number(value)
  83. }
  84. /**
  85. * Casts a value to an integer using parseInt. If `value` is a string an int
  86. * will be extracted with regex before casting).
  87. * @param {any} value Value to cast
  88. * @returns {number}
  89. */
  90. type_casts.int = value => parseInt(type_casts.num(value))
  91. /**
  92. * Casts a value to a string. If `value` is an array, it will be joined by "".
  93. * @param {any} value Value to cast
  94. */
  95. type_casts.str = value => {
  96. const str = value?.toString()
  97. if (str === null) return "null"
  98. if (str === undefined) return "undefined"
  99. if (value instanceof Vec)
  100. return `Vec(${value.x}, ${value.y})`
  101. if (type_checks.isarr(value))
  102. return value.join("")
  103. if (type_checks.isobj(value))
  104. return str === "[object Object]" ? JSON.stringify(value) : str
  105. return str
  106. }
  107. /**
  108. * Casts a value to an array. If `value` is a number, an array of length `value`
  109. * will be created
  110. * @param {any} value Value to cast
  111. * @returns {Array}
  112. */
  113. type_casts.arr = value => {
  114. if (type_checks.isnum(value)) return Array(value)
  115. if (type_checks.isiter(value)) return [...value]
  116. return Array.from(value)
  117. }
  118. /**
  119. * Casts a value to a boolean (alias for Boolean constructor)
  120. * @param {any} value Value to cast
  121. * @returns {boolean}
  122. */
  123. type_casts.bool = value => Boolean(value)
  124. /** @namespace */
  125. const math_utils = {}
  126. /**
  127. * Casts `a` and `b` using `Number` constructor, then adds them using `+` operator
  128. * @param {number} a
  129. * @param {number} b
  130. * @return {number}
  131. */
  132. math_utils.add = (a, b) => Number(a) + Number(b)
  133. /**
  134. * Casts `a` and `b` using `Number` constructor, then subtracts them using `-` operator
  135. * @param {number} a
  136. * @param {number} b
  137. * @return {number}
  138. */
  139. math_utils.sub = (a, b) => Number(a) - Number(b)
  140. /**
  141. * Casts `a` and `b` using `Number` constructor, then multiplies them using `*` operator
  142. * @param {number} a
  143. * @param {number} b
  144. * @return {number}
  145. */
  146. math_utils.mul = (a, b) => Number(a) * Number(b)
  147. /**
  148. * Casts `a` and `b` using `Number` constructor, then divides them using `/` operator
  149. * @param {number} a
  150. * @param {number} b
  151. * @return {number}
  152. */
  153. math_utils.div = (a, b) => Number(a) / Number(b)
  154. /**
  155. * Casts `a` and `b` using `Number` constructor, then calculates `a % b`
  156. * (note: this is not true modulo, just remainder after division)
  157. * @param {number} a
  158. * @param {number} b
  159. * @return {number}
  160. */
  161. math_utils.mod = (a, b) => Number(a) % Number(b)
  162. /**
  163. * Calculates `b ** m` (optionally modulo `m`)
  164. * @param {number} b
  165. * @param {number} e
  166. * @param {number} [m]
  167. * @return {number}
  168. */
  169. math_utils.exp = (b, e, m = null) => {
  170. if (m) {
  171. // naive solution but it does the job
  172. if (m == 1) return 0
  173. let ret = 1
  174. for (let i = 0; i < e; i++)
  175. ret = (ret * b) % m
  176. return ret
  177. } else return b ** e
  178. }
  179. /**
  180. * Returns the absolute difference between `a` and `b`
  181. * @param {number} a
  182. * @param {number} b
  183. * @return {number}
  184. */
  185. math_utils.absdiff = (a, b) => Math.abs(a - b)
  186. /**
  187. * Checks if `a` is greater than `b`
  188. * @param {number} a
  189. * @param {number} b
  190. * @returns {boolean}
  191. */
  192. math_utils.gt = (a, b) => a > b
  193. /**
  194. * Checks if `a` is less than `b`
  195. * @param {number} a
  196. * @param {number} b
  197. * @returns {boolean}
  198. */
  199. math_utils.lt = (a, b) => a < b
  200. /**
  201. * Checks if `a` is greater than or equal to `b`
  202. * @param {number} a
  203. * @param {number} b
  204. * @returns {boolean}
  205. */
  206. math_utils.gte = (a, b) => a >= b
  207. /**
  208. * Checks if `a` is less than or equal to `b`
  209. * @param {number} a
  210. * @param {number} b
  211. * @returns {boolean}
  212. */
  213. math_utils.lte = (a, b) => a <= b
  214. /**
  215. * Checks if `n` is odd
  216. * @param {number} n
  217. * @returns {boolean}
  218. */
  219. math_utils.odd = n => n % 2 === 1
  220. /**
  221. * Checks if `n` is even
  222. * @param {number} n
  223. * @returns {boolean}
  224. */
  225. math_utils.even = n => n % 2 === 0
  226. /**
  227. * Calculates the absolute value of `n`
  228. * @param {number} n
  229. * @returns {number}
  230. */
  231. math_utils.abs = n => Math.abs(n)
  232. /**
  233. * Calculates the square root of `n`
  234. * @param {number} n
  235. * @returns {number}
  236. */
  237. math_utils.sqrt = n => Math.sqrt(n)
  238. /**
  239. * Calculates the sign of `n`
  240. * @param {number} n
  241. * @returns {number}
  242. */
  243. math_utils.sign = n => Math.sign(n)
  244. /**
  245. * Rounds `n` down to the nearest integer
  246. * @param {number} n
  247. * @returns {number}
  248. */
  249. math_utils.floor = n => Math.floor(n)
  250. /**
  251. * Rounds `n` up to the nearest integer
  252. * @param {number} n
  253. * @returns {number}
  254. */
  255. math_utils.ceil = n => Math.ceil(n)
  256. /**
  257. * Rounds `n` to the nearest integer
  258. * @param {number} n
  259. * @returns {number}
  260. */
  261. math_utils.round = n => Math.round(n)
  262. /**
  263. * Wraps `index` around `length` (for indexing into to arrays, strings, etc.)
  264. * @param {number} index
  265. * @param {number} length
  266. * @returns {number}
  267. */
  268. math_utils.wrapindex = (index, length) => (index % length + length) % length
  269. /**
  270. * Clamps `n` between `min` and `max`
  271. * @param {number} n
  272. * @param {number} min
  273. * @param {number} max
  274. * @returns {number}
  275. */
  276. math_utils.clamp = (n, min, max) => Math.min(Math.max(n, min), max)
  277. /**
  278. * Checks if `n` is in the range [`min`, `max`] (inclusive)
  279. * @param {number} n
  280. * @param {number} min
  281. * @param {number} max
  282. * @returns {boolean}
  283. */
  284. math_utils.inrange = (n, min, max) => n >= min && n <= max
  285. /**
  286. * Calculates the minimum of an iterable using the builtin [Math.min](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min)
  287. * @param {Iterable.<*>} iter The iterable to find the minimum of
  288. * @returns {number}
  289. * @example min([2, 1, 3]) // 1
  290. */
  291. math_utils.min = iter => Math.min(...iter)
  292. /**
  293. * Calculates the maximum of an iterable using the builtin [Math.max](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max)
  294. * @param {Iterable.<*>} iter The iterable to find the maximum of
  295. * @returns {number}
  296. * @example max([2, 1, 3]) // 3
  297. */
  298. math_utils.max = iter => Math.max(...iter)
  299. /**
  300. * Functions which operate on iterable types
  301. * @namespace
  302. */
  303. const iter_utils = {}
  304. /**
  305. * Gets the first `n` elements of an iterable value and returns them in an array
  306. * @template T
  307. * @param {Iterable.<T>} iter The iterable to get elements from
  308. * @param {number} n The number of elements to get
  309. * @returns {T[]}
  310. */
  311. iter_utils.firstn = (iter, n) => [...iter].slice(0, n)
  312. /**
  313. * Gets the last `n` elements of an iterable value and returns them in an array
  314. * @template T
  315. * @param {Iterable.<T>} iter The iterable to get elements from
  316. * @param {number} n The number of elements to get
  317. * @returns {T[]}
  318. */
  319. iter_utils.lastn = (iter, n) => !n ? [] : [...iter].slice(-n)
  320. /**
  321. * Gets the first element of an iterable value
  322. * @param {Iterable.<*>} iter The iterable to get the first element from
  323. * @returns {any}
  324. */
  325. iter_utils.first = iter => [...iter][0]
  326. /**
  327. * Gets the last element of an iterable value
  328. * @param {Iterable.<*>} iter The iterable to get the last element from
  329. * @returns {any}
  330. */
  331. iter_utils.last = iter => {
  332. const array = [...iter]
  333. return array[array.length - 1]
  334. }
  335. /**
  336. * Removes the nth element from an iterable value
  337. * @template T
  338. * @param {Iterable.<T>} iter The iterable to remove an element from
  339. * @param {number} index The index of the element to remove
  340. * @returns {T[]} The resulting array
  341. */
  342. iter_utils.dropnth = (iter, index) => {
  343. const array = [...iter]
  344. array.splice(math_utils.wrapindex(index, array.length), 1)
  345. return array
  346. };
  347. /**
  348. * Sums the elements of an iterable value
  349. * @param {Iterable.<*>} iter The iterable to sum
  350. * @returns {number|string}
  351. */
  352. iter_utils.sum = iter => [...iter].reduce((acc, cur) => acc + cur)
  353. /**
  354. * Calculates the product of all values in an iterable
  355. * @param {Iterable.<*>} iter The iterable
  356. * @returns {number}
  357. */
  358. iter_utils.prod = iter => [...iter].reduce((acc, cur) => acc * cur)
  359. /**
  360. * Reverses the elements of an iterable (not in place)
  361. * @template T
  362. * @param {Iterable.<T>} iter The iterable to reverse
  363. * @returns {T[]} The reversed array
  364. */
  365. iter_utils.rev = iter => [...iter].reverse()
  366. /**
  367. * **[Global]** Zips multiple iterable into a single array of arrays, each
  368. * containing a single element from each iterable. The result will only be as
  369. * long as the shortest input.
  370. * @template T
  371. * @function
  372. * @param {...Iterable.<T[]>} iters The iterables to zip
  373. * @returns {T[][]}
  374. * @example zip([1, 2, 3], [4, 5, 6]) // [[1, 4], [2, 5], [3, 6]]
  375. * @example zip([1, 2]) // [[1], [2]]
  376. */
  377. iter_utils.zip = tag({ keep_global: true }, (...iters) => {
  378. if (!iters.length) return [];
  379. const smallest = Math.min(...iters.map(x => x.length))
  380. const ret = [];
  381. for (let i = 0; i < smallest; i++) {
  382. ret.push(iters.map(x => x[i]));
  383. }
  384. return ret;
  385. })
  386. /**
  387. * Creates a new {@link _Set} from an iterable. Same as {@link constructors.set}.
  388. * @param {Iterable.<*>} iter The iterable to create a set from
  389. * @returns {_Set}
  390. */
  391. iter_utils.uniq = iter => new _Set(iter)
  392. /**
  393. * Sorts an iterable given a comparison function (same as [Array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort))
  394. * but not in place
  395. * @template T
  396. * @param {Iterable.<T>} iter The iterable to sort
  397. * @param {function(T, T): number} compare_fn The comparison function
  398. * @returns {T[]} The sorted array
  399. */
  400. iter_utils.sorted = (iter, compare_fn) => [...iter].sort(compare_fn)
  401. /**
  402. * Sorts an iterable (of numbers) in ascending order
  403. * @template T
  404. * @param {Iterable.<T>} iter The iterable to sort
  405. * @returns {T[]} The sorted array
  406. */
  407. iter_utils.nsort = iter => [...iter].sort((a, b) => a - b)
  408. /**
  409. * Sorts an iterable (of numbers) in descending order
  410. * @param {Iterable.<*>} iter The iterable to sort
  411. * @returns {T[]} The sorted array
  412. */
  413. iter_utils.rsort = iter => [...iter].sort((a, b) => b - a)
  414. /**
  415. * Sorts an iterable in ascending order by the result of applying a given
  416. * function to each element
  417. * @template T
  418. * @param {Iterable.<T>} iter The iterable to sort
  419. * @param {function(T)} func The function to apply to each element
  420. * @returns {T[]} The sorted array
  421. */
  422. iter_utils.sortby = (iter, func) => iter.sort((a, b) => func(a) - func(b))
  423. /**
  424. * Sorts an iterable in descending order by the result of applying a given
  425. * function to each element
  426. * @template T
  427. * @param {Iterable.<T>} iter The iterable to sort
  428. * @param {function(T)} func The function to apply to each element
  429. * @returns {T[]} The sorted array
  430. */
  431. iter_utils.rsortby = (iter, func) => iter.sort((a, b) => func(b) - func(a))
  432. /**
  433. * Same as the built in [Array.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
  434. * @template T
  435. * @param {Iterable.<T>} iter The iterable to iterate over
  436. * @param {function(T, number, Iterable.<T>)} callback The callback to call for each element (see the MDN link for more info)
  437. * @returns {Iterable.<T>} The original iterable
  438. */
  439. iter_utils.for = (iter, callback) => {
  440. [...iter].forEach(callback)
  441. return iter
  442. }
  443. /**
  444. * Same as the built in [Array.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
  445. * @function
  446. * @template T
  447. * @param {Iterable.<T>} iter The iterable to iterate over
  448. * @param {function(T, number, Iterable.<T>)} callback The callback to call for each element (see the MDN link for more info)
  449. * @returns {Iterable.<T>} The original iterable
  450. */
  451. iter_utils.each = iter_utils.for
  452. /**
  453. * Same as the built in [Math.min](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min)
  454. * but it takes an iterable as a single argument
  455. * @param {Iterable.<*>} iter The iterable to find the minimum of
  456. * @returns {number}
  457. */
  458. iter_utils.min = iter => Math.min(...iter)
  459. /**
  460. * Same as the built in [Math.max](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max)
  461. * but it takes an iterable as a single argument
  462. * @param {Iterable.<*>} iter The iterable to find the maximum of
  463. * @returns {number}
  464. */
  465. iter_utils.max = iter => Math.max(...iter)
  466. /**
  467. * Same as the built in [Array.push](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push)
  468. * @template T
  469. * @param {T[]} array The array to append to
  470. * @param {...T} items The items to append
  471. * @returns {T[]} The resulting array
  472. */
  473. iter_utils.append = (array, ...items) => (array.push(...items), array)
  474. /**
  475. * Same as the built in [Array.unshift](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift)
  476. * @template T
  477. * @param {T[]} array The array to prepend to
  478. * @param {...T} items The items to prepend
  479. * @returns {T[]} The resulting array
  480. */
  481. iter_utils.prepend = (array, ...items) => (array.unshift(...items), array)
  482. /**
  483. * Checks if all items in an iterable are equal
  484. * @param {Iterable.<*>} iter The iterable to check
  485. * @returns {boolean}
  486. */
  487. iter_utils.alleq = iter => {
  488. const array = [...iter]
  489. return array.every(item => misc_utils.eq(item, array[0]))
  490. }
  491. /**
  492. * Creates a list of sublists of length `size` each of which is a sliding
  493. * window looking into `iter` starting at index `0` moving along by 1 each
  494. * time. If `loop` is true, there will be some extra windows at the end which
  495. * wrap around to the start.
  496. * @template T
  497. * @param {Iterable.<T[]>} iter The iterable to create sliding windows from
  498. * @param {number} size The size of the sliding window
  499. * @param {boolean} [wrap=false] Whether to include windows that wrap around
  500. * @returns {T[][]}
  501. * @example [1, 2, 3, 4, 5].sliding(3) // [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
  502. * @example [1, 2, 3].sliding(2, true) // [[1, 2], [2, 3], [3, 1]]
  503. */
  504. iter_utils.sliding = (iter, size = 2, wrap = false) => {
  505. const array = [...iter]
  506. if (array.length < size) return []
  507. const x = wrap ? array.concat(array.slice(0, size - 1)) : array
  508. return x.slice(0, -size + 1).map((_, i) => x.slice(i, i + size))
  509. }
  510. /**
  511. * Creates a list of contiguous non-overlapping chunks of `iter`, each of
  512. * length `size`
  513. * @template T
  514. * @param {Iterable.<*>} iter The iterable to create chunks from
  515. * @param {number} [size=2] The size of each chunk
  516. * @returns {T[][]}
  517. * @example [1, 2, 3, 4, 5, 6].chunks() // [[1, 2], [3, 4], [5, 6]]
  518. * @example [1, 2, 3, 4, 5, 6].chunks(3) // [[1, 2, 3], [4, 5, 6]]
  519. */
  520. iter_utils.chunks = (iter, size = 2) => {
  521. const ret = []
  522. for (let i = 0; i < iter.length; i += size) {
  523. ret.push(iter.slice(i, i + size))
  524. }
  525. return ret
  526. }
  527. /**
  528. * Swaps the elements at indices `index_a` and `index_b` in `array`. Only works
  529. * on arrays so that it can be done in place.
  530. * @template T
  531. * @param {T[]} array The array to swap elements in
  532. * @param {number} index_a The index of the first element to swap
  533. * @param {number} index_b The index of the second element to swap
  534. * @returns {T[]} The resulting array
  535. */
  536. iter_utils.swap = (array, index_a, index_b) => {
  537. [array[index_a], array[index_b]] = [array[index_b], array[index_a]]
  538. return array
  539. }
  540. /**
  541. * Generates all permutations of an iterable
  542. * @template T
  543. * @param {Iterable.<T>} iter
  544. * @returns {T[][]}
  545. */
  546. iter_utils.perms = iter => {
  547. const array = [...iter]
  548. if (!array.length) return []
  549. const output = []
  550. const generate = (k, array) => {
  551. if (k === 1) {
  552. output.push(array.slice())
  553. return
  554. }
  555. generate(k - 1, array)
  556. for (let i = 0; i < k - 1; i++) {
  557. if (k % 2 === 0) iter_utils.swap(array, i, k - 1)
  558. else iter_utils.swap(array, 0, k - 1)
  559. generate(k - 1, array)
  560. }
  561. }
  562. generate(array.length, array)
  563. return output
  564. }
  565. /**
  566. * Return a list with every `n`th element of `iter` starting at index `start`
  567. * @template T
  568. * @param {Iterable.<T>} iter The iterable to get elements from
  569. * @param {number} n The step size
  570. * @param {number} [start=0] The starting index
  571. * @returns {T[]}
  572. */
  573. iter_utils.everynth = (iter, n, start = 0) => {
  574. const ret = [];
  575. for (let i = start; i < iter.length; i += n)
  576. ret.push(iter[i])
  577. return ret
  578. }
  579. /**
  580. * Gets the element at `index` in `iter`. Indices wrap around using
  581. * {@link math_utils.wrapindex}. If `index` is a {@link Vec}, `iter` will be
  582. * treated as a grid, or if `index` is a list of integers, a list of elements
  583. * at those indices will be returned.
  584. * @function
  585. * @template T
  586. * @param {Iterable.<T|Iterable.<T>>} iter The iterable to get elements from
  587. * @param {number|Vec|number[]} index The index/indicies to get
  588. * @returns {T}
  589. */
  590. iter_utils.at = tag({ attach_to: [Array] }, (iter, index) => {
  591. const array = [...iter]
  592. if (type_checks.isint(index)) {
  593. return array[math_utils.wrapindex(index, array.length)];
  594. } else if (index instanceof Vec) {
  595. return iter?.[index.y]?.[index.x]
  596. } else if (type_checks.isarr(index) && index.every(type_checks.isint)) {
  597. return index.map(i => iter_utils.at(array, i));
  598. } else {
  599. throw new Error(`Invalid index/indicies ${JSON.stringify(index)}`);
  600. }
  601. })
  602. const count = (iter, value, string_like_match = false, overlapping = false) => {
  603. const array = [...iter]
  604. if (typeof value === "function") return array.filter(value).length
  605. string_like_match = type_checks.isstr(iter) || string_like_match
  606. if (type_checks.isiter(value) && string_like_match) {
  607. const to_find = [...value]
  608. let count = 0
  609. for (let i = 0; i < array.length;) {
  610. if (misc_utils.eq(array.slice(i, i + to_find.length), to_find)) {
  611. count++
  612. i += overlapping ? 1 : to_find.length
  613. } else i++
  614. }
  615. return count
  616. }
  617. return array.filter(x => misc_utils.eq(x, value)).length
  618. }
  619. /**
  620. * Counts the number of times `value` appears in `iter`. If `value` is a
  621. * function, it's will do the same as `.filter(f).length`, if `iter` is a
  622. * string or `string_like_match` is explicitly set to `true`, `["a", "b"]` will
  623. * match `abcd` or ["a", "b", "c", "d"] as well as something like
  624. * ["arstneio", ["a", "b], 4].
  625. * @param {Iterable.<*>} iter The iterable to count values in
  626. * @param {any} value The value to count
  627. * @param {boolean} [string_like_match=false] (See description)
  628. * @returns {number}
  629. * @example [4, 2, 3, 1, 2].count(2) // 2
  630. * @example "abababa".count("aba") // 2
  631. * @example [3, 2, 1, 2, 1].count([2, 1]) // 0
  632. * @example [3, 2, 1, 2, 1].count([2, 1], true) // 2
  633. */
  634. iter_utils.count = (...args) => count(...args)
  635. /**
  636. * Same as `iter_utils.count` but counts overlapping matches
  637. * @param {Iterable.<*>} iter The iterable to count values in
  638. * @param {any} value The value to count
  639. * @param {boolean} [string_like_match=false] (See description)
  640. * @returns {number}
  641. * @example "abababa".countol("aba") // 3
  642. * @example [1, 2, 1, 2, 1].countol([1, 2, 1]) // 2
  643. */
  644. iter_utils.countol = (iter, value, string_like_match = false) => count(iter, value, string_like_match, true)
  645. /**
  646. * Same as the built in [Array.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
  647. * but inverted. For consistency with builtins like `Array.filter` and `Array.map` which _don't_ work on any iterable. This must also be called on an array.
  648. * @template T
  649. * @param {T[]} array The iterable to filter
  650. * @param {function(T): boolean} filter_fn The filter function
  651. * @returns {T[]}
  652. */
  653. iter_utils.filterout = (array, filter_fn) => array.filter((...args) => !filter_fn(...args))
  654. /**
  655. * Checks if there are no elements in `array` that satisfy `fn`. `fn` is passed
  656. * to the built in [Array.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some)
  657. * so refer to those docs if needed.
  658. * @template T
  659. * @param {T[]} array The array to check
  660. * @param {function(T, number, T[]): boolean} fn The function to check
  661. * @returns {boolean}
  662. */
  663. iter_utils.none = (array, fn) => !array.some(fn)
  664. /**
  665. * Gets the differences between consecutive elements of an iterable
  666. * @param {Iterable.<number>} iter The iterable to get deltas from
  667. * @returns {number[]}
  668. * @example [1, 2, 9, -4].deltas // [1, 7, -13]
  669. */
  670. iter_utils.deltas = iter => {
  671. const array = [...iter];
  672. if (array.length <= 1) return [];
  673. const ret = [];
  674. for (let i = 0; i < array.length - 1; i++) {
  675. ret.push(array[i + 1] - array[i]);
  676. }
  677. return ret;
  678. }
  679. /**
  680. * Splits an iterable into `n` pieces. Rounds up if the split is uneven.
  681. * @template T
  682. * @param {Iterable.<T>} iter The iterable to split
  683. * @param {number} n The number of pieces to split into
  684. * @returns {T[][]}
  685. * @example [1, 2, 3, 4, 5, 6].pieces(3) // [[1, 2], [3, 4], [5, 6]]
  686. * @example [1, 2, 3].pieces(2) // [[1, 2], [3]]
  687. */
  688. iter_utils.pieces = (iter, n) => {
  689. if (n <= 0) return []
  690. const array = [...iter], ret = [], step = Math.ceil(array.length / n);
  691. for (let i = 0; i < array.length; i += step) {
  692. ret.push(array.slice(i, i + step))
  693. }
  694. return ret
  695. }
  696. /**
  697. * Returns list of indices where the function `fn` returns true. `fn` receives
  698. * the value, index and the iterable as arguments, in that order.
  699. * @template T
  700. * @param {Iterable.<T>} iter
  701. * @param {function(T, number, Iterable.<T>): boolean} fn
  702. * @returns {number[]}
  703. * @example [1, 2, 3, 4, 5].iwhere(x => x % 2 === 0) // [1, 3]
  704. */
  705. iter_utils.iwhere = (iter, fn) => [...iter]
  706. .map((value, index) => [value, index])
  707. .filter(([value, index]) => fn(value, index, iter))
  708. .map(([, index]) => index)
  709. /**
  710. * Returns a list of sublists containing consecutive elements of `iter`
  711. * @template T
  712. * @param {Iterable.<T>} iter The iterable to group
  713. * @returns {T[][]}
  714. */
  715. iter_utils.seqs = iter => {
  716. const ret = []
  717. for (const value of iter) {
  718. if (ret[ret.length - 1]?.[ret[ret.length - 1].length - 1] === value) {
  719. ret[ret.length - 1].push(value)
  720. } else {
  721. ret.push([value])
  722. }
  723. }
  724. return ret
  725. }
  726. /**
  727. * Checks if an iterable includes a value. Uses {@link iter_utils.count}.
  728. * @template T
  729. * @param {Iterable.<T>} iter The iterable to check
  730. * @param {T} value The value to check for
  731. * @param {number} [start_index=0] The index to start checking from
  732. * @returns {boolean}
  733. */
  734. iter_utils.includes = tag({ attach_to: [Array] }, (iter, value, start_index) => {
  735. if (typeof iter === "string") return iter.includes(value, start_index)
  736. return [...iter].filter(x => misc_utils.eq(x, value)).length > 0
  737. })
  738. /** Alias for {@link iter_utils.includes}
  739. * @template T
  740. * @param {Iterable.<T>} iter The iterable to check
  741. * @param {T} value The value to check for
  742. * @param {number} [start_index=0] The index to start checking from
  743. * @returns {boolean}
  744. */
  745. iter_utils.incl = iter_utils.includes
  746. /**
  747. * Deep flattens an iterable
  748. * @template T
  749. * @param {Iterable.<T>} iter The iterable to flatten
  750. * @returns {T[]}
  751. * @example [[1, [2]], [[[[3, [4, 5]]]]], 6].flat // [1, 2, 3, 4, 5, 6]
  752. */
  753. iter_utils.flat = iter => [...iter].flat(Infinity)
  754. /**
  755. * Flattens an iterable to a certain depth. Alias for the builtin [Array.flat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat).
  756. * @template T
  757. * @param {Iterable.<T>} iter The iterable to flatten
  758. * @param {number} [depth=1] The depth to flatten to
  759. * @returns {T[]}
  760. */
  761. iter_utils.nflat = (iter, depth = 1) => [...iter].flat(depth)
  762. /** @namespace */
  763. const string_utils = {}
  764. /**
  765. * Splits a string into an array of characters
  766. * @param {string} str The string to split
  767. * @returns {string[]}
  768. */
  769. string_utils.chars = str => str.split("")
  770. /**
  771. * Splits a string on spaces and trims each word
  772. * @param {string} str The string to split
  773. * @returns {string[]}
  774. */
  775. string_utils.words = str => str.split(" ").map(s => s.trim())
  776. /**
  777. * Splits a string on "\n"
  778. * @param {string} str The string to split
  779. * @returns {string[]}
  780. */
  781. string_utils.lines = str => str.split("\n")
  782. /**
  783. * Splits a string on "\n\n"
  784. * @param {string} str The string to split
  785. * @returns {string[]}
  786. */
  787. string_utils.groups = str => str.split("\n\n")
  788. /**
  789. * Splits a string on commas and trims each element
  790. * @param {string} str The string to split
  791. * @returns {string[]}
  792. */
  793. string_utils.csv = str => str.split(",").map(s => s.trim())
  794. /**
  795. * Checks if a character is a digit
  796. * @param {string} char The character to check
  797. * @returns {boolean}
  798. */
  799. string_utils.isdigit = char => /^\d$/.test(char)
  800. /**
  801. * Extracts all integers from a string and returns them in an array
  802. * @param {string} str The string to extract integers from
  803. * @returns {number[]}
  804. */
  805. string_utils.ints = str => str.match(/-?\d+/g).map(type_casts.int)
  806. /**
  807. * Extracts all numbers from a string and returns them in an array
  808. * @param {string} str The string to extract numbers from
  809. * @returns {number[]}
  810. */
  811. string_utils.nums = str => str.match(/\d+(\.\d+)?/g).map(type_casts.num)
  812. /**
  813. * Gets the ASCII code a character
  814. * @param {string} char The character to get the code of
  815. * @returns {number}
  816. */
  817. string_utils.chcode = char => char.charCodeAt(0)
  818. /**
  819. * Converts a string to upper case
  820. * @param {string} str The string to convert
  821. * @returns {string}
  822. */
  823. string_utils.upper = str => str.toUpperCase()
  824. /**
  825. * Converts a string to lower case
  826. * @param {string} str The string to convert
  827. * @returns {string}
  828. */
  829. string_utils.lower = str => str.toLowerCase()
  830. /** @namespace */
  831. const logic_utils = {}
  832. /**
  833. * Returns `a && b`. I.e. if `a` is truthy it returns `b`, otherwise it short
  834. * circuits and returns `a`
  835. * @param {any} a
  836. * @param {any} b
  837. * @returns {any}
  838. */
  839. logic_utils.and = (a, b) => a && b
  840. /**
  841. * Returns `a || b`. I.e. if `a` is truthy it short circuits and returns `a`,
  842. * otherwise it returns `b`
  843. * @param {any} a
  844. * @param {any} b
  845. * @returns {any}
  846. */
  847. logic_utils.or = (a, b) => a || b
  848. /**
  849. * Returns logical NOT of `a`
  850. * @param {any} a
  851. * @returns {boolean}
  852. */
  853. logic_utils.not = a => !a
  854. /**
  855. * Returns logical XOR of `a` and `b`. I.e. returns true if exactly one of `a`
  856. * and `b` are truthy, otherwise returns false
  857. * @param {any} a
  858. * @param {any} b
  859. * @returns {boolean}
  860. */
  861. logic_utils.xor = (a, b) => !!(!a ^ !b)
  862. /** @namespace */
  863. const grid_utils = {}
  864. /**
  865. * Creates a grid from a string where each row is separated by a newline and
  866. * each cell is seperated by `delim`.
  867. * @param {string} str The string to create a grid from
  868. * @param {string} delim The delimiter to split cells by
  869. * @returns {string[][]}
  870. */
  871. grid_utils.gridd = (str, delim) => str.trim().split("\n").filter(x => x).map(row => row.split(delim).filter(x => x))
  872. /**
  873. * Calls with {@link grid_utils.gridd} with an empty delimiter
  874. * @param {string} str The string to create a grid from
  875. * @returns {string[][]}
  876. */
  877. grid_utils.grid = str => grid_utils.gridd(str, "")
  878. /**
  879. * Uses {@link grid_utils.grid} then maps each cell to a number
  880. * @param {string} str The string to create a grid from
  881. * @returns {number[][]}
  882. */
  883. grid_utils.digitgrid = str => grid_utils.grid(str).map(row => row.map(cell => +cell))
  884. /**
  885. * Maps a function over each cell in a grid
  886. * @template T
  887. * @template K
  888. * @param {T[][]} grid The grid to map over
  889. * @param {function(T, Vec, T[][]): K} fn The function to map
  890. * @returns {K[][]}
  891. */
  892. grid_utils.gmap = (grid, fn) => grid.map((row, y) => row.map((cell, x) => fn(cell, new Vec(x, y), grid)))
  893. /**
  894. * Finds {@link Vec}s in a grid which satisfy the given function
  895. * @template T
  896. * @param {T[][]} grid The grid to search
  897. * @param {function(T, Vec, T[][]): boolean} fn The function to filter with
  898. * @returns {Vec[]}
  899. */
  900. grid_utils.vecswhere = (grid, fn) => grid.flatMap(
  901. (row, y) => row
  902. .map((cell, x) => [cell, new Vec(x, y)])
  903. .filter(args => fn(...args, grid))
  904. .map(([, vec]) => vec)
  905. )
  906. /**
  907. * Rotates a grid 90 degrees clockwise `times` times
  908. * @param {T[][]} grid The grid to rotate
  909. * @param {number} [times=1] The number of times to rotate
  910. * @returns {T[][]}
  911. */
  912. grid_utils.nrotate = (grid, times = 1) => {
  913. if (!grid.length) return []
  914. let ret = grid.map(row => row.slice())
  915. for (let i = 0; i < times; i++) {
  916. ret = ret[0].map((_, i) => ret.map(row => row[i]).reverse())
  917. }
  918. return ret
  919. }
  920. /**
  921. * Rotates a grid 90 degrees clockwise once (alias for `grid_utils.nrotate(grid, 1)`)
  922. * @param {T[][]} grid The grid to rotate
  923. * @returns {T[][]}
  924. */
  925. grid_utils.rotate = grid => grid_utils.nrotate(grid, 1)
  926. /**
  927. * Gets diagonals of a grid (top right to bottom left). Assumes the grid is rectangular.
  928. * @param {T[][]} grid The grid to get diagonals from
  929. * @returns {T[][]}
  930. * @example diagonals([
  931. * [1, 2, 3],
  932. * [4, 5, 6],
  933. * [7, 8, 9]
  934. * ]) // [[1], [2, 4], [3, 5, 7], [6, 8], [9]]
  935. */
  936. grid_utils.diagonals = grid => {
  937. const ret = []
  938. for (let r = 0; r < grid.length; r++) {
  939. for (let c = 0; c < grid[0].length; c++) {
  940. ret[r + c] ??= []
  941. ret[r + c].push(grid[r][c])
  942. }
  943. }
  944. return ret
  945. }
  946. /**
  947. * Gets diagonals of a grid in the other direction to {@link grid_utils.diagonals}
  948. * (so top left to bottom right). Assumes the grid is rectangular.
  949. * @param {T[][]} grid The grid to get diagonals from
  950. * @returns {T[][]}
  951. * @example antidiagonals([
  952. * [1, 2, 3],
  953. * [4, 5, 6],
  954. * [7, 8, 9]
  955. * ]) // [[3], [2, 6], [1, 5, 9], [4, 8], [7]]
  956. */
  957. grid_utils.antidiagonals = grid => {
  958. const ret = [], width = grid[0]?.length
  959. for (let r = 0; r < grid.length; r++) {
  960. for (let c = 0; c < width; c++) {
  961. ret[r + (width - 1 - c)] ??= []
  962. ret[r + (width - 1 - c)].push(grid[r][c])
  963. }
  964. }
  965. return ret
  966. }
  967. /**
  968. * **[Global]** Creates a grid of size `width` by `height` filled with `fill`.
  969. * Fill defaults to `null`.
  970. * @template T
  971. * @param {number} width The width of the grid
  972. * @param {number} height The height of the grid
  973. * @param {T} [fill=null] The value to fill the grid with
  974. * @returns {T[][]}
  975. */
  976. grid_utils.emptygrid = tag(
  977. { keep_global: true },
  978. (width, height, fill = null) => Array(height).fill().map(() => Array(width).fill(fill))
  979. )
  980. /**
  981. * **[Global]** Prints a grid and returns it. If the shortest cell is only 1 character long
  982. * then the grid will be printed without spaces between cells.
  983. * @function
  984. * @template T
  985. * @param {T[][]} grid
  986. * @returns {T[][]}
  987. */
  988. grid_utils.gprint = tag({ keep_global: true }, grid => {
  989. const longest_cell = Math.max(...grid.flatMap(
  990. row => row.map(cell => cell.toString().length)
  991. ))
  992. console.log(grid.map(row => row.map(
  993. cell => cell.toString().padEnd(longest_cell)
  994. ).join(longest_cell > 1 ? " " : "")).join("\n"))
  995. return grid
  996. })
  997. /**
  998. * Alias for {@link grid_utils.gprint}
  999. * @template T
  1000. * @param {T[][]} grid
  1001. * @returns {T[][]}
  1002. */
  1003. grid_utils.gpr = grid => grid_utils.gprint(grid)
  1004. /**
  1005. * Sets value at the given vector in a grid. If the cell doesn't exist, it will be created.
  1006. * @template T
  1007. * @param {T[][]} grid The grid to set the value in
  1008. * @param {Vec} vec The vector to set the value at
  1009. * @param {T} value The value to set
  1010. * @returns {T[][]} The modified grid
  1011. */
  1012. grid_utils.gset = (grid, vec, value) => {
  1013. const row = grid[vec.y]
  1014. if (!row) grid[vec.y] = []
  1015. grid[vec.y][vec.x] = value
  1016. return grid
  1017. }
  1018. /**
  1019. * Returns the first vector in a grid (searching top to bottom, left to right)
  1020. * where the function `fn` is truthy for that cell. `fn` also receives the
  1021. * position of each cell and a reference to the grid.
  1022. * @template T
  1023. * @param {T[][]} grid The grid to search
  1024. * @param {function(T, Vec, T[][]): boolean} fn The function to search with
  1025. * @returns {Vec}
  1026. */
  1027. grid_utils.vecwhere = (grid, fn) => {
  1028. for (let y = 0; y < grid.length; y++) {
  1029. for (let x = 0; x < grid[y].length; x++) {
  1030. if (fn(grid[y][x], new Vec(x, y), grid)) return new Vec(x, y)
  1031. }
  1032. }
  1033. return null
  1034. }
  1035. /**
  1036. * Returns the first cell in a grid (searching top to bottom, left to right)
  1037. * where the function `fn` is truthy for that cell. `fn` also receives the
  1038. * position of each cell and a reference to the grid.
  1039. * @template T
  1040. * @param {T[][]} grid The grid to search
  1041. * @param {function(T, Vec, T[][]): boolean} fn The function to search with
  1042. * @returns {T}
  1043. */
  1044. grid_utils.gfind = (grid, fn) => {
  1045. for (let y = 0; y < grid.length; y++) {
  1046. for (let x = 0; x < grid[y].length; x++) {
  1047. if (fn(grid[y][x], new Vec(x, y), grid)) return grid[y][x]
  1048. }
  1049. }
  1050. return null
  1051. }
  1052. /** @namespace */
  1053. const object_utils = {}
  1054. /**
  1055. * Same as the built in [Object.keys](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys)
  1056. * @param {object} obj The object to get keys from
  1057. * @returns {string[]}
  1058. */
  1059. object_utils.keys = obj => Object.keys(obj)
  1060. /**
  1061. * Same as the built in [Object.values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values)
  1062. * @param {object} obj The object to get values from
  1063. * @returns {any[]}
  1064. */
  1065. object_utils.values = obj => Object.values(obj)
  1066. /**
  1067. * Same as the built in [Object.entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries)
  1068. * @param {object} obj The object to get entries from
  1069. * @returns {any[]} An array of key-value tuples
  1070. */
  1071. object_utils.entries = obj => Object.entries(obj)
  1072. /** @namespace */
  1073. const misc_utils = {}
  1074. /**
  1075. * **[Global]** Checks `a` and `b` are equal. In theory this works for any two values,
  1076. * whether they're primitives, arrays or some other object.
  1077. * @function
  1078. * @param {any} a
  1079. * @param {any} b
  1080. * @returns {boolean}
  1081. */
  1082. misc_utils.eq = tag({ keep_global: true }, (a, b) => {
  1083. if (Array.isArray(a) && Array.isArray(b)) {
  1084. if (a.length !== b.length) return false;
  1085. for (let i = 0; i < a.length; i++)
  1086. if (!misc_utils.eq(a[i], b[i])) return false;
  1087. return true;
  1088. } else if (typeof a === "object" && typeof b === "object") {
  1089. return JSON.stringify(a) === JSON.stringify(b);
  1090. } else return a === b;
  1091. })
  1092. /**
  1093. * **[Global]** Checks `a` and `b` are not equal (by negating `misc_utils.eq`)
  1094. * @function
  1095. * @param {any} a
  1096. * @param {any} b
  1097. * @returns {boolean}
  1098. */
  1099. misc_utils.neq = tag({ keep_global: true }, (a, b) => !eq(a, b))
  1100. /**
  1101. * **[Global]** Creates the range `[a, b)` in an array with an optional step size
  1102. * @function
  1103. * @param {number} a End of the range (if `b` is not provided)
  1104. * @param {number} [b=0] End of the range (if provided, in which case `a` is the start)
  1105. * @param {number} [step=1]
  1106. * @returns {number[]}
  1107. * @example range(4) // [0, 1, 2, 3]
  1108. * @example range(2, 5) // [2, 3, 4]
  1109. * @example range(1, 10, 2) // [1, 3, 5, 7, 9]
  1110. */
  1111. misc_utils.range = tag({ keep_global: true }, function(a, b = 0, step = 1) {
  1112. let start = 0, end = a
  1113. if (arguments.length > 1) {
  1114. start = a
  1115. end = b
  1116. }
  1117. const ret = [];
  1118. for (let n = start; n < end; n += step)
  1119. ret.push(n)
  1120. return ret
  1121. })
  1122. /**
  1123. * **[Global]** Same as `console.log` its arg(s)
  1124. * @function
  1125. * @template T
  1126. * @param {...T} values Values to print
  1127. * @returns {T|T[]}
  1128. */
  1129. misc_utils.print = tag({ keep_global: true }, (...values) => {
  1130. console.log(...values)
  1131. return values.length > 1 ? values : values[0]
  1132. })
  1133. /**
  1134. * **[Global]** Same as `misc_utils.print` but niladic (so that it becomes a getter)
  1135. * @template T
  1136. * @param {T} value Value to print
  1137. * @returns {T}
  1138. */
  1139. misc_utils.pr = value => misc_utils.print(value)
  1140. /**
  1141. * **[Global]** Tries to get the length property of `value` otherwise tries to get `size`
  1142. * @function
  1143. * @param {any} value Value to get the length/size of
  1144. * @returns {?number}
  1145. */
  1146. misc_utils.len = value => value?.length ?? value?.size
  1147. /**
  1148. * Wraps a value in a singleton list
  1149. * @function
  1150. * @template T
  1151. * @param {T} value Value to wrap
  1152. * @returns {T[]}
  1153. */
  1154. misc_utils.wrap = value => [value]
  1155. /**
  1156. * Finds the number of corners in an area
  1157. * @param {_Set<Vec>} area The area to find corners in
  1158. * @returns {number}
  1159. */
  1160. misc_utils.corners = area => {
  1161. const xs = [...area].map(v => v.x)
  1162. const ys = [...area].map(v => v.y)
  1163. let corners = 0
  1164. for (let x = Math.min(...xs) - 1; x <= Math.max(...xs); x++) {
  1165. for (let y = Math.min(...ys) - 1; y <= Math.max(...ys); y++) {
  1166. const subgrid = [new Vec(x, y), new Vec(x + 1, y), new Vec(x, y + 1), new Vec(x + 1, y + 1)]
  1167. const in_area = subgrid.map(v => area.has(v))
  1168. const count_in_area = in_area.filter(x => x).length
  1169. if (count_in_area == 1 || count_in_area == 3) corners++
  1170. else if (
  1171. misc_utils.eq(in_area, [true, false, false, true]) ||
  1172. misc_utils.eq(in_area, [false, true, true, false])
  1173. ) corners += 2
  1174. }
  1175. }
  1176. return corners
  1177. }
  1178. /**
  1179. * **[Global]** Exits the program (alias for [process.exit](https://nodejs.org/api/process.html#process_process_exit_code))
  1180. * @param {number|string} [exit_code=0]
  1181. * @returns {void}
  1182. */
  1183. misc_utils.exit = tag({ keep_global: true }, (exit_code = process.exitCode ?? 0) => process.exit(exit_code))
  1184. /** @namespace */
  1185. const constructors = {}
  1186. /**
  1187. * **[Global]** Calls `new _Set(iter)`. See the documentation for `{@link _Set}` for more info
  1188. * @function
  1189. * @param {Iterable.<*>} iter The iterable to create the set from
  1190. * @returns {_Set}
  1191. */
  1192. constructors.S = tag({ keep_global: true }, (iter = []) => new _Set(iter))
  1193. /**
  1194. * **[Global]** Calls `new Vec(x, y)`. See the documentation for `{@link Vec}` for more info
  1195. * @function
  1196. * @param {number} x The x component of the vector
  1197. * @param {number} y The y component of the vector
  1198. * @returns {Vec}
  1199. */
  1200. constructors.V = tag({ keep_global: true }, (x, y) => new Vec(x, y))
  1201. export default {
  1202. ...type_checks,
  1203. ...type_casts,
  1204. ...math_utils,
  1205. ...string_utils,
  1206. ...iter_utils,
  1207. ...object_utils,
  1208. ...logic_utils,
  1209. ...grid_utils,
  1210. ...misc_utils,
  1211. ...constructors
  1212. }