@vbarbarosh/node-helpers 3.74.1 → 3.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) hide show
  1. package/README.md +29 -3
  2. package/dist/browser.js +1 -2504
  3. package/package.json +31 -11
  4. package/src/HeartbeatServer.js +24 -3
  5. package/src/HeartbeatServer.md +33 -0
  6. package/src/array_chunk.js +1 -1
  7. package/src/array_chunk.md +8 -0
  8. package/src/array_chunk_balanced.md +14 -0
  9. package/src/array_fps.md +12 -0
  10. package/src/array_gcd.js +4 -2
  11. package/src/array_gcd.md +2 -1
  12. package/src/array_group.js +3 -3
  13. package/src/array_group.md +14 -0
  14. package/src/array_group_map.js +3 -3
  15. package/src/array_group_map.md +13 -0
  16. package/src/array_index.js +2 -2
  17. package/src/array_index.md +9 -0
  18. package/src/array_lcm.js +4 -2
  19. package/src/array_lcm.md +2 -1
  20. package/src/array_max.js +11 -4
  21. package/src/array_max.md +1 -1
  22. package/src/array_min.js +11 -4
  23. package/src/array_min.md +1 -1
  24. package/src/array_permutations.js +4 -0
  25. package/src/array_permutations.md +13 -0
  26. package/src/array_sort.js +7 -2
  27. package/src/array_sort.md +13 -0
  28. package/src/array_sort_other.js +8 -5
  29. package/src/array_sort_other.md +11 -0
  30. package/src/array_sum.js +2 -2
  31. package/src/array_sum.md +8 -0
  32. package/src/array_unique.js +2 -2
  33. package/src/array_unique_last.js +2 -2
  34. package/src/assert_valid_expires_at.md +10 -0
  35. package/src/clamp.md +9 -0
  36. package/src/cli-apps/watchdog.js +5 -0
  37. package/src/cli.js +3 -1
  38. package/src/cli.md +15 -0
  39. package/src/const_stream.md +7 -0
  40. package/src/const_type.md +5 -0
  41. package/src/countdown.js +22 -5
  42. package/src/countdown.md +21 -0
  43. package/src/crypto_decrypt_aes256.md +13 -0
  44. package/src/crypto_encrypt_aes256.md +13 -0
  45. package/src/crypto_hash_md5.md +10 -0
  46. package/src/crypto_hash_sha256.md +10 -0
  47. package/src/crypto_hmac_sha256.md +11 -0
  48. package/src/date_add_hours.md +8 -0
  49. package/src/date_add_milliseconds.md +4 -0
  50. package/src/date_add_minutes.md +4 -0
  51. package/src/date_add_months.md +13 -0
  52. package/src/date_add_seconds.md +4 -0
  53. package/src/date_diff_seconds.md +4 -0
  54. package/src/date_is_leap_year.md +9 -0
  55. package/src/escape_content_disposition.js +6 -3
  56. package/src/escape_content_disposition.md +13 -0
  57. package/src/escape_regexp.md +7 -0
  58. package/src/eta.js +7 -1
  59. package/src/eta.md +18 -0
  60. package/src/factorize_ms.js +3 -0
  61. package/src/factorize_ms.md +10 -0
  62. package/src/fastdl.js +14 -3
  63. package/src/fcmp_dates.md +12 -0
  64. package/src/fcmp_default.js +7 -0
  65. package/src/fcmp_default.md +29 -0
  66. package/src/fcmp_default_desc.js +4 -7
  67. package/src/fcmp_default_desc.md +10 -0
  68. package/src/fcmp_from_spec.md +13 -0
  69. package/src/fcmp_numbers.md +11 -0
  70. package/src/fcmp_tuples.md +17 -0
  71. package/src/fcmp_utf8_bin.md +14 -0
  72. package/src/fcmp_utf8_ci.md +14 -0
  73. package/src/fcmp_utf8_cs.md +15 -0
  74. package/src/fcmp_utf8_natural_bin.js +38 -0
  75. package/src/fcmp_utf8_natural_bin.md +8 -0
  76. package/src/fcmp_utf8_natural_ci.md +13 -0
  77. package/src/fcmp_utf8_natural_cs.md +13 -0
  78. package/src/fcmpx.md +26 -9
  79. package/src/filter1_from_spec.js +3 -3
  80. package/src/format_bytes.md +15 -0
  81. package/src/format_date.md +7 -0
  82. package/src/format_date_fs.md +7 -0
  83. package/src/format_date_human.md +6 -0
  84. package/src/format_date_ymd.md +6 -0
  85. package/src/format_error_report.js +3 -3
  86. package/src/format_error_report.md +12 -0
  87. package/src/format_kilo.md +13 -0
  88. package/src/format_ms.js +3 -2
  89. package/src/format_ms.md +12 -0
  90. package/src/format_ms2.js +6 -3
  91. package/src/format_ms2.md +12 -0
  92. package/src/format_ms3.js +3 -2
  93. package/src/format_ms3.md +12 -0
  94. package/src/format_percents.md +10 -0
  95. package/src/format_progress_bytes.md +13 -0
  96. package/src/format_progress_kilo.md +10 -0
  97. package/src/format_seconds.md +11 -0
  98. package/src/format_thousands.md +9 -0
  99. package/src/fs_append.md +7 -0
  100. package/src/fs_append_json.md +8 -0
  101. package/src/fs_append_utf8.md +6 -0
  102. package/src/fs_assert_file_exists.md +3 -0
  103. package/src/fs_assert_file_readable.js +1 -1
  104. package/src/fs_assert_file_readable.md +3 -0
  105. package/src/fs_assert_file_socket.md +2 -0
  106. package/src/fs_copy.md +7 -0
  107. package/src/fs_copy_excl.md +2 -0
  108. package/src/fs_exists.md +6 -0
  109. package/src/fs_fclose.md +5 -0
  110. package/src/fs_fi.js +13 -1
  111. package/src/fs_fi.md +11 -0
  112. package/src/fs_file_md5.md +8 -0
  113. package/src/fs_find.md +7 -0
  114. package/src/fs_fopen.md +6 -0
  115. package/src/fs_fread.js +2 -2
  116. package/src/fs_fread.md +11 -0
  117. package/src/fs_fsize.md +2 -0
  118. package/src/fs_fstat.md +2 -0
  119. package/src/fs_fwrite.js +2 -2
  120. package/src/fs_fwrite.md +9 -0
  121. package/src/fs_list.md +5 -0
  122. package/src/fs_list_deep.md +5 -0
  123. package/src/fs_ls.md +2 -0
  124. package/src/fs_lsr.md +4 -0
  125. package/src/fs_lstat.md +3 -0
  126. package/src/fs_mkdir.md +3 -0
  127. package/src/fs_mkdirp.js +3 -30
  128. package/src/fs_mkdirp.md +7 -0
  129. package/src/fs_path_basename.md +2 -0
  130. package/src/fs_path_dirname.md +2 -0
  131. package/src/fs_path_extname.md +9 -0
  132. package/src/fs_path_join.md +2 -0
  133. package/src/fs_path_relative.md +2 -0
  134. package/src/fs_path_resolve.md +2 -0
  135. package/src/fs_path_tempdir.md +2 -0
  136. package/src/fs_path_untildify.md +8 -0
  137. package/src/fs_read.md +3 -0
  138. package/src/fs_read_buffer.md +5 -0
  139. package/src/fs_read_json.md +6 -0
  140. package/src/fs_read_lines.md +7 -0
  141. package/src/fs_read_stream.md +2 -0
  142. package/src/fs_read_utf8.md +5 -0
  143. package/src/fs_readdir.md +3 -0
  144. package/src/fs_readlink.md +6 -0
  145. package/src/fs_rename.md +6 -0
  146. package/src/fs_rm.md +4 -0
  147. package/src/fs_rmdir.md +3 -0
  148. package/src/fs_rmf.md +2 -0
  149. package/src/fs_rmrf.md +8 -0
  150. package/src/fs_sha256.js +16 -0
  151. package/src/fs_sha256.md +9 -0
  152. package/src/fs_size.js +2 -2
  153. package/src/fs_size.md +6 -0
  154. package/src/fs_stat.md +2 -0
  155. package/src/fs_tempdir.js +20 -5
  156. package/src/fs_touch.md +6 -0
  157. package/src/fs_walk.js +2 -2
  158. package/src/fs_walk.md +14 -0
  159. package/src/fs_write.md +3 -0
  160. package/src/fs_write_json.md +7 -0
  161. package/src/fs_write_stream.md +2 -0
  162. package/src/gettype.md +13 -0
  163. package/src/http_delete.md +11 -0
  164. package/src/http_get_blob.md +8 -0
  165. package/src/http_get_buffer.md +10 -0
  166. package/src/http_get_file.js +8 -8
  167. package/src/http_get_file.md +14 -0
  168. package/src/http_get_json.md +10 -0
  169. package/src/http_get_stream.md +14 -0
  170. package/src/http_get_stream_range.js +27 -9
  171. package/src/http_get_stream_range.md +22 -0
  172. package/src/http_get_utf8.md +9 -0
  173. package/src/http_head.md +9 -0
  174. package/src/http_patch_json.md +10 -0
  175. package/src/http_post_json.md +11 -0
  176. package/src/http_post_multipart.md +15 -0
  177. package/src/http_post_urlencoded.md +11 -0
  178. package/src/http_put_buffer.md +9 -0
  179. package/src/http_put_file.js +9 -6
  180. package/src/http_put_file.md +16 -0
  181. package/src/http_put_json.md +11 -0
  182. package/src/http_put_utf8.md +9 -0
  183. package/src/http_range_parse.js +6 -3
  184. package/src/http_range_parse.md +18 -0
  185. package/src/http_stream_range.js +35 -22
  186. package/src/http_stream_range.md +29 -0
  187. package/src/identity.md +2 -0
  188. package/src/ignore.md +2 -0
  189. package/src/json_stringify_safe.md +10 -0
  190. package/src/json_stringify_stable.md +9 -0
  191. package/src/logger.js +2 -3
  192. package/src/logger.md +15 -0
  193. package/src/make_progress.js +8 -5
  194. package/src/make_progress.md +20 -0
  195. package/src/math_gcd.js +2 -1
  196. package/src/mongo_stream_upsert.js +10 -3
  197. package/src/mongo_stream_upsert.md +17 -0
  198. package/src/mongo_stream_write.js +10 -3
  199. package/src/mongo_stream_write.md +16 -0
  200. package/src/msval.md +10 -0
  201. package/src/now_fs.md +7 -0
  202. package/src/now_human.md +6 -0
  203. package/src/object_defaults.md +11 -0
  204. package/src/object_schema.js +2 -1
  205. package/src/object_schema.md +12 -0
  206. package/src/object_walk_preorder.md +16 -0
  207. package/src/parallel.js +23 -10
  208. package/src/parse_bytes.js +4 -2
  209. package/src/parse_bytes.md +15 -0
  210. package/src/parse_hms.js +1 -1
  211. package/src/parse_http_content_range.js +9 -5
  212. package/src/parse_http_content_range.md +16 -0
  213. package/src/perf_end_human.md +10 -0
  214. package/src/perf_end_ms.md +8 -0
  215. package/src/perf_measure.md +10 -0
  216. package/src/perf_measure_human.md +8 -0
  217. package/src/perf_start.md +9 -0
  218. package/src/pgid_exists.md +6 -0
  219. package/src/pgid_kill_grace.js +1 -1
  220. package/src/pgid_kill_grace.md +15 -0
  221. package/src/pid_exists.md +5 -0
  222. package/src/pid_kill_grace.js +1 -1
  223. package/src/pid_kill_grace.md +14 -0
  224. package/src/plural.md +13 -0
  225. package/src/random_hex.md +9 -0
  226. package/src/random_int.md +8 -0
  227. package/src/range.js +4 -2
  228. package/src/range.md +2 -0
  229. package/src/redis_connect.js +1 -1
  230. package/src/redis_connect.md +10 -0
  231. package/src/redis_lshift.md +14 -0
  232. package/src/redis_poll.js +1 -0
  233. package/src/redis_poll.md +17 -0
  234. package/src/redis_poll_zshift_callback_rpush.js +1 -2
  235. package/src/redis_poll_zshift_callback_rpush.md +17 -0
  236. package/src/redis_poll_zshift_spawn_rpush.js +2 -1
  237. package/src/redis_poll_zshift_spawn_rpush.md +20 -0
  238. package/src/redis_zshift.md +14 -0
  239. package/src/round.js +7 -8
  240. package/src/round.md +15 -0
  241. package/src/sanitize_dash_name.md +13 -0
  242. package/src/sanitize_filename.md +9 -0
  243. package/src/sanitize_var_name.md +14 -0
  244. package/src/sftp_get_file_info.js +2 -2
  245. package/src/sftp_get_file_info.md +14 -0
  246. package/src/sftp_get_stream_range.js +32 -22
  247. package/src/sftp_get_stream_range.md +20 -0
  248. package/src/shell_curl_progress.js +2 -1
  249. package/src/shell_curl_progress.md +17 -0
  250. package/src/shell_lines.js +2 -2
  251. package/src/shell_lines.md +1 -1
  252. package/src/shell_spawn.js +7 -0
  253. package/src/shell_ytdlp_progress.js +2 -1
  254. package/src/shell_ytdlp_progress.md +17 -0
  255. package/src/str_camel_to_snake.md +11 -0
  256. package/src/str_parse_kv.md +11 -0
  257. package/src/stream_curl_progress.md +14 -0
  258. package/src/stream_data_ln.js +7 -1
  259. package/src/stream_discard.md +8 -0
  260. package/src/stream_group.md +3 -0
  261. package/src/stream_gunzip.md +7 -0
  262. package/src/stream_hash.md +10 -0
  263. package/src/stream_map.js +8 -1
  264. package/src/stream_map_parallel.js +9 -1
  265. package/src/stream_md5.md +9 -0
  266. package/src/stream_multiplex.js +11 -0
  267. package/src/stream_multiplex.md +16 -0
  268. package/src/stream_through.md +3 -0
  269. package/src/stream_transform.md +2 -0
  270. package/src/stream_xml_analyze.js +9 -1
  271. package/src/stream_xml_parse.js +9 -1
  272. package/src/stream_ytdlp_progress.js +1 -1
  273. package/src/stream_ytdlp_progress.md +18 -0
  274. package/src/strtr.js +15 -5
  275. package/src/strtr.md +11 -0
  276. package/src/urlclean.js +9 -2
  277. package/src/urlmod.js +5 -0
  278. package/src/urlparts.md +17 -0
  279. package/src/wait_while.js +1 -1
  280. package/src/wait_while.md +1 -1
  281. package/src/HeartbeatServer.test.js +0 -31
  282. package/src/array_chunk.test.js +0 -24
  283. package/src/array_chunk_balanced.test.js +0 -37
  284. package/src/array_fps.test.js +0 -72
  285. package/src/array_gcd.test.js +0 -10
  286. package/src/array_index.test.js +0 -14
  287. package/src/array_lcm.test.js +0 -12
  288. package/src/array_max.test.js +0 -20
  289. package/src/array_min.test.js +0 -20
  290. package/src/array_permutations.test.js +0 -20
  291. package/src/array_sort.test.js +0 -85
  292. package/src/array_sort_other.test.js +0 -9
  293. package/src/array_sum.test.js +0 -11
  294. package/src/cli-apps/watchdog.d/connect_close.js +0 -17
  295. package/src/cli-apps/watchdog.d/connect_close2.js +0 -20
  296. package/src/cli-apps/watchdog.d/connect_close3.js +0 -25
  297. package/src/cli-apps/watchdog.d/connect_no_ping.js +0 -13
  298. package/src/cli-apps/watchdog.d/early_exit.js +0 -7
  299. package/src/cli-apps/watchdog.d/flood.js +0 -13
  300. package/src/cli-apps/watchdog.d/flood2.js +0 -15
  301. package/src/cli-apps/watchdog.d/hang.js +0 -8
  302. package/src/cli-apps/watchdog.d/huge_delay.js +0 -18
  303. package/src/cli-apps/watchdog.d/ignore_sigterm.js +0 -29
  304. package/src/cli-apps/watchdog.d/late_heartbeat.js +0 -21
  305. package/src/cli-apps/watchdog.d/my-exit-after-2-pings.js +0 -16
  306. package/src/cli-apps/watchdog.d/my-happy-path.js +0 -16
  307. package/src/cli-apps/watchdog.d/my-ignore-sigterm.js +0 -22
  308. package/src/cli-apps/watchdog.d/my-never-ping.js +0 -15
  309. package/src/cli-apps/watchdog.d/no_heartbeat.js +0 -5
  310. package/src/cli-apps/watchdog.d/ok.js +0 -17
  311. package/src/cli-apps/watchdog.d/quick-exit-after-2-pings.js +0 -15
  312. package/src/cli-apps/watchdog.d/quick-hang-after-1-ping.js +0 -15
  313. package/src/cli-apps/watchdog.d/spawn_children.js +0 -14
  314. package/src/cli-apps/watchdog.test.js +0 -48
  315. package/src/crypto_encrypt_aes256.test.js +0 -10
  316. package/src/crypto_hash_sha256.test.js +0 -10
  317. package/src/date_add_months.test.js +0 -40
  318. package/src/date_is_leap_year.test.js +0 -14
  319. package/src/escape_content_disposition.test.js +0 -22
  320. package/src/fcmp_from_spec.test.js +0 -91
  321. package/src/fcmpx.test.js +0 -173
  322. package/src/filter1_from_spec.test.js +0 -31
  323. package/src/format_bytes.test.js +0 -22
  324. package/src/format_error_report.d/src/1.js +0 -26
  325. package/src/format_error_report.d/src/2.js +0 -29
  326. package/src/format_kilo.test.js +0 -25
  327. package/src/format_ms.test.js +0 -33
  328. package/src/format_ms2.test.js +0 -33
  329. package/src/format_ms3.test.js +0 -33
  330. package/src/format_percents.test.js +0 -22
  331. package/src/format_progress_bytes.test.js +0 -19
  332. package/src/format_progress_kilo.test.js +0 -19
  333. package/src/format_seconds.test.js +0 -42
  334. package/src/format_thousands.test.js +0 -28
  335. package/src/fs_file_md5.test.js +0 -11
  336. package/src/fs_mkdirp.test.js +0 -24
  337. package/src/fs_path_extname.test.js +0 -22
  338. package/src/gettype.test.js +0 -27
  339. package/src/object_schema.test.js +0 -15
  340. package/src/object_walk_preorder.test.js +0 -17
  341. package/src/parallel.test.js +0 -11
  342. package/src/parse_bytes.test.js +0 -21
  343. package/src/parse_hms.test.js +0 -32
  344. package/src/parse_http_content_range.test.js +0 -14
  345. package/src/pid_kill_grace.d/ignore-sigterm-for-10ms.js +0 -33
  346. package/src/pid_kill_grace.d/ignore-sigterm.js +0 -22
  347. package/src/pid_kill_grace.test.js +0 -63
  348. package/src/ping_socket.test.js +0 -58
  349. package/src/plural.test.js +0 -20
  350. package/src/range.test.js +0 -41
  351. package/src/redis_lshift.test.js +0 -57
  352. package/src/redis_zshift.test.js +0 -58
  353. package/src/round.test.js +0 -56
  354. package/src/sanitize_dash_name.test.js +0 -59
  355. package/src/sanitize_var_name.test.js +0 -39
  356. package/src/shell_spawn.test.js +0 -30
  357. package/src/str_camel_to_snake.test.js +0 -17
  358. package/src/stream_curl_progress.d/basic +0 -3
  359. package/src/stream_curl_progress.d/basic.json +0 -42
  360. package/src/stream_curl_progress.test.js +0 -17
  361. package/src/stream_data_ln.test.js +0 -24
  362. package/src/stream_map_parallel.test.js +0 -26
  363. package/src/stream_multiplex.test.js +0 -67
  364. package/src/stream_strpbrk.test.js +0 -29
  365. package/src/urlclean.test.js +0 -18
  366. package/src/urlmod.test.js +0 -40
  367. package/src/urlparts.test.js +0 -294
@@ -0,0 +1,11 @@
1
+ Converts camelCase/PascalCase to snake_case and lowercases the result.
2
+ Acronyms are kept together as one word (`SomeUPCCode` → `some_upc_code`),
3
+ though an acronym at the end of the string has nothing to split it from the
4
+ previous word (`thisISNT` → `this_isnt`).
5
+
6
+ ```js
7
+ str_camel_to_snake('CamelCase') // 'camel_case'
8
+ str_camel_to_snake('SomeUPCCode') // 'some_upc_code'
9
+ str_camel_to_snake('thisISDifficult') // 'this_is_difficult'
10
+ str_camel_to_snake('UPC') // 'upc'
11
+ ```
@@ -0,0 +1,11 @@
1
+ Splits a `key: value` string on the first colon and returns a trimmed
2
+ `[key, value]` pair. Only the first colon splits — the rest stays in the
3
+ value — so URLs survive. Without a colon, the whole string is the key and
4
+ the value is `''`.
5
+
6
+ ```js
7
+ str_parse_kv('key: value') // ['key', 'value']
8
+ str_parse_kv('url: http://example.com') // ['url', 'http://example.com']
9
+ str_parse_kv('key') // ['key', '']
10
+ str_parse_kv(':value') // ['', 'value']
11
+ ```
@@ -0,0 +1,14 @@
1
+ Transform that parses curl's stderr progress meter (the `--progress-meter`
2
+ table) into objects. The two header lines are skipped; every following line
3
+ becomes `{perc, done, total, speed, eta, duration, time_total, ...}` with the
4
+ raw columns (`recv`, `transferred`, `speed_down`, `speed_up`, ...) included.
5
+ `done` is the received column, falling back to the transferred column while
6
+ received is `'0'` (uploads). `--:--:--` times are reported as `'~'`.
7
+
8
+ Lines starting with `curl:` (error messages) are written to
9
+ `process.stderr` and dropped from the output.
10
+
11
+ ```js
12
+ stream.compose(proc.stderr, stream_curl_progress())
13
+ // {perc: '18', done: '587M', total: '3217M', speed: '19.0M', eta: '0:02:22', ...}
14
+ ```
@@ -1,3 +1,5 @@
1
+ const {StringDecoder} = require('string_decoder');
2
+
1
3
  /**
2
4
  * Split stream on each \n and call `fn` for each line.
3
5
  *
@@ -7,6 +9,9 @@
7
9
  */
8
10
  function stream_data_ln(stream, fn)
9
11
  {
12
+ // StringDecoder buffers a multi-byte character split across chunk
13
+ // boundaries; plain buffer.toString('utf8') would corrupt it into �.
14
+ const decoder = new StringDecoder('utf8');
10
15
  let utf8 = '';
11
16
  stream.on('data', data);
12
17
  stream.on('end', end);
@@ -18,12 +23,13 @@ function stream_data_ln(stream, fn)
18
23
  }
19
24
  function end() {
20
25
  off();
26
+ utf8 += decoder.end();
21
27
  if (utf8) {
22
28
  fn(utf8, true);
23
29
  }
24
30
  }
25
31
  function data(buffer) {
26
- utf8 += buffer.toString('utf8');
32
+ utf8 += (typeof buffer === 'string') ? buffer : decoder.write(buffer);
27
33
  for (let iteration = 1; true; ++iteration) {
28
34
  if (iteration == 1000000) {
29
35
  throw new Error('Too many iterations');
@@ -0,0 +1,8 @@
1
+ A writable sink that accepts and discards every chunk — useful to drain a
2
+ pipeline whose output is irrelevant. Byte mode by default; pass
3
+ `{objectMode: true}` for object streams. Consumes empty streams fine.
4
+
5
+ ```js
6
+ await stream.promises.pipeline(source, stream_discard());
7
+ await stream.promises.pipeline(objects, stream_discard({objectMode: true}));
8
+ ```
@@ -0,0 +1,3 @@
1
+ Deprecated alias of `stream_chunk` — splits an object stream into arrays of
2
+ up to `chunk_size` items. Calls `stream_chunk(chunk_size)` directly; use
3
+ `stream_chunk` in new code.
@@ -0,0 +1,7 @@
1
+ Thin wrapper around `zlib.createGunzip(options)`: a transform that
2
+ decompresses a gzipped byte stream. Corrupt input errors the stream
3
+ (`incorrect header check`).
4
+
5
+ ```js
6
+ await stream.promises.pipeline(gzipped_source, stream_gunzip(), destination);
7
+ ```
@@ -0,0 +1,10 @@
1
+ Transform that consumes all input chunks and emits a single output chunk at
2
+ flush: the hex digest of the whole stream. `algorithm` defaults to `'md5'`;
3
+ any `crypto.createHash` algorithm name works, and `options` is passed
4
+ through to it. An empty stream still emits the digest of empty input.
5
+
6
+ ```js
7
+ const chunks = await stream.Readable.from(['aaa', 'bbb']).pipe(stream_hash('sha256')).toArray();
8
+ Buffer.concat(chunks).toString('utf8');
9
+ // '2ce109e9d0faf820b2434e166297934e6177b65ab9951dbc3e204cad4689b39c'
10
+ ```
package/src/stream_map.js CHANGED
@@ -2,6 +2,10 @@ const stream = require('stream');
2
2
 
3
3
  /**
4
4
  * Transform each item using a simple function.
5
+ *
6
+ * Returning null or undefined from `fn` drops the item: streams cannot
7
+ * carry null (it is an eof mark), so pushing it would end the stream and
8
+ * silently discard everything after it.
5
9
  */
6
10
  function stream_map(fn)
7
11
  {
@@ -9,7 +13,10 @@ function stream_map(fn)
9
13
  objectMode: true,
10
14
  transform: async function (item, encoding, callback) {
11
15
  try {
12
- this.push(await fn(item));
16
+ const out = await fn(item);
17
+ if (out !== null && out !== undefined) {
18
+ this.push(out);
19
+ }
13
20
  callback();
14
21
  }
15
22
  catch (error) {
@@ -3,6 +3,10 @@ const stream = require('stream');
3
3
 
4
4
  /**
5
5
  * Transform each item using a simple function in parallel.
6
+ *
7
+ * Returning null or undefined from `handler` drops the item: streams cannot
8
+ * carry null (it is an eof mark), so pushing it would end the stream and
9
+ * silently discard everything after it.
6
10
  */
7
11
  function stream_map_parallel({handler, concurrency})
8
12
  {
@@ -46,7 +50,11 @@ function stream_map_parallel({handler, concurrency})
46
50
  function ready() {
47
51
  running--;
48
52
  while (buf.length && buf[0].isFulfilled()) {
49
- out.push(buf.shift().value());
53
+ const value = buf.shift().value();
54
+ // null is an eof mark, pushing it would end the stream
55
+ if (value !== null && value !== undefined) {
56
+ out.push(value);
57
+ }
50
58
  }
51
59
  if (callback_next && buf.length < buf_limit) {
52
60
  const tmp = callback_next;
@@ -0,0 +1,9 @@
1
+ Transform that consumes all input chunks and emits a single output chunk at
2
+ flush: the md5 hex digest of the whole stream. An empty stream still emits
3
+ `'d41d8cd98f00b204e9800998ecf8427e'`. Equivalent to `stream_hash('md5')`;
4
+ the source carries a TODO to rename this to `stream_hash_md5`.
5
+
6
+ ```js
7
+ const chunks = await stream.Readable.from(['aaa', 'bbb']).pipe(stream_md5()).toArray();
8
+ Buffer.concat(chunks).toString('utf8'); // '6547436690a26a399603a7096e876a2d'
9
+ ```
@@ -3,6 +3,17 @@ const stream = require('stream');
3
3
 
4
4
  function stream_multiplex(...streams)
5
5
  {
6
+ if (streams.length === 0) {
7
+ // Multiplex of nothing is a sink which accepts and discards all writes
8
+ // (the generic write/final below would never invoke their callbacks).
9
+ return stream.Writable({
10
+ objectMode: true,
11
+ write: function (chunk, encoding, callback) {
12
+ callback();
13
+ },
14
+ });
15
+ }
16
+
6
17
  if (streams.length === 1) {
7
18
  return streams[0];
8
19
  }
@@ -0,0 +1,16 @@
1
+ Combines several writable streams into one object-mode writable that
2
+ duplicates every chunk to all of them. Backpressure is respected: a write
3
+ completes only after every target accepted the chunk.
4
+
5
+ - Zero streams → a sink that accepts and discards all writes.
6
+ - One stream → returned as is (no wrapper).
7
+ - Ending the multiplex ends all targets; destroying it destroys all targets.
8
+ - An error in any target destroys the multiplex (and, through it, the other
9
+ targets) with that error — the first error wins.
10
+
11
+ ```js
12
+ await stream.promises.pipeline(
13
+ source,
14
+ stream_multiplex(ws1, ws2),
15
+ );
16
+ ```
@@ -0,0 +1,3 @@
1
+ Deprecated alias of `stream_tap` — calls `fn` on each item and passes the
2
+ item through unchanged. Calls `stream_tap(fn)` directly; use `stream_tap`
3
+ in new code.
@@ -0,0 +1,2 @@
1
+ Deprecated alias of `stream_map` — maps each item through `fn`. Calls
2
+ `stream_map(fn)` directly; use `stream_map` in new code.
@@ -1,5 +1,6 @@
1
1
  const htmlparser2 = require('htmlparser2');
2
2
  const stream = require('stream');
3
+ const {StringDecoder} = require('string_decoder');
3
4
 
4
5
  /**
5
6
  * Consume XML, produce an object with analytics about provided xml stream.
@@ -30,13 +31,20 @@ function stream_xml_analyze()
30
31
  };
31
32
 
32
33
  const parser = new htmlparser2.Parser(events, options);
34
+ // StringDecoder buffers a multi-byte character split across chunk
35
+ // boundaries; plain buf.toString() would corrupt it into �.
36
+ const decoder = new StringDecoder('utf8');
33
37
  return out = new stream.Transform({
34
38
  objectMode: true,
35
39
  transform: function (buf, encoding, callback) {
36
- parser.write(buf.toString());
40
+ parser.write(typeof buf === 'string' ? buf : decoder.write(buf));
37
41
  callback();
38
42
  },
39
43
  flush: function (callback) {
44
+ const tail = decoder.end();
45
+ if (tail) {
46
+ parser.write(tail);
47
+ }
40
48
  parser.end();
41
49
  callback();
42
50
  },
@@ -2,6 +2,7 @@ const assert = require('assert');
2
2
  const const_stream = require('./const_stream');
3
3
  const htmlparser2 = require('htmlparser2');
4
4
  const stream = require('stream');
5
+ const {StringDecoder} = require('string_decoder');
5
6
 
6
7
  /**
7
8
  * Consume XML, produce objects.
@@ -48,13 +49,20 @@ function stream_xml_parse(selector, mapper = stream_xml_parse.guess)
48
49
  };
49
50
 
50
51
  const parser = new htmlparser2.Parser(events, options);
52
+ // StringDecoder buffers a multi-byte character split across chunk
53
+ // boundaries; plain buf.toString() would corrupt it into �.
54
+ const decoder = new StringDecoder('utf8');
51
55
  return out = new stream.Transform({
52
56
  objectMode: true,
53
57
  transform: function (buf, encoding, callback) {
54
- parser.write(buf.toString());
58
+ parser.write(typeof buf === 'string' ? buf : decoder.write(buf));
55
59
  callback();
56
60
  },
57
61
  flush: function (callback) {
62
+ const tail = decoder.end();
63
+ if (tail) {
64
+ parser.write(tail);
65
+ }
58
66
  parser.end();
59
67
  callback();
60
68
  },
@@ -55,7 +55,7 @@ function stream_ytdlp_progress()
55
55
  current_part = downloading_formats.indexOf(m[1]) + 1;
56
56
  return false;
57
57
  }
58
- if (m = line.match(/^\[Merger]/i)) {
58
+ if (line.match(/^\[Merger]/i)) {
59
59
  last.merging = true;
60
60
  return last;
61
61
  }
@@ -0,0 +1,18 @@
1
+ Transform that parses yt-dlp `--progress` output (stdout) into objects:
2
+ `{current_part, total_parts, perc, done, total, speed, eta, merging}`. Sizes
3
+ are re-formatted via `parse_bytes`/`format_bytes` (`15.71MiB` → `'15.71MB'`,
4
+ `done` computed from the percentage), `Unknown` speed/ETA become `'~'`, and
5
+ non-progress lines are dropped.
6
+
7
+ - `[info] ...: Downloading N format(s): 251+248` plus the per-part
8
+ `[download] Destination: ....fNNN.ext` lines drive
9
+ `current_part`/`total_parts` for multi-format downloads (otherwise
10
+ `1`/`0`).
11
+ - A `[Merger]` line re-emits the last row with `merging: true`. The last row
12
+ is mutated in place, so copy rows if you collect them.
13
+
14
+ ```js
15
+ stream.Readable.from(lines).pipe(stream_ytdlp_progress())
16
+ // {current_part: 1, total_parts: 0, perc: '50.90%', done: '8.0MB',
17
+ // total: '15.71MB', speed: '33.83MB/s', eta: '00:01', merging: false}
18
+ ```
package/src/strtr.js CHANGED
@@ -2,13 +2,23 @@
2
2
  // echo strtr("hello", ["he" => "X", "hell" => "Y"]);
3
3
  function strtr(subject, map)
4
4
  {
5
- let out = subject;
6
- Object.entries(map).sort(fcmp).forEach(function ([search, replace]) {
7
- out = out.replaceAll(search, replace);
8
- });
5
+ // Single pass, like PHP: replaced text is never scanned again
6
+ const keys = Object.keys(map).filter(v => v.length).sort(fcmp);
7
+ let out = '';
8
+ for (let i = 0; i < subject.length; ) {
9
+ const key = keys.find(v => subject.startsWith(v, i));
10
+ if (key) {
11
+ out += map[key];
12
+ i += key.length;
13
+ }
14
+ else {
15
+ out += subject[i];
16
+ i++;
17
+ }
18
+ }
9
19
  return out;
10
20
  function fcmp(b, a) {
11
- return a[0].length - b[0].length;
21
+ return a.length - b.length;
12
22
  }
13
23
  }
14
24
 
package/src/strtr.md ADDED
@@ -0,0 +1,11 @@
1
+ Replaces substrings in `subject` using a `{from: to}` map, like PHP's
2
+ `strtr`. Single pass: replaced text is never scanned again, so maps like
3
+ `{a: 'b', b: 'c'}` cannot cascade. When keys overlap, the longest matching
4
+ key wins regardless of map order. Empty keys are ignored.
5
+
6
+ ```js
7
+ strtr('hello world', {world: 'there'}) // 'hello there'
8
+ strtr('hello', {he: 'X', hell: 'Y'}) // 'Yo' (longest key wins)
9
+ strtr('ab', {a: 'b', b: 'c'}) // 'bc' (single pass, no cascade)
10
+ strtr('hello', {l: ''}) // 'heo'
11
+ ```
package/src/urlclean.js CHANGED
@@ -6,6 +6,13 @@ const querystring = require('querystring');
6
6
  */
7
7
  function urlclean(url)
8
8
  {
9
+ // The #fragment is not part of the query string: without splitting it
10
+ // off first it would be percent-encoded into the last query value.
11
+ const h = url.indexOf('#');
12
+ const hash = (h === -1) ? '' : url.slice(h);
13
+ if (hash) {
14
+ url = url.slice(0, h);
15
+ }
9
16
  const i = url.indexOf('?') + 1;
10
17
  if (i) {
11
18
  const s = querystring.stringify(querystring.parse(url.slice(i)), '&', '=', {
@@ -13,9 +20,9 @@ function urlclean(url)
13
20
  return encodeURIComponent(v).replaceAll('%3A', ':').replaceAll('%2F', '/');
14
21
  },
15
22
  });
16
- return url.slice(0, i) + s;
23
+ return url.slice(0, i) + s + hash;
17
24
  }
18
- return url;
25
+ return url + hash;
19
26
  }
20
27
 
21
28
  module.exports = urlclean;
package/src/urlmod.js CHANGED
@@ -26,6 +26,11 @@ function urlmod(url, params)
26
26
  break;
27
27
  }
28
28
  });
29
+ if (url && url[0] === '/' && url[1] === '/') {
30
+ // Protocol-relative url: the fake base host was replaced by the
31
+ // real one, only the fake scheme is left to strip.
32
+ return tmp_url.toString().replace(/^xxx:/, '');
33
+ }
29
34
  if (url && url[0] === '/') {
30
35
  return tmp_url.toString().replace(/^xxx:\/\/___base___/, '');
31
36
  }
@@ -0,0 +1,17 @@
1
+ Splits a URL into a fixed-shape plain object. Accepts a `URL` instance or a
2
+ string; strings are parsed against the base `fake://fake/`, so relative paths
3
+ work (and non-string input degrades to the bare base instead of throwing).
4
+ The keys mirror the `URL` properties, except `pathname` is exposed as `path`.
5
+
6
+ ```js
7
+ urlparts('https://john:secret@example.com:8080/users/15?page=2#top')
8
+ // {
9
+ // href: 'https://john:secret@example.com:8080/users/15?page=2#top',
10
+ // protocol: 'https:', hostname: 'example.com',
11
+ // username: 'john', password: 'secret',
12
+ // host: 'example.com:8080', port: '8080',
13
+ // path: '/users/15', search: '?page=2', hash: '#top',
14
+ // }
15
+ urlparts('/users?page=5').path // '/users'
16
+ urlparts('/users?page=5').protocol // 'fake:'
17
+ ```
package/src/wait_while.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const Promise = require('bluebird');
2
2
 
3
3
  /**
4
- * Wait until `fn` returns `true`.
4
+ * Wait while `fn` returns a truthy value; resolve as soon as it turns falsy.
5
5
  *
6
6
  * W A R N I N G
7
7
  * This method was designed mainly for prototyping (where code cleanliness is important).
package/src/wait_while.md CHANGED
@@ -1,4 +1,4 @@
1
- Wait until `fn` returns `true`.
1
+ Wait while `fn` returns a truthy value; resolve as soon as it turns falsy.
2
2
 
3
3
  W A R N I N G
4
4
  This method was designed mainly for prototyping (where code cleanliness is important).
@@ -1,31 +0,0 @@
1
- const HeartbeatServer = require('./HeartbeatServer');
2
- const assert = require('assert');
3
- const fs_assert_file_socket = require('./fs_assert_file_socket');
4
- const ping_socket = require('./ping_socket');
5
-
6
- // 💎 Only the lack of a valid PING within WATCHDOG_INTERVAL is fatal
7
-
8
- // 📕 Notes by ChatGPT
9
- // If listen() fails (EADDRINUSE, perms, etc.), constructor will throw,
10
- // and heartbeat_server will be undefined in finally { await heartbeat_server.dispose() }.
11
-
12
- describe('HeartbeatServer', function () {
13
- it('Happy Path', async function () {
14
- const server = new HeartbeatServer();
15
- try {
16
- let counter = 0;
17
- server.on('heartbeat', () => counter++);
18
- await fs_assert_file_socket(server.socket_path);
19
- await ping_socket(server.socket_path);
20
- await ping_socket(server.socket_path);
21
- assert.strictEqual(counter, 2);
22
- }
23
- finally {
24
- await server.dispose();
25
- }
26
- });
27
-
28
- // should emit a "warning" event on any client errors
29
- // should not send any heartbeat signals after rejection (decision to kill a child process)
30
- // should reject when no heartbeat received in an expected interval
31
- });
@@ -1,24 +0,0 @@
1
- const array_chunk = require('./array_chunk');
2
- const assert = require('assert');
3
-
4
- describe('array_chunk', function () {
5
- it('should accept no arguments', function () {
6
- assert.deepStrictEqual(array_chunk(), []);
7
- });
8
- it('should handle basic input', function () {
9
- assert.deepStrictEqual(array_chunk([]), []);
10
- assert.deepStrictEqual(array_chunk([1,2,3,4,5]), [[1],[2],[3],[4],[5]]);
11
- assert.deepStrictEqual(array_chunk([1,2,3,4,5], 1), [[1],[2],[3],[4],[5]]);
12
- assert.deepStrictEqual(array_chunk([1,2,3,4,5], 2), [[1,2],[3,4],[5]]);
13
- assert.deepStrictEqual(array_chunk([1,2,3,4,5], 3), [[1,2,3],[4,5]]);
14
- assert.deepStrictEqual(array_chunk([1,2,3,4,5], 4), [[1,2,3,4],[5]]);
15
- assert.deepStrictEqual(array_chunk([1,2,3,4,5], 5), [[1,2,3,4,5]]);
16
- assert.deepStrictEqual(array_chunk([1,2,3,4,5], 6), [[1,2,3,4,5]]);
17
- });
18
- it('should throw when limit is less than 1', function () {
19
- assert.throws(() => array_chunk([], 0));
20
- assert.throws(() => array_chunk([], -1));
21
- assert.throws(() => array_chunk([1], 0));
22
- assert.throws(() => array_chunk([1], -1));
23
- });
24
- });
@@ -1,37 +0,0 @@
1
- const array_chunk_balanced = require('./array_chunk_balanced');
2
- const assert = require('assert');
3
-
4
- describe('array_chunk_balanced', function () {
5
- it('should handle basic input', function () {
6
- assert.deepStrictEqual(array_chunk_balanced([1]), [[1]]);
7
- assert.deepStrictEqual(array_chunk_balanced([1,2]), [[1,2]]);
8
- assert.deepStrictEqual(array_chunk_balanced([1,2,3]), [[1,2,3]]);
9
- assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5], 3, 2), [[1,2,3],[4,5]]);
10
- assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5,6], 3, 2), [[1,2],[3,4],[5,6]]);
11
- assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5,6,7], 3, 2), [[1,2,3],[4,5],[6,7]]);
12
- assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5], 3, 3), [[1,2,3,4,5]]);
13
- assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5,6], 3, 3), [[1,2,3],[4,5,6]]);
14
- assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5,6,7], 3, 3), [[1,2,3,4],[5,6,7]]);
15
- assert.deepStrictEqual(array_chunk_balanced([1,2,3,4,5,6,7,8], 3, 3), [[1,2,3,4],[5,6,7,8]]);
16
- });
17
- it('edge: If an array is empty → returns []', function () {
18
- assert.deepStrictEqual(array_chunk_balanced([]), []);
19
- });
20
- it('edge: If there are too few items to satisfy `min_items_per_chunk`, even for 1 chunk, everything goes into a single chunk', function () {
21
- assert.deepStrictEqual(array_chunk_balanced([1,2,3], 5, 5), [[1,2,3]]);
22
- });
23
- it('should never produce more chunks than max_threads', function () {
24
- // 12 jobs, max 5 threads, min 2 jobs per thread
25
- // Correct result MUST have exactly 5 chunks
26
- assert.deepStrictEqual(
27
- array_chunk_balanced([1,2,3,4,5,6,7,8,9,10,11,12], 5, 2),
28
- [
29
- [1,2,3],
30
- [4,5,6],
31
- [7,8],
32
- [9,10],
33
- [11,12]
34
- ]
35
- );
36
- });
37
- });
@@ -1,72 +0,0 @@
1
- const array_fps = require('./array_fps');
2
- const assert = require('assert');
3
-
4
- describe('array_fps', function () {
5
- it('should handle basic input', function () {
6
- assert.deepStrictEqual(array_fps(1, 1), [0]);
7
- assert.deepStrictEqual(array_fps(1, 2), [0, 0.99999]);
8
- assert.deepStrictEqual(array_fps(1, 3), [0, 0.49999, 0.99999]);
9
- assert.deepStrictEqual(array_fps(1, 4), [0, 0.33333, 0.66666, 0.99999]);
10
- assert.deepStrictEqual(array_fps(5, 20), [
11
- 0, 0.0505, 0.10101, 0.15151, 0.20202, 0.25252, 0.30303, 0.35353, 0.40404, 0.45454,
12
- 0.50505, 0.55555, 0.60606, 0.65656, 0.70707, 0.75757, 0.80808, 0.85858, 0.90909, 0.95959,
13
- 1.0101, 1.0606, 1.11111, 1.16161, 1.21212, 1.26262, 1.31313, 1.36363, 1.41414, 1.46464,
14
- 1.51515, 1.56565, 1.61616, 1.66666, 1.71717, 1.76767, 1.81818, 1.86868, 1.91919, 1.96969,
15
- 2.0202, 2.0707, 2.12121, 2.17171, 2.22222, 2.27272, 2.32323, 2.37373, 2.42424, 2.47474,
16
- 2.52525, 2.57575, 2.62626, 2.67676, 2.72727, 2.77777, 2.82828, 2.87878, 2.92929, 2.97979,
17
- 3.0303, 3.0808, 3.13131, 3.18181, 3.23232, 3.28282, 3.33333, 3.38383, 3.43434, 3.48484,
18
- 3.53535, 3.58585, 3.63636, 3.68686, 3.73737, 3.78787, 3.83838, 3.88888, 3.93939, 3.98989,
19
- 4.0404, 4.0909, 4.14141, 4.19191, 4.24242, 4.29292, 4.34343, 4.39393, 4.44444, 4.49494,
20
- 4.54545, 4.59595, 4.64646, 4.69696, 4.74747, 4.79797, 4.84848, 4.89898, 4.94949, 4.99999,
21
- ]);
22
- assert.deepStrictEqual(array_fps(5, 30), [
23
- 0, 0.03356, 0.06711, 0.10067, 0.13423, 0.16778, 0.20134, 0.2349, 0.26846, 0.30201,
24
- 0.33557, 0.36913, 0.40268, 0.43624, 0.4698, 0.50335, 0.53691, 0.57047, 0.60403, 0.63758,
25
- 0.67114, 0.7047, 0.73825, 0.77181, 0.80537, 0.83892, 0.87248, 0.90604, 0.9396, 0.97315,
26
- 1.00671, 1.04027, 1.07382, 1.10738, 1.14094, 1.17449, 1.20805, 1.24161, 1.27517, 1.30872,
27
- 1.34228, 1.37584, 1.40939, 1.44295, 1.47651, 1.51006, 1.54362, 1.57718, 1.61074, 1.64429,
28
- 1.67785, 1.71141, 1.74496, 1.77852, 1.81208, 1.84563, 1.87919, 1.91275, 1.9463, 1.97986,
29
- 2.01342, 2.04698, 2.08053, 2.11409, 2.14765, 2.1812, 2.21476, 2.24832, 2.28187, 2.31543,
30
- 2.34899, 2.38255, 2.4161, 2.44966, 2.48322, 2.51677, 2.55033, 2.58389, 2.61744, 2.651,
31
- 2.68456, 2.71812, 2.75167, 2.78523, 2.81879, 2.85234, 2.8859, 2.91946, 2.95301, 2.98657,
32
- 3.02013, 3.05369, 3.08724, 3.1208, 3.15436, 3.18791, 3.22147, 3.25503, 3.28858, 3.32214,
33
- 3.3557, 3.38925, 3.42281, 3.45637, 3.48993, 3.52348, 3.55704, 3.5906, 3.62415, 3.65771,
34
- 3.69127, 3.72482, 3.75838, 3.79194, 3.8255, 3.85905, 3.89261, 3.92617, 3.95972, 3.99328,
35
- 4.02684, 4.06039, 4.09395, 4.12751, 4.16107, 4.19462, 4.22818, 4.26174, 4.29529, 4.32885,
36
- 4.36241, 4.39596, 4.42952, 4.46308, 4.49664, 4.53019, 4.56375, 4.59731, 4.63086, 4.66442,
37
- 4.69798, 4.73153, 4.76509, 4.79865, 4.83221, 4.86576, 4.89932, 4.93288, 4.96643, 4.99999,
38
- ]);
39
- assert.deepStrictEqual(array_fps(5, 60), [
40
- 0, 0.01672, 0.03344, 0.05017, 0.06689, 0.08361, 0.10033, 0.11706, 0.13378, 0.1505,
41
- 0.16722, 0.18395, 0.20067, 0.21739, 0.23411, 0.25084, 0.26756, 0.28428, 0.301, 0.31773,
42
- 0.33445, 0.35117, 0.36789, 0.38461, 0.40134, 0.41806, 0.43478, 0.4515, 0.46823, 0.48495,
43
- 0.50167, 0.51839, 0.53512, 0.55184, 0.56856, 0.58528, 0.60201, 0.61873, 0.63545, 0.65217,
44
- 0.66889, 0.68562, 0.70234, 0.71906, 0.73578, 0.75251, 0.76923, 0.78595, 0.80267, 0.8194,
45
- 0.83612, 0.85284, 0.86956, 0.88629, 0.90301, 0.91973, 0.93645, 0.95318, 0.9699, 0.98662,
46
- 1.00334, 1.02006, 1.03679, 1.05351, 1.07023, 1.08695, 1.10368, 1.1204, 1.13712, 1.15384,
47
- 1.17057, 1.18729, 1.20401, 1.22073, 1.23746, 1.25418, 1.2709, 1.28762, 1.30435, 1.32107,
48
- 1.33779, 1.35451, 1.37123, 1.38796, 1.40468, 1.4214, 1.43812, 1.45485, 1.47157, 1.48829,
49
- 1.50501, 1.52174, 1.53846, 1.55518, 1.5719, 1.58863, 1.60535, 1.62207, 1.63879, 1.65552,
50
- 1.67224, 1.68896, 1.70568, 1.7224, 1.73913, 1.75585, 1.77257, 1.78929, 1.80602, 1.82274,
51
- 1.83946, 1.85618, 1.87291, 1.88963, 1.90635, 1.92307, 1.9398, 1.95652, 1.97324, 1.98996,
52
- 2.00668, 2.02341, 2.04013, 2.05685, 2.07357, 2.0903, 2.10702, 2.12374, 2.14046, 2.15719,
53
- 2.17391, 2.19063, 2.20735, 2.22408, 2.2408, 2.25752, 2.27424, 2.29097, 2.30769, 2.32441,
54
- 2.34113, 2.35785, 2.37458, 2.3913, 2.40802, 2.42474, 2.44147, 2.45819, 2.47491, 2.49163,
55
- 2.50836, 2.52508, 2.5418, 2.55852, 2.57525, 2.59197, 2.60869, 2.62541, 2.64214, 2.65886,
56
- 2.67558, 2.6923, 2.70902, 2.72575, 2.74247, 2.75919, 2.77591, 2.79264, 2.80936, 2.82608,
57
- 2.8428, 2.85953, 2.87625, 2.89297, 2.90969, 2.92642, 2.94314, 2.95986, 2.97658, 2.99331,
58
- 3.01003, 3.02675, 3.04347, 3.06019, 3.07692, 3.09364, 3.11036, 3.12708, 3.14381, 3.16053,
59
- 3.17725, 3.19397, 3.2107, 3.22742, 3.24414, 3.26086, 3.27759, 3.29431, 3.31103, 3.32775,
60
- 3.34447, 3.3612, 3.37792, 3.39464, 3.41136, 3.42809, 3.44481, 3.46153, 3.47825, 3.49498,
61
- 3.5117, 3.52842, 3.54514, 3.56187, 3.57859, 3.59531, 3.61203, 3.62876, 3.64548, 3.6622,
62
- 3.67892, 3.69564, 3.71237, 3.72909, 3.74581, 3.76253, 3.77926, 3.79598, 3.8127, 3.82942,
63
- 3.84615, 3.86287, 3.87959, 3.89631, 3.91304, 3.92976, 3.94648, 3.9632, 3.97993, 3.99665,
64
- 4.01337, 4.03009, 4.04681, 4.06354, 4.08026, 4.09698, 4.1137, 4.13043, 4.14715, 4.16387,
65
- 4.18059, 4.19732, 4.21404, 4.23076, 4.24748, 4.26421, 4.28093, 4.29765, 4.31437, 4.3311,
66
- 4.34782, 4.36454, 4.38126, 4.39798, 4.41471, 4.43143, 4.44815, 4.46487, 4.4816, 4.49832,
67
- 4.51504, 4.53176, 4.54849, 4.56521, 4.58193, 4.59865, 4.61538, 4.6321, 4.64882, 4.66554,
68
- 4.68226, 4.69899, 4.71571, 4.73243, 4.74915, 4.76588, 4.7826, 4.79932, 4.81604, 4.83277,
69
- 4.84949, 4.86621, 4.88293, 4.89966, 4.91638, 4.9331, 4.94982, 4.96655, 4.98327, 4.99999,
70
- ]);
71
- });
72
- });
@@ -1,10 +0,0 @@
1
- const array_gcd = require('./array_gcd');
2
- const assert = require('assert');
3
-
4
- describe('array_gcd', function () {
5
- it('should handle basic input', function () {
6
- assert.deepStrictEqual(array_gcd([1,2,3,4,5]), 1);
7
- assert.deepStrictEqual(array_gcd([4,8,16]), 4);
8
- assert.deepStrictEqual(array_gcd([300,100,200,300]), 100);
9
- });
10
- });
@@ -1,14 +0,0 @@
1
- const array_index = require('./array_index');
2
- const assert = require('assert');
3
-
4
- describe('array_index', function () {
5
- it('should accept empty array', function () {
6
- assert.deepStrictEqual(array_index([]), {});
7
- });
8
- it('should handle basic input', function () {
9
- const a = {uid: 'a'};
10
- const b = {uid: 'b'};
11
- const c = {uid: 'c'};
12
- assert.deepStrictEqual(array_index([a, b, c], v => v.uid), {a, b, c});
13
- });
14
- });
@@ -1,12 +0,0 @@
1
- const array_lcm = require('./array_lcm');
2
- const assert = require('assert');
3
-
4
- describe('array_lcm', function () {
5
- it('should handle basic input', function () {
6
- assert.deepStrictEqual(array_lcm([1,2,3,4,5]), 60);
7
- assert.deepStrictEqual(array_lcm([15,25]), 75);
8
- assert.deepStrictEqual(array_lcm([4,6,8]), 24);
9
- assert.deepStrictEqual(array_lcm([4,8,16]), 16);
10
- assert.deepStrictEqual(array_lcm([300,100,200,300]), 600);
11
- });
12
- });