@dooboostore/simple-boot-http-server 1.0.26 → 1.0.27

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 (41) hide show
  1. package/README.md +100 -14
  2. package/dist/cjs/SimpleBootHttpServer.js +20 -16
  3. package/dist/cjs/SimpleBootHttpServer.js.map +2 -2
  4. package/dist/cjs/codes/Mimes.js +2 -0
  5. package/dist/cjs/codes/Mimes.js.map +2 -2
  6. package/dist/cjs/decorators/MethodMapping.js +2 -2
  7. package/dist/cjs/decorators/MethodMapping.js.map +2 -2
  8. package/dist/cjs/filters/ResourceFilter.js +0 -1
  9. package/dist/cjs/filters/ResourceFilter.js.map +2 -2
  10. package/dist/cjs/websocket/WebSocketManager.js +68 -40
  11. package/dist/cjs/websocket/WebSocketManager.js.map +2 -2
  12. package/dist/esm/SimpleBootHttpServer.js +20 -16
  13. package/dist/esm/SimpleBootHttpServer.js.map +2 -2
  14. package/dist/esm/codes/Mimes.js +2 -0
  15. package/dist/esm/codes/Mimes.js.map +2 -2
  16. package/dist/esm/decorators/MethodMapping.js +2 -2
  17. package/dist/esm/decorators/MethodMapping.js.map +2 -2
  18. package/dist/esm/filters/ResourceFilter.js +0 -1
  19. package/dist/esm/filters/ResourceFilter.js.map +2 -2
  20. package/dist/esm/websocket/WebSocketManager.js +68 -40
  21. package/dist/esm/websocket/WebSocketManager.js.map +2 -2
  22. package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js +279 -137
  23. package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js.map +4 -4
  24. package/dist/types/SimpleBootHttpServer.d.ts.map +1 -1
  25. package/dist/types/codes/Mimes.d.ts +2 -0
  26. package/dist/types/codes/Mimes.d.ts.map +1 -1
  27. package/dist/types/decorators/MethodMapping.d.ts +8 -0
  28. package/dist/types/decorators/MethodMapping.d.ts.map +1 -1
  29. package/dist/types/filters/ResourceFilter.d.ts.map +1 -1
  30. package/dist/types/websocket/WebSocketManager.d.ts +3 -1
  31. package/dist/types/websocket/WebSocketManager.d.ts.map +1 -1
  32. package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js +279 -137
  33. package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js.map +4 -4
  34. package/dist/umd-bundle/websocket-client.umd.js +209 -9
  35. package/dist/umd-bundle/websocket-client.umd.js.map +4 -4
  36. package/package.json +8 -8
  37. package/src/SimpleBootHttpServer.ts +21 -16
  38. package/src/codes/Mimes.ts +2 -0
  39. package/src/decorators/MethodMapping.ts +14 -7
  40. package/src/filters/ResourceFilter.ts +0 -1
  41. package/src/websocket/WebSocketManager.ts +69 -41
@@ -55,6 +55,7 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
55
55
  Fetcher: () => Fetcher,
56
56
  FormValidator: () => FormValidator,
57
57
  FunctionUtils: () => FunctionUtils,
58
+ HashUtils: () => HashUtils,
58
59
  HttpFetcher: () => HttpFetcher,
59
60
  HttpJsonFetcher: () => HttpJsonFetcher,
60
61
  HttpResponseError: () => HttpResponseError,
@@ -135,6 +136,7 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
135
136
  isCssCommentItem: () => isCssCommentItem,
136
137
  isCssDeclarationItem: () => isCssDeclarationItem,
137
138
  isCssRuleItem: () => isCssRuleItem,
139
+ isDefined: () => isDefined,
138
140
  isHttpResponseError: () => isHttpResponseError,
139
141
  isPoint2DType: () => isPoint2DType,
140
142
  isPoint3DType: () => isPoint3DType,
@@ -2094,6 +2096,12 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
2094
2096
  this.z = z ?? 0;
2095
2097
  }
2096
2098
  }
2099
+ /**
2100
+ * 성분 대입 (파괴적). 벡터 전달 시 그 성분을 복사.
2101
+ * @example
2102
+ * v.set(1, 2, 3); // v = (1, 2, 3)
2103
+ * v.set(otherVector); // v = other와 동일 성분
2104
+ */
2097
2105
  set(v, y = 0, z = 0) {
2098
2106
  if (v instanceof _Vector || v instanceof Point3D) {
2099
2107
  this.set(v.x || 0, v.y || 0, v.z || 0);
@@ -2104,16 +2112,45 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
2104
2112
  }
2105
2113
  return this;
2106
2114
  }
2115
+ /**
2116
+ * 복사본 반환 (비파괴). 파괴적 메서드와 조합해 원본 보존용.
2117
+ * @example
2118
+ * const s = a.get(); s.add(b); // s = a+b, a는 그대로
2119
+ */
2107
2120
  get() {
2108
2121
  return new _Vector(this.x, this.y, this.z);
2109
2122
  }
2110
- // 피타고라스의 정리는 a의 제곱 더하기 b 의 제곱은 c 의 제곱과 같다는 것을 정의합니다.
2111
- mag() {
2123
+ /**
2124
+ * 노름(norm). 평평한 공간(유클리드 공간)에서의 직선 거리.
2125
+ * - 수식: ‖v‖ = √(x² + y² + z²)
2126
+ * - 2D에서는 피타고라스 정리 그 자체. 3D는 두 번 적용한 것과 같음.
2127
+ * (바닥 대각선 √(x²+y²) → 공간 대각선 √((바닥)²+z²))
2128
+ * - "유클리드"는 평평한 공간의 기하학을 말함 (좌표계는 데카르트의 것, 유클리드는 좌표 없이 기하학을 세움).
2129
+ * 휘어진 공간(구면·쌍곡)에서는 이 공식이 성립하지 않음.
2130
+ * @example
2131
+ * new Vector(3, 4, 0).norm(); // 5
2132
+ * new Vector(6, 8, 0).norm(); // 10
2133
+ */
2134
+ norm() {
2112
2135
  const x = this.x;
2113
2136
  const y = this.y;
2114
2137
  const z = this.z;
2115
2138
  return Math.sqrt(x * x + y * y + z * z);
2116
2139
  }
2140
+ /**
2141
+ * norm()의 별칭 (p5.js 호환).
2142
+ * @example
2143
+ * new Vector(3, 4, 0).mag(); // 5
2144
+ */
2145
+ mag() {
2146
+ return this.norm();
2147
+ }
2148
+ /**
2149
+ * 덧셈 (파괴적). 성분별 합. 기하학적으로 평행사변형의 대각선.
2150
+ * - 수식: a + b = (ax+bx, ay+by, az+bz)
2151
+ * @example
2152
+ * const a = new Vector(4, 2); a.add(new Vector(-2, 3)); // a = (2, 5)
2153
+ */
2117
2154
  add(v, y = 0, z = 0) {
2118
2155
  if (v instanceof _Vector || v instanceof Point3D) {
2119
2156
  this.x += v.x;
@@ -2125,12 +2162,24 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
2125
2162
  this.z += z;
2126
2163
  }
2127
2164
  }
2165
+ /**
2166
+ * 덧셈 결과의 새 벡터 반환 (비파괴).
2167
+ * - 수식: a + b = (ax+bx, ay+by, az+bz)
2168
+ * @example
2169
+ * const s = a.toAdd(a, b); // s = a+b, a·b는 그대로
2170
+ */
2128
2171
  toAdd(v1, v2) {
2129
2172
  return new _Vector(v1.x + v2.x, v1.y + v2.y, v1.x + v2.y);
2130
2173
  }
2131
2174
  // public static add(v1: Vector, v2: Vector): Vector {
2132
2175
  // return new Vector(v1.x + v2.x, v1.y + v2.y, v1.x + v2.y);
2133
2176
  // }
2177
+ /**
2178
+ * 뺄셈 (파괴적). a - b는 "a에서 b를 되돌리는" 벡터.
2179
+ * - 수식: a - b = (ax-bx, ay-by, az-bz)
2180
+ * @example
2181
+ * const a = new Vector(4, 2); a.sub(new Vector(1, 1)); // a = (3, 1)
2182
+ */
2134
2183
  sub(v, y = 0, z = 0) {
2135
2184
  if (v instanceof _Vector || v instanceof Point3D) {
2136
2185
  this.x -= v.x;
@@ -2142,6 +2191,12 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
2142
2191
  this.z -= z;
2143
2192
  }
2144
2193
  }
2194
+ /**
2195
+ * 뺄셈 결과의 새 벡터 반환 (비파괴).
2196
+ * - 수식: a - b = (ax-bx, ay-by, az-bz)
2197
+ * @example
2198
+ * const d = a.toSub(b); // d = a-b, a·b는 그대로
2199
+ */
2145
2200
  toSub(v2) {
2146
2201
  const v1 = this;
2147
2202
  return new _Vector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
@@ -2150,6 +2205,12 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
2150
2205
  // public static sub(v1: Vector, v2: Vector): Vector {
2151
2206
  // return new Vector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
2152
2207
  // }
2208
+ /**
2209
+ * 스칼라배 또는 성분별 곱 (파괴적). 스칼라 k>1이면 늘어나고, 0<k<1이면 줄어듦. k<0이면 반대 방향.
2210
+ * - 수식(스칼라): k·v = (k·x, k·y, k·z)
2211
+ * @example
2212
+ * const v = new Vector(1, 2); v.mult(3); // v = (3, 6)
2213
+ */
2153
2214
  mult(v) {
2154
2215
  if (v instanceof _Vector || v instanceof Point3D) {
2155
2216
  this.x *= v.x;
@@ -2162,6 +2223,12 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
2162
2223
  }
2163
2224
  return this;
2164
2225
  }
2226
+ /**
2227
+ * 성분별 곱 결과의 새 벡터 반환 (비파괴).
2228
+ * - 수식: (ax·bx, ay·by, az·bz)
2229
+ * @example
2230
+ * const m = a.toMult(b); // m = 성분별 곱, a·b는 그대로
2231
+ */
2165
2232
  toMult(v2) {
2166
2233
  const v1 = this;
2167
2234
  return new _Vector(v1.x *= v2.x, v1.y *= v2.y, v1.z *= v2.z);
@@ -2169,6 +2236,12 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
2169
2236
  // public static mult(v1: Vector, v2: Vector) {
2170
2237
  // return new Vector(v1.x *= v2.x, v1.y *= v2.y, v1.z *= v2.z);
2171
2238
  // }
2239
+ /**
2240
+ * 스칼라 나눗셈 또는 성분별 나눗셈 (파괴적). 정규화의 핵심 연산.
2241
+ * - 수식(스칼라): v/k = (x/k, y/k, z/k)
2242
+ * @example
2243
+ * const v = new Vector(6, 8); v.div(2); // v = (3, 4)
2244
+ */
2172
2245
  div(v) {
2173
2246
  if (v instanceof _Vector || v instanceof Point3D) {
2174
2247
  this.x /= v.x;
@@ -2181,6 +2254,12 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
2181
2254
  }
2182
2255
  return this;
2183
2256
  }
2257
+ /**
2258
+ * 스칼라 나눗셈 결과의 새 벡터 반환 (비파괴).
2259
+ * - 수식: v/k = (x/k, y/k, z/k)
2260
+ * @example
2261
+ * const h = v.toDiv(2); // h = v/2, v는 그대로
2262
+ */
2184
2263
  toDiv(d) {
2185
2264
  const v = this;
2186
2265
  const rv = v.get();
@@ -2196,10 +2275,22 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
2196
2275
  // rv.z /= d;
2197
2276
  // return rv;
2198
2277
  // }
2278
+ /**
2279
+ * 두 점(벡터) 사이 거리. 차 벡터의 크기.
2280
+ * - 수식: d = √((dx)² + (dy)² + (dz)²)
2281
+ * @example
2282
+ * new Vector(0, 0).dist(new Vector(3, 4)); // 5
2283
+ */
2199
2284
  dist(v) {
2200
2285
  const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
2201
2286
  return Math.sqrt(dx * dx + dy * dy + dz * dz);
2202
2287
  }
2288
+ /**
2289
+ * 두 점(벡터) 사이 거리 (toDist는 dist와 동일, 비파괴).
2290
+ * - 수식: d = √((dx)² + (dy)² + (dz)²)
2291
+ * @example
2292
+ * a.toDist(b); // a와 b 사이 거리
2293
+ */
2203
2294
  toDist(v2) {
2204
2295
  const v1 = this;
2205
2296
  const dx = v1.x - v2.x, dy = v1.y - v2.y, dz = v1.z - v2.z;
@@ -2211,36 +2302,90 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
2211
2302
  // dz = v1.z - v2.z;
2212
2303
  // return Math.sqrt(dx * dx + dy * dy + dz * dz);
2213
2304
  // }
2214
- dot(v, y, z) {
2305
+ /**
2306
+ * 내적(dot product). 두 벡터가 같은 방향을 향하는 정도.
2307
+ * - 수식: a·b = ax·bx + ay·by + az·bz = |a||b|cosθ
2308
+ * - θ=90°면 0(직교), 0°면 최대(같은 방향).
2309
+ * - 벡터 전달 시 y·z 생략 가능, 스칼라(x) 전달 시 y·z와 함께 사용.
2310
+ * @example
2311
+ * new Vector(5, 12).dot(new Vector(-5, 12)); // -25+144 = 119
2312
+ * new Vector(1, 0).dot(new Vector(0, 1)); // 0 (직각)
2313
+ * new Vector(1, 2).dot(3, 4); // 1*3+2*4 = 11
2314
+ */
2315
+ dot(v, y = 0, z = 0) {
2215
2316
  if (v instanceof _Vector || v instanceof Point3D) {
2216
2317
  return this.x * v.x + this.y * v.y + this.z * v.z;
2217
2318
  }
2218
2319
  ;
2219
2320
  return this.x * v + this.y * y + this.z * z;
2220
2321
  }
2322
+ /**
2323
+ * 외적(cross product). 두 벡터에 수직인 벡터. 오른손 법칙 방향.
2324
+ * - 수식: a×b = (ay·bz − az·by, az·bx − ax·bz, ax·by − ay·bx)
2325
+ * - 2D에서는 z값 = ax·by − ay·bx (부호 있는 면적, 회전 방향 판정용).
2326
+ * @example
2327
+ * new Vector(1, 0, 0).cross(new Vector(0, 1, 0)); // (0, 0, 1)
2328
+ */
2221
2329
  cross(v) {
2222
2330
  const x = this.x, y = this.y, z = this.z;
2223
2331
  return new _Vector(y * v.z - v.y * z, z * v.x - v.z * x, x * v.y - v.x * y);
2224
2332
  }
2333
+ /**
2334
+ * 정규화 (파괴적). 방향은 그대로, 크기를 1로. 단위벡터 v̂ 생성.
2335
+ * - 수식: v̂ = v / |v|
2336
+ * - 영벡터(|v|=0)는 0으로 나누지 않고 그대로 둠.
2337
+ * @example
2338
+ * const v = new Vector(6, 8); v.normalize(); // v = (0.6, 0.8), |v| = 1
2339
+ */
2225
2340
  normalize() {
2226
- const m = this.mag();
2341
+ const m = this.norm();
2227
2342
  if (m > 0) this.div(m);
2228
2343
  }
2344
+ /**
2345
+ * 크기 상한 (파괴적). 속도가 high를 넘으면 방향 유지한 채 high로 자름. 물리 시뮬레이션 최고속도용.
2346
+ * - 수식: |v| > high → v = v̂ · high
2347
+ * @example
2348
+ * const v = new Vector(6, 8); v.limit(5); // |v|=10 → 5, v = (3, 4)
2349
+ */
2229
2350
  limit(high) {
2230
- if (this.mag() > high) {
2351
+ if (this.norm() > high) {
2231
2352
  this.normalize();
2232
2353
  this.mult(high);
2233
2354
  }
2234
2355
  }
2356
+ /**
2357
+ * 2D 방향각. +x축 기준 반시계 방향 라디안 (-π ~ π).
2358
+ * - 수식: θ = atan2(y, x)
2359
+ * @example
2360
+ * new Vector(1, 1).heading2D(); // π/4 (45°)
2361
+ * new Vector(-1, 0).heading2D(); // π (180°)
2362
+ */
2235
2363
  heading2D() {
2236
2364
  return -Math.atan2(-this.y, this.x);
2237
2365
  }
2366
+ /**
2367
+ * 무작위 방향 단위벡터 반환 (새 Vector, 자신은 변경 안 함).
2368
+ * @example
2369
+ * const r = new Vector().random2D(); // |r| = 1, 방향 랜덤
2370
+ */
2238
2371
  random2D() {
2239
2372
  return this.fromAngle(Math.random() * (2 * Math.PI));
2240
2373
  }
2374
+ /**
2375
+ * 각도→벡터. 각도 θ, 길이 L인 2D 벡터 반환 (새 Vector).
2376
+ * - 수식: (L·cosθ, L·sinθ, 0)
2377
+ * @example
2378
+ * new Vector().fromAngle(Math.PI / 3, 2); // (1, 1.73, 0)
2379
+ */
2241
2380
  fromAngle(angle, length = 1) {
2242
2381
  return new _Vector(length * Math.cos(angle), length * Math.sin(angle), 0);
2243
2382
  }
2383
+ /**
2384
+ * 구면좌표→3D 벡터 (새 Vector 반환, p5.js 컨벤션).
2385
+ * - 수식: (L·sinθ·sinφ, −L·cosθ, L·sinθ·cosφ)
2386
+ * @example
2387
+ * new Vector().fromAngles(Math.PI / 2, Math.PI / 2, 1); // (1, 0, 0)
2388
+ */
2244
2389
  fromAngles(theta, phi, length = 1) {
2245
2390
  const cosPhi = Math.cos(phi);
2246
2391
  const sinPhi = Math.sin(phi);
@@ -2252,18 +2397,43 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
2252
2397
  length * sinTheta * cosPhi
2253
2398
  );
2254
2399
  }
2400
+ /**
2401
+ * 성분 배열 반환. [x, y, z] 순서.
2402
+ * @example
2403
+ * new Vector(1, 2, 3).array(); // [1, 2, 3]
2404
+ */
2255
2405
  array() {
2256
2406
  return [this.x, this.y, this.z];
2257
2407
  }
2408
+ /**
2409
+ * Point3D로 변환 (위치 의미로 바꿀 때).
2410
+ * @example
2411
+ * new Vector(1, 2, 3).toPoint3D(); // Point3D(1, 2, 3)
2412
+ */
2258
2413
  toPoint3D() {
2259
2414
  return new Point3D(this.x, this.y, this.z);
2260
2415
  }
2416
+ /**
2417
+ * Point2D로 변환 (z 버림).
2418
+ * @example
2419
+ * new Vector(1, 2, 3).toPoint2D(); // Point2D(1, 2)
2420
+ */
2261
2421
  toPoint2D() {
2262
2422
  return new Point2D(this.x, this.y);
2263
2423
  }
2424
+ /**
2425
+ * 복사본 반환 (get()과 동일, 비파괴).
2426
+ * @example
2427
+ * const c = v.copy(); // v와 같은 성분의 새 벡터
2428
+ */
2264
2429
  copy() {
2265
2430
  return new _Vector(this.x, this.y, this.z);
2266
2431
  }
2432
+ /**
2433
+ * 문자열 표현. "[x, y, z]" 형식.
2434
+ * @example
2435
+ * new Vector(1, 2).toString(); // "[1, 2, 0]"
2436
+ */
2267
2437
  toString() {
2268
2438
  return "[" + this.x + ", " + this.y + ", " + this.z + "]";
2269
2439
  }
@@ -7109,7 +7279,7 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
7109
7279
 
7110
7280
  // ../core/dist/esm/url/UrlUtils.js
7111
7281
  var UrlUtils;
7112
- ((UrlUtils2) => {
7282
+ (function(UrlUtils2) {
7113
7283
  UrlUtils2.origin = (fullurl) => {
7114
7284
  return new URL(fullurl).origin;
7115
7285
  };
@@ -7147,15 +7317,28 @@ var dooboostoreSimpleBootHttpServerWebSocketClient = (() => {
7147
7317
  });
7148
7318
  return searchParams;
7149
7319
  };
7320
+ UrlUtils2.toAbsoluteUrl = (relative, base) => {
7321
+ return new URL(relative, base);
7322
+ };
7323
+ function toAbsoluteRequest(input, base) {
7324
+ if (input instanceof URL) {
7325
+ return UrlUtils2.toAbsoluteUrl(input.href, base);
7326
+ }
7327
+ if (typeof input === "string") {
7328
+ return UrlUtils2.toAbsoluteUrl(input, base).href;
7329
+ }
7330
+ return new Request(UrlUtils2.toAbsoluteUrl(input.url, base).href, input);
7331
+ }
7332
+ UrlUtils2.toAbsoluteRequest = toAbsoluteRequest;
7150
7333
  UrlUtils2.manipulateSearchParams = (searchParams, options) => {
7151
7334
  if (options?.delete) {
7152
- (0, UrlUtils2.deleteSearchParam)(searchParams, options.delete);
7335
+ UrlUtils2.deleteSearchParam(searchParams, options.delete);
7153
7336
  }
7154
7337
  if (options?.append) {
7155
- (0, UrlUtils2.appendSearchParam)(searchParams, options.append);
7338
+ UrlUtils2.appendSearchParam(searchParams, options.append);
7156
7339
  }
7157
7340
  if (options?.upsert) {
7158
- (0, UrlUtils2.upsertSearchParam)(searchParams, options.upsert);
7341
+ UrlUtils2.upsertSearchParam(searchParams, options.upsert);
7159
7342
  }
7160
7343
  return searchParams;
7161
7344
  };
@@ -9549,6 +9732,23 @@ ${indentStr}}`;
9549
9732
  };
9550
9733
  }
9551
9734
 
9735
+ // ../core/dist/esm/hash/HashUtils.js
9736
+ var HashUtils;
9737
+ ((HashUtils2) => {
9738
+ const core53 = (str, seed) => {
9739
+ let h1 = 3735928559 ^ seed, h2 = 1103547991 ^ seed;
9740
+ for (let i = 0; i < str.length; i++) {
9741
+ const ch = str.charCodeAt(i);
9742
+ h1 = Math.imul(h1 ^ ch, 2654435761);
9743
+ h2 = Math.imul(h2 ^ ch, 1597334677);
9744
+ }
9745
+ h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
9746
+ h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
9747
+ return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(16).padStart(14, "0");
9748
+ };
9749
+ HashUtils2.hash53 = (str, seed = 0, xyz = 16) => `${core53(str, seed)}${core53(str, seed + 1)}`.slice(0, Math.max(1, xyz));
9750
+ })(HashUtils || (HashUtils = {}));
9751
+
9552
9752
  // ../core/dist/esm/message/operators/filter.js
9553
9753
  function filter(predicate) {
9554
9754
  return (source) => {