From b2ebbfc8e6389f2d13b1f505ba7e9d3e855676ca Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 02:20:45 +0100 Subject: [PATCH 01/68] fix(strings): float type decl --- packages/strings/src/float.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/strings/src/float.ts b/packages/strings/src/float.ts index d38dd99846..5b8d2f71d6 100644 --- a/packages/strings/src/float.ts +++ b/packages/strings/src/float.ts @@ -8,7 +8,5 @@ import { Stringer } from "./api"; * @param len number of fractional digits * @kind function */ -export const float = memoizeJ( - (prec: number): Stringer => - (x: number) => x.toFixed(prec) -); +export const float: (prec: number) => Stringer = + memoizeJ((prec) => (x: number) => x.toFixed(prec)); From 6eb97b58688d560464111962533721c9059fe801 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 02:21:29 +0100 Subject: [PATCH 02/68] Publish - @thi.ng/iges@0.2.3 - @thi.ng/strings@0.1.1 --- packages/iges/CHANGELOG.md | 8 ++++++++ packages/iges/package.json | 4 ++-- packages/strings/CHANGELOG.md | 11 +++++++++++ packages/strings/package.json | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/iges/CHANGELOG.md b/packages/iges/CHANGELOG.md index e62a11c97f..eb517d7633 100644 --- a/packages/iges/CHANGELOG.md +++ b/packages/iges/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.3](https://github.com/thi-ng/umbrella/compare/@thi.ng/iges@0.2.2...@thi.ng/iges@0.2.3) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/iges + ## [0.2.2](https://github.com/thi-ng/umbrella/compare/@thi.ng/iges@0.2.1...@thi.ng/iges@0.2.2) (2018-08-08) diff --git a/packages/iges/package.json b/packages/iges/package.json index 71bcd9bbd0..03146e92cc 100644 --- a/packages/iges/package.json +++ b/packages/iges/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/iges", - "version": "0.2.2", + "version": "0.2.3", "description": "IGES 5.3 serializer for (currently only) polygonal geometry, both open & closed", "main": "./index.js", "typings": "./index.d.ts", @@ -30,7 +30,7 @@ "dependencies": { "@thi.ng/api": "^4.0.6", "@thi.ng/defmulti": "^0.3.7", - "@thi.ng/strings": "^0.1.0", + "@thi.ng/strings": "^0.1.1", "@thi.ng/transducers": "^1.15.0" }, "keywords": [ diff --git a/packages/strings/CHANGELOG.md b/packages/strings/CHANGELOG.md index b314981304..3d5fd2137a 100644 --- a/packages/strings/CHANGELOG.md +++ b/packages/strings/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/strings@0.1.0...@thi.ng/strings@0.1.1) (2018-08-08) + + +### Bug Fixes + +* **strings:** float type decl ([b2ebbfc](https://github.com/thi-ng/umbrella/commit/b2ebbfc)) + + + + # 0.1.0 (2018-08-08) diff --git a/packages/strings/package.json b/packages/strings/package.json index ab2c775d6b..85e7e1ef87 100644 --- a/packages/strings/package.json +++ b/packages/strings/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/strings", - "version": "0.1.0", + "version": "0.1.1", "description": "Various string formatting & utility functions", "main": "./index.js", "typings": "./index.d.ts", From a5e2c28a4b9c2328dcf67f10789b189802f0f1bf Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 03:21:01 +0100 Subject: [PATCH 03/68] feat(transducers): add partitionBits() xform & tests --- packages/transducers/src/index.ts | 1 + .../transducers/src/xform/partition-bits.ts | 56 +++++++++++++++++++ packages/transducers/test/partition-bits.ts | 33 +++++++++++ 3 files changed, 90 insertions(+) create mode 100644 packages/transducers/src/xform/partition-bits.ts create mode 100644 packages/transducers/test/partition-bits.ts diff --git a/packages/transducers/src/index.ts b/packages/transducers/src/index.ts index 9820ad436e..01bb5989dd 100644 --- a/packages/transducers/src/index.ts +++ b/packages/transducers/src/index.ts @@ -68,6 +68,7 @@ export * from "./xform/multiplex-obj"; export * from "./xform/noop"; export * from "./xform/pad-last"; export * from "./xform/page"; +export * from "./xform/partition-bits"; export * from "./xform/partition-by"; export * from "./xform/partition-of"; export * from "./xform/partition-sort"; diff --git a/packages/transducers/src/xform/partition-bits.ts b/packages/transducers/src/xform/partition-bits.ts new file mode 100644 index 0000000000..bc33d25408 --- /dev/null +++ b/packages/transducers/src/xform/partition-bits.ts @@ -0,0 +1,56 @@ +import { Transducer } from "../api"; +import { isReduced } from "../reduced"; + +/** + * Transducer. + * + * @param fn + * @param stateful + */ +export function partitionBits(n: number, wordSize = 8): Transducer { + return ([init, complete, reduce]) => { + const maxb = wordSize - n; + const m1 = (1 << wordSize) - 1; + const m2 = (1 << n) - 1; + let r = 0; + let y = 0; + return [ + init, + (acc) => complete(r > 0 ? reduce(acc, y) : acc), + n < wordSize ? + (acc, x) => { + let b = 0; + do { + acc = reduce(acc, y + ((x >>> (maxb + r)) & m2)); + b += n - r; + x = (x << (n - r)) & m1; + y = 0; + r = 0; + } while (b <= maxb && !isReduced(acc)); + r = wordSize - b; + y = r > 0 ? (x >>> maxb) & m2 : 0; + return acc; + } : + n > wordSize ? + (acc, x) => { + if (r + wordSize <= n) { + y |= (x & m1) << (n - wordSize - r); + r += wordSize; + if (r === n) { + acc = reduce(acc, y); + y = 0; + r = 0; + } + } + else { + const k = n - r; + r = wordSize - k; + acc = reduce(acc, y | ((x >>> r) & ((1 << k) - 1))); + y = (x & ((1 << r) - 1)) << (n - r); + } + return acc; + } : + reduce + ]; + }; +} diff --git a/packages/transducers/test/partition-bits.ts b/packages/transducers/test/partition-bits.ts new file mode 100644 index 0000000000..9e6d09809e --- /dev/null +++ b/packages/transducers/test/partition-bits.ts @@ -0,0 +1,33 @@ +import * as assert from "assert"; +import { radix } from "@thi.ng/strings/radix"; + +import { comp } from "../src/func/comp"; +import { range } from "../src/iter/range"; +import { iterator } from "../src/iterator"; +import { run } from "../src/run"; +import { bits } from "../src/xform/bits"; +import { map } from "../src/xform/map"; +import { padLast } from "../src/xform/pad-last"; +import { partition } from "../src/xform/partition"; +import { partitionBits } from "../src/xform/partition-bits"; + +const src = [0xff, 0xa5, 0xfe, 0xf7]; + +const xform = (n: number) => + comp(partitionBits(n), map(radix(2, n))); + +const xformB = (n: number) => + comp(bits(8), padLast(n, 0), partition(n, true), map((x) => x.join(""))); + +const check = (n: number) => + assert.deepEqual( + [...iterator(xform(n), src)], + [...iterator(xformB(n), src)], + `bits=${n}` + ); + +describe("partitionBits", () => { + + it("all sizes", () => run(map((n: number) => check(n)), range(1, 33))); + +}); \ No newline at end of file From 5864f2cd09437990de3d3fd80f74c89cddb17b12 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 03:44:31 +0100 Subject: [PATCH 04/68] feat(strings): add opt prefix arg for radix() --- packages/strings/src/radix.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/strings/src/radix.ts b/packages/strings/src/radix.ts index bd57d0e49a..61f81ffd29 100644 --- a/packages/strings/src/radix.ts +++ b/packages/strings/src/radix.ts @@ -4,18 +4,20 @@ import { Stringer } from "./api"; import { repeat } from "./repeat"; /** - * Returns a `Stringer` which formats given numbers to `radix` and `len`. + * Returns a `Stringer` which formats given numbers to `radix`, `len` + * and with optional prefix (not included in `len`). * * @param radix * @param len + * @param prefix */ -export const radix: (radix: number, len: number) => Stringer = +export const radix: (radix: number, len: number, prefix?: string) => Stringer = memoizeJ( - (radix: number, n: number) => { + (radix: number, n: number, prefix = "") => { const buf = repeat("0", n); return (x: any) => { x = (x >>> 0).toString(radix); - return x.length < n ? buf.substr(x.length) + x : x; + return prefix + (x.length < n ? buf.substr(x.length) + x : x); }; } ); From b1ea9a555435539bcf8cf86598141acc41bcc7af Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 03:46:17 +0100 Subject: [PATCH 05/68] refactor(transducers): deprecate hex(), update hexDump() xform & deps --- packages/transducers/package.json | 5 +++-- packages/transducers/src/func/hex.ts | 15 ++++++++------- packages/transducers/src/xform/hex-dump.ts | 7 ++++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/transducers/package.json b/packages/transducers/package.json index 18b0c4842b..525001a0e7 100644 --- a/packages/transducers/package.json +++ b/packages/transducers/package.json @@ -32,7 +32,8 @@ "@thi.ng/checks": "^1.5.7", "@thi.ng/compare": "^0.1.6", "@thi.ng/equiv": "^0.1.7", - "@thi.ng/errors": "^0.1.6" + "@thi.ng/errors": "^0.1.6", + "@thi.ng/strings": "^0.1.1" }, "keywords": [ "ES6", @@ -48,4 +49,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/packages/transducers/src/func/hex.ts b/packages/transducers/src/func/hex.ts index 4f67059678..d5228cf139 100644 --- a/packages/transducers/src/func/hex.ts +++ b/packages/transducers/src/func/hex.ts @@ -1,8 +1,9 @@ -const ZEROES = "00000000"; +import { radix } from "@thi.ng/strings/radix"; -export function hex(digits = 2, prefix = "") { - return (x: number) => { - const s = x.toString(16); - return prefix + (s.length >= digits ? s : ZEROES.substring(0, digits - s.length) + s); - } -} +/** + * @deprecated use thi.ng/strings `radix()` instead + * + * @param digits + * @param prefix + */ +export const hex = (digits = 2, prefix = "") => radix(16, digits, prefix); diff --git a/packages/transducers/src/xform/hex-dump.ts b/packages/transducers/src/xform/hex-dump.ts index 4d38423921..5f9b3bc594 100644 --- a/packages/transducers/src/xform/hex-dump.ts +++ b/packages/transducers/src/xform/hex-dump.ts @@ -1,7 +1,8 @@ +import { U8, U32 } from "@thi.ng/strings/radix"; + import { Transducer } from "../api"; import { comp } from "../func/comp"; -import { hex } from "../func/hex"; import { juxt } from "../func/juxt"; import { map } from "./map"; @@ -29,7 +30,7 @@ import { partition } from "./partition"; export function hexDump(cols = 16, addr = 0): Transducer { return comp( padLast(cols, 0), - map(juxt(hex(), (x) => x > 31 && x < 128 ? String.fromCharCode(x) : ".")), + map(juxt(U8, (x) => x > 31 && x < 128 ? String.fromCharCode(x) : ".")), partition(cols, true), map( juxt( @@ -37,6 +38,6 @@ export function hexDump(cols = 16, addr = 0): Transducer { (x) => x.map(y => y[1]).join("") ) ), - mapIndexed((i, [h, a]) => `${hex(8)(addr + i * cols)} | ${h} | ${a}`) + mapIndexed((i, [h, a]) => `${U32(addr + i * cols)} | ${h} | ${a}`) ); } From 6a0db9c79cb3001a5505662c3b7d3882c0fe26ca Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 03:47:41 +0100 Subject: [PATCH 06/68] refactor(examples): replace hex() => radix(), update deps --- examples/hdom-benchmark/package.json | 1 + examples/hdom-benchmark/src/index.ts | 6 +++--- examples/svg-particles/package.json | 1 + examples/svg-particles/src/index.ts | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/hdom-benchmark/package.json b/examples/hdom-benchmark/package.json index 50a0ab2e65..144b2c1404 100644 --- a/examples/hdom-benchmark/package.json +++ b/examples/hdom-benchmark/package.json @@ -20,6 +20,7 @@ "@thi.ng/hdom": "latest", "@thi.ng/hdom-components": "latest", "@thi.ng/rstream": "latest", + "@thi.ng/strings": "latest", "@thi.ng/transducers": "latest" } } \ No newline at end of file diff --git a/examples/hdom-benchmark/src/index.ts b/examples/hdom-benchmark/src/index.ts index 45fdf5b31c..ea665bc1d5 100644 --- a/examples/hdom-benchmark/src/index.ts +++ b/examples/hdom-benchmark/src/index.ts @@ -2,8 +2,8 @@ import { start } from "@thi.ng/hdom"; import { dropdown } from "@thi.ng/hdom-components/dropdown"; import { fromRAF } from "@thi.ng/rstream/from/raf"; import { Stream } from "@thi.ng/rstream/stream"; +import { radix } from "@thi.ng/strings/radix"; import { comp } from "@thi.ng/transducers/func/comp"; -import { hex } from "@thi.ng/transducers/func/hex"; import { range } from "@thi.ng/transducers/iter/range"; import { iterator } from "@thi.ng/transducers/iterator"; import { benchmark } from "@thi.ng/transducers/xform/benchmark"; @@ -13,8 +13,8 @@ import { movingAverage } from "@thi.ng/transducers/xform/moving-average"; import { partition } from "@thi.ng/transducers/xform/partition"; // pre-defined hex formatters -const hex4 = hex(4); -const hex6 = hex(6); +const hex4 = radix(16, 4); +const hex6 = radix(16, 6); /** * Single box component. Uses given id to switch between using `div` or diff --git a/examples/svg-particles/package.json b/examples/svg-particles/package.json index a6db945db8..f7e8302cf5 100644 --- a/examples/svg-particles/package.json +++ b/examples/svg-particles/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "@thi.ng/hdom": "latest", + "@thi.ng/strings": "latest", "@thi.ng/transducers": "latest" } } \ No newline at end of file diff --git a/examples/svg-particles/src/index.ts b/examples/svg-particles/src/index.ts index f0cb42aa06..98b644f188 100644 --- a/examples/svg-particles/src/index.ts +++ b/examples/svg-particles/src/index.ts @@ -1,10 +1,10 @@ import { start } from "@thi.ng/hdom"; -import { hex } from "@thi.ng/transducers/func/hex"; +import { radix } from "@thi.ng/strings/radix"; import { repeatedly } from "@thi.ng/transducers/iter/repeatedly"; const width = window.innerWidth; const height = window.innerHeight; -const hex6 = hex(6); +const hex6 = radix(16, 6); const updateParticle = (p, v) => { let x = p.cx + v[0]; From ea768ad06924322e640ac2d669cc91c5dd84c895 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 03:52:19 +0100 Subject: [PATCH 07/68] Publish - @thi.ng/csp@0.3.55 - @thi.ng/hiccup-css@0.2.14 - @thi.ng/iges@0.2.4 - @thi.ng/range-coder@0.1.4 - @thi.ng/rstream-csp@0.1.96 - @thi.ng/rstream-dot@0.2.35 - @thi.ng/rstream-gestures@0.4.16 - @thi.ng/rstream-graph@2.1.20 - @thi.ng/rstream-log@1.0.47 - @thi.ng/rstream-query@0.3.34 - @thi.ng/rstream@1.11.2 - @thi.ng/sax@0.3.13 - @thi.ng/strings@0.2.0 - @thi.ng/transducers-fsm@0.2.12 - @thi.ng/transducers-hdom@0.1.2 - @thi.ng/transducers-stats@0.3.4 - @thi.ng/transducers@1.16.0 --- packages/csp/CHANGELOG.md | 8 ++++++++ packages/csp/package.json | 4 ++-- packages/hiccup-css/CHANGELOG.md | 8 ++++++++ packages/hiccup-css/package.json | 4 ++-- packages/iges/CHANGELOG.md | 8 ++++++++ packages/iges/package.json | 6 +++--- packages/range-coder/CHANGELOG.md | 8 ++++++++ packages/range-coder/package.json | 4 ++-- packages/rstream-csp/CHANGELOG.md | 8 ++++++++ packages/rstream-csp/package.json | 6 +++--- packages/rstream-dot/CHANGELOG.md | 8 ++++++++ packages/rstream-dot/package.json | 4 ++-- packages/rstream-gestures/CHANGELOG.md | 8 ++++++++ packages/rstream-gestures/package.json | 6 +++--- packages/rstream-graph/CHANGELOG.md | 8 ++++++++ packages/rstream-graph/package.json | 6 +++--- packages/rstream-log/CHANGELOG.md | 8 ++++++++ packages/rstream-log/package.json | 6 +++--- packages/rstream-query/CHANGELOG.md | 8 ++++++++ packages/rstream-query/package.json | 8 ++++---- packages/rstream/CHANGELOG.md | 8 ++++++++ packages/rstream/package.json | 4 ++-- packages/sax/CHANGELOG.md | 8 ++++++++ packages/sax/package.json | 6 +++--- packages/strings/CHANGELOG.md | 11 +++++++++++ packages/strings/package.json | 2 +- packages/transducers-fsm/CHANGELOG.md | 8 ++++++++ packages/transducers-fsm/package.json | 4 ++-- packages/transducers-hdom/CHANGELOG.md | 8 ++++++++ packages/transducers-hdom/package.json | 4 ++-- packages/transducers-stats/CHANGELOG.md | 8 ++++++++ packages/transducers-stats/package.json | 4 ++-- packages/transducers/CHANGELOG.md | 11 +++++++++++ packages/transducers/package.json | 6 +++--- 34 files changed, 184 insertions(+), 42 deletions(-) diff --git a/packages/csp/CHANGELOG.md b/packages/csp/CHANGELOG.md index 05830dca7f..174cf47b51 100644 --- a/packages/csp/CHANGELOG.md +++ b/packages/csp/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.3.55](https://github.com/thi-ng/umbrella/compare/@thi.ng/csp@0.3.54...@thi.ng/csp@0.3.55) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/csp + ## [0.3.54](https://github.com/thi-ng/umbrella/compare/@thi.ng/csp@0.3.53...@thi.ng/csp@0.3.54) (2018-08-02) diff --git a/packages/csp/package.json b/packages/csp/package.json index 58db97d3a2..0c5ca6b148 100644 --- a/packages/csp/package.json +++ b/packages/csp/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/csp", - "version": "0.3.54", + "version": "0.3.55", "description": "ES6 promise based CSP implementation", "main": "./index.js", "typings": "./index.d.ts", @@ -36,7 +36,7 @@ "@thi.ng/checks": "^1.5.7", "@thi.ng/dcons": "^1.0.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/transducers": "^1.15.0" + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "async", diff --git a/packages/hiccup-css/CHANGELOG.md b/packages/hiccup-css/CHANGELOG.md index 28e58a8f4c..572573b5f1 100644 --- a/packages/hiccup-css/CHANGELOG.md +++ b/packages/hiccup-css/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.14](https://github.com/thi-ng/umbrella/compare/@thi.ng/hiccup-css@0.2.13...@thi.ng/hiccup-css@0.2.14) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/hiccup-css + ## [0.2.13](https://github.com/thi-ng/umbrella/compare/@thi.ng/hiccup-css@0.2.12...@thi.ng/hiccup-css@0.2.13) (2018-08-02) diff --git a/packages/hiccup-css/package.json b/packages/hiccup-css/package.json index d3363026a6..0d38b59268 100644 --- a/packages/hiccup-css/package.json +++ b/packages/hiccup-css/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/hiccup-css", - "version": "0.2.13", + "version": "0.2.14", "description": "CSS from nested JS data structures", "main": "./index.js", "typings": "./index.d.ts", @@ -31,7 +31,7 @@ "@thi.ng/api": "^4.0.6", "@thi.ng/checks": "^1.5.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/transducers": "^1.15.0" + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "clojure", diff --git a/packages/iges/CHANGELOG.md b/packages/iges/CHANGELOG.md index eb517d7633..814ea35ad3 100644 --- a/packages/iges/CHANGELOG.md +++ b/packages/iges/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.4](https://github.com/thi-ng/umbrella/compare/@thi.ng/iges@0.2.3...@thi.ng/iges@0.2.4) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/iges + ## [0.2.3](https://github.com/thi-ng/umbrella/compare/@thi.ng/iges@0.2.2...@thi.ng/iges@0.2.3) (2018-08-08) diff --git a/packages/iges/package.json b/packages/iges/package.json index 03146e92cc..f415d313c1 100644 --- a/packages/iges/package.json +++ b/packages/iges/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/iges", - "version": "0.2.3", + "version": "0.2.4", "description": "IGES 5.3 serializer for (currently only) polygonal geometry, both open & closed", "main": "./index.js", "typings": "./index.d.ts", @@ -30,8 +30,8 @@ "dependencies": { "@thi.ng/api": "^4.0.6", "@thi.ng/defmulti": "^0.3.7", - "@thi.ng/strings": "^0.1.1", - "@thi.ng/transducers": "^1.15.0" + "@thi.ng/strings": "^0.2.0", + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "CAD", diff --git a/packages/range-coder/CHANGELOG.md b/packages/range-coder/CHANGELOG.md index 32d9017683..9f011827df 100644 --- a/packages/range-coder/CHANGELOG.md +++ b/packages/range-coder/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.4](https://github.com/thi-ng/umbrella/compare/@thi.ng/range-coder@0.1.3...@thi.ng/range-coder@0.1.4) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/range-coder + ## [0.1.3](https://github.com/thi-ng/umbrella/compare/@thi.ng/range-coder@0.1.2...@thi.ng/range-coder@0.1.3) (2018-08-02) diff --git a/packages/range-coder/package.json b/packages/range-coder/package.json index 5f126b326e..1479fd5a5e 100644 --- a/packages/range-coder/package.json +++ b/packages/range-coder/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/range-coder", - "version": "0.1.3", + "version": "0.1.4", "description": "Binary data range encoder / decoder", "main": "./index.js", "typings": "./index.d.ts", @@ -20,7 +20,7 @@ "test": "rm -rf build && tsc -p test && nyc mocha build/test/*.js" }, "devDependencies": { - "@thi.ng/transducers": "^1.15.0", + "@thi.ng/transducers": "^1.16.0", "@types/mocha": "^5.2.5", "@types/node": "^10.5.5", "mocha": "^5.2.0", diff --git a/packages/rstream-csp/CHANGELOG.md b/packages/rstream-csp/CHANGELOG.md index 1d79462d89..a594a2b9f1 100644 --- a/packages/rstream-csp/CHANGELOG.md +++ b/packages/rstream-csp/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.96](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-csp@0.1.95...@thi.ng/rstream-csp@0.1.96) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/rstream-csp + ## [0.1.95](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-csp@0.1.94...@thi.ng/rstream-csp@0.1.95) (2018-08-06) diff --git a/packages/rstream-csp/package.json b/packages/rstream-csp/package.json index d04d71e123..998b0b0356 100644 --- a/packages/rstream-csp/package.json +++ b/packages/rstream-csp/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-csp", - "version": "0.1.95", + "version": "0.1.96", "description": "@thi.ng/csp bridge module for @thi.ng/rstream", "main": "./index.js", "typings": "./index.d.ts", @@ -28,8 +28,8 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/csp": "^0.3.54", - "@thi.ng/rstream": "^1.11.1" + "@thi.ng/csp": "^0.3.55", + "@thi.ng/rstream": "^1.11.2" }, "keywords": [ "bridge", diff --git a/packages/rstream-dot/CHANGELOG.md b/packages/rstream-dot/CHANGELOG.md index e300656479..07b5a21a8e 100644 --- a/packages/rstream-dot/CHANGELOG.md +++ b/packages/rstream-dot/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.35](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-dot@0.2.34...@thi.ng/rstream-dot@0.2.35) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/rstream-dot + ## [0.2.34](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-dot@0.2.33...@thi.ng/rstream-dot@0.2.34) (2018-08-06) diff --git a/packages/rstream-dot/package.json b/packages/rstream-dot/package.json index f7d5eb8f36..21bade3336 100644 --- a/packages/rstream-dot/package.json +++ b/packages/rstream-dot/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-dot", - "version": "0.2.34", + "version": "0.2.35", "description": "Graphviz DOT conversion of @thi.ng/rstream dataflow graph topologies", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/rstream": "^1.11.1" + "@thi.ng/rstream": "^1.11.2" }, "keywords": [ "conversion", diff --git a/packages/rstream-gestures/CHANGELOG.md b/packages/rstream-gestures/CHANGELOG.md index 43cfc9ac5c..0f48ee9225 100644 --- a/packages/rstream-gestures/CHANGELOG.md +++ b/packages/rstream-gestures/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.4.16](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-gestures@0.4.15...@thi.ng/rstream-gestures@0.4.16) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/rstream-gestures + ## [0.4.15](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-gestures@0.4.14...@thi.ng/rstream-gestures@0.4.15) (2018-08-06) diff --git a/packages/rstream-gestures/package.json b/packages/rstream-gestures/package.json index 60c063cb11..89ec46963d 100644 --- a/packages/rstream-gestures/package.json +++ b/packages/rstream-gestures/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-gestures", - "version": "0.4.15", + "version": "0.4.16", "description": "Unified mouse, mouse wheel & single-touch event stream abstraction", "main": "./index.js", "typings": "./index.d.ts", @@ -29,8 +29,8 @@ }, "dependencies": { "@thi.ng/api": "^4.0.6", - "@thi.ng/rstream": "^1.11.1", - "@thi.ng/transducers": "^1.15.0" + "@thi.ng/rstream": "^1.11.2", + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "dataflow", diff --git a/packages/rstream-graph/CHANGELOG.md b/packages/rstream-graph/CHANGELOG.md index ef2046ebb4..20a00a093b 100644 --- a/packages/rstream-graph/CHANGELOG.md +++ b/packages/rstream-graph/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [2.1.20](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-graph@2.1.19...@thi.ng/rstream-graph@2.1.20) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/rstream-graph + ## [2.1.19](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-graph@2.1.18...@thi.ng/rstream-graph@2.1.19) (2018-08-06) diff --git a/packages/rstream-graph/package.json b/packages/rstream-graph/package.json index 984fed2bec..b365aa1c54 100644 --- a/packages/rstream-graph/package.json +++ b/packages/rstream-graph/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-graph", - "version": "2.1.19", + "version": "2.1.20", "description": "Declarative dataflow graph construction for @thi.ng/rstream", "main": "./index.js", "typings": "./index.d.ts", @@ -33,8 +33,8 @@ "@thi.ng/errors": "^0.1.6", "@thi.ng/paths": "^1.5.2", "@thi.ng/resolve-map": "^3.0.7", - "@thi.ng/rstream": "^1.11.1", - "@thi.ng/transducers": "^1.15.0" + "@thi.ng/rstream": "^1.11.2", + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "compute", diff --git a/packages/rstream-log/CHANGELOG.md b/packages/rstream-log/CHANGELOG.md index 9ee59ce2c3..fda5d78d35 100644 --- a/packages/rstream-log/CHANGELOG.md +++ b/packages/rstream-log/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.0.47](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-log@1.0.46...@thi.ng/rstream-log@1.0.47) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/rstream-log + ## [1.0.46](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-log@1.0.45...@thi.ng/rstream-log@1.0.46) (2018-08-06) diff --git a/packages/rstream-log/package.json b/packages/rstream-log/package.json index 31f869ccec..56af579fe3 100644 --- a/packages/rstream-log/package.json +++ b/packages/rstream-log/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-log", - "version": "1.0.46", + "version": "1.0.47", "description": "Structured, multilevel & hierarchical loggers based on @thi.ng/rstream", "main": "./index.js", "typings": "./index.d.ts", @@ -31,8 +31,8 @@ "@thi.ng/api": "^4.0.6", "@thi.ng/checks": "^1.5.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/rstream": "^1.11.1", - "@thi.ng/transducers": "^1.15.0" + "@thi.ng/rstream": "^1.11.2", + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "ES6", diff --git a/packages/rstream-query/CHANGELOG.md b/packages/rstream-query/CHANGELOG.md index 3dd2663732..5764dcb1ae 100644 --- a/packages/rstream-query/CHANGELOG.md +++ b/packages/rstream-query/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.3.34](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-query@0.3.33...@thi.ng/rstream-query@0.3.34) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/rstream-query + ## [0.3.33](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-query@0.3.32...@thi.ng/rstream-query@0.3.33) (2018-08-06) diff --git a/packages/rstream-query/package.json b/packages/rstream-query/package.json index e70ba85eaf..bed0ffb37a 100644 --- a/packages/rstream-query/package.json +++ b/packages/rstream-query/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-query", - "version": "0.3.33", + "version": "0.3.34", "description": "@thi.ng/rstream based triple store & reactive query engine", "main": "./index.js", "typings": "./index.d.ts", @@ -33,9 +33,9 @@ "@thi.ng/checks": "^1.5.7", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/rstream": "^1.11.1", - "@thi.ng/rstream-dot": "^0.2.34", - "@thi.ng/transducers": "^1.15.0" + "@thi.ng/rstream": "^1.11.2", + "@thi.ng/rstream-dot": "^0.2.35", + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "dataflow", diff --git a/packages/rstream/CHANGELOG.md b/packages/rstream/CHANGELOG.md index 95255e6312..93238a4c82 100644 --- a/packages/rstream/CHANGELOG.md +++ b/packages/rstream/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.11.2](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream@1.11.1...@thi.ng/rstream@1.11.2) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/rstream + ## [1.11.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream@1.11.0...@thi.ng/rstream@1.11.1) (2018-08-06) diff --git a/packages/rstream/package.json b/packages/rstream/package.json index 1f7c6259bf..fd93485f6b 100644 --- a/packages/rstream/package.json +++ b/packages/rstream/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream", - "version": "1.11.1", + "version": "1.11.2", "description": "Reactive multi-tap streams, dataflow & transformation pipeline constructs", "main": "./index.js", "typings": "./index.d.ts", @@ -34,7 +34,7 @@ "@thi.ng/checks": "^1.5.7", "@thi.ng/errors": "^0.1.6", "@thi.ng/paths": "^1.5.2", - "@thi.ng/transducers": "^1.15.0" + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "datastructure", diff --git a/packages/sax/CHANGELOG.md b/packages/sax/CHANGELOG.md index 49cf57d607..e4a1de4409 100644 --- a/packages/sax/CHANGELOG.md +++ b/packages/sax/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.3.13](https://github.com/thi-ng/umbrella/compare/@thi.ng/sax@0.3.12...@thi.ng/sax@0.3.13) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/sax + ## [0.3.12](https://github.com/thi-ng/umbrella/compare/@thi.ng/sax@0.3.11...@thi.ng/sax@0.3.12) (2018-08-02) diff --git a/packages/sax/package.json b/packages/sax/package.json index 318d6e078b..0e2072e7bf 100644 --- a/packages/sax/package.json +++ b/packages/sax/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/sax", - "version": "0.3.12", + "version": "0.3.13", "description": "Transducer-based, SAX-like, non-validating, speedy & tiny XML parser", "main": "./index.js", "typings": "./index.d.ts", @@ -29,8 +29,8 @@ }, "dependencies": { "@thi.ng/api": "^4.0.6", - "@thi.ng/transducers": "^1.15.0", - "@thi.ng/transducers-fsm": "^0.2.11" + "@thi.ng/transducers": "^1.16.0", + "@thi.ng/transducers-fsm": "^0.2.12" }, "keywords": [ "ES6", diff --git a/packages/strings/CHANGELOG.md b/packages/strings/CHANGELOG.md index 3d5fd2137a..2777331297 100644 --- a/packages/strings/CHANGELOG.md +++ b/packages/strings/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [0.2.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/strings@0.1.1...@thi.ng/strings@0.2.0) (2018-08-08) + + +### Features + +* **strings:** add opt prefix arg for radix() ([5864f2c](https://github.com/thi-ng/umbrella/commit/5864f2c)) + + + + ## [0.1.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/strings@0.1.0...@thi.ng/strings@0.1.1) (2018-08-08) diff --git a/packages/strings/package.json b/packages/strings/package.json index 85e7e1ef87..0ade10c618 100644 --- a/packages/strings/package.json +++ b/packages/strings/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/strings", - "version": "0.1.1", + "version": "0.2.0", "description": "Various string formatting & utility functions", "main": "./index.js", "typings": "./index.d.ts", diff --git a/packages/transducers-fsm/CHANGELOG.md b/packages/transducers-fsm/CHANGELOG.md index b4b56ac9f8..6acab0c0a9 100644 --- a/packages/transducers-fsm/CHANGELOG.md +++ b/packages/transducers-fsm/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.12](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-fsm@0.2.11...@thi.ng/transducers-fsm@0.2.12) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/transducers-fsm + ## [0.2.11](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-fsm@0.2.10...@thi.ng/transducers-fsm@0.2.11) (2018-08-02) diff --git a/packages/transducers-fsm/package.json b/packages/transducers-fsm/package.json index 3c2859c17a..113f63b278 100644 --- a/packages/transducers-fsm/package.json +++ b/packages/transducers-fsm/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/transducers-fsm", - "version": "0.2.11", + "version": "0.2.12", "description": "Transducer-based Finite State Machine transformer", "main": "./index.js", "typings": "./index.d.ts", @@ -29,7 +29,7 @@ }, "dependencies": { "@thi.ng/api": "^4.0.6", - "@thi.ng/transducers": "^1.15.0" + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "ES6", diff --git a/packages/transducers-hdom/CHANGELOG.md b/packages/transducers-hdom/CHANGELOG.md index 812eeb684c..ce84f6e27d 100644 --- a/packages/transducers-hdom/CHANGELOG.md +++ b/packages/transducers-hdom/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.2](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-hdom@0.1.1...@thi.ng/transducers-hdom@0.1.2) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/transducers-hdom + ## [0.1.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-hdom@0.1.0...@thi.ng/transducers-hdom@0.1.1) (2018-08-02) diff --git a/packages/transducers-hdom/package.json b/packages/transducers-hdom/package.json index 07ad1bdd46..b55c2b286a 100644 --- a/packages/transducers-hdom/package.json +++ b/packages/transducers-hdom/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/transducers-hdom", - "version": "0.1.1", + "version": "0.1.2", "description": "Transducer based UI updater for @thi.ng/hdom", "main": "./index.js", "typings": "./index.d.ts", @@ -30,7 +30,7 @@ "dependencies": { "@thi.ng/checks": "^1.5.7", "@thi.ng/hdom": "^3.0.32", - "@thi.ng/transducers": "^1.15.0" + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "diff", diff --git a/packages/transducers-stats/CHANGELOG.md b/packages/transducers-stats/CHANGELOG.md index 5b969ac598..40ca613732 100644 --- a/packages/transducers-stats/CHANGELOG.md +++ b/packages/transducers-stats/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.3.4](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-stats@0.3.3...@thi.ng/transducers-stats@0.3.4) (2018-08-08) + + + + +**Note:** Version bump only for package @thi.ng/transducers-stats + ## [0.3.3](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-stats@0.3.2...@thi.ng/transducers-stats@0.3.3) (2018-08-02) diff --git a/packages/transducers-stats/package.json b/packages/transducers-stats/package.json index 661842c8df..efb4541a8f 100644 --- a/packages/transducers-stats/package.json +++ b/packages/transducers-stats/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/transducers-stats", - "version": "0.3.3", + "version": "0.3.4", "description": "Transducers for statistical / technical analysis", "main": "./index.js", "typings": "./index.d.ts", @@ -30,7 +30,7 @@ "dependencies": { "@thi.ng/dcons": "^1.0.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/transducers": "^1.15.0" + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "ES6", diff --git a/packages/transducers/CHANGELOG.md b/packages/transducers/CHANGELOG.md index 1e6af91295..94bcbe0d66 100644 --- a/packages/transducers/CHANGELOG.md +++ b/packages/transducers/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [1.16.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers@1.15.0...@thi.ng/transducers@1.16.0) (2018-08-08) + + +### Features + +* **transducers:** add partitionBits() xform & tests ([a5e2c28](https://github.com/thi-ng/umbrella/commit/a5e2c28)) + + + + # [1.15.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers@1.14.3...@thi.ng/transducers@1.15.0) (2018-08-02) diff --git a/packages/transducers/package.json b/packages/transducers/package.json index 525001a0e7..d1a16bc03c 100644 --- a/packages/transducers/package.json +++ b/packages/transducers/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/transducers", - "version": "1.15.0", + "version": "1.16.0", "description": "Lightweight transducer implementations for ES6 / TypeScript", "main": "./index.js", "typings": "./index.d.ts", @@ -33,7 +33,7 @@ "@thi.ng/compare": "^0.1.6", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/strings": "^0.1.1" + "@thi.ng/strings": "^0.2.0" }, "keywords": [ "ES6", @@ -49,4 +49,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} From 723da5bb1113e7b3512d358ae75864cc4eac69b9 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 04:00:44 +0100 Subject: [PATCH 08/68] fix(transducers): hex type decl --- packages/transducers/src/func/hex.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/transducers/src/func/hex.ts b/packages/transducers/src/func/hex.ts index d5228cf139..747161cedc 100644 --- a/packages/transducers/src/func/hex.ts +++ b/packages/transducers/src/func/hex.ts @@ -6,4 +6,4 @@ import { radix } from "@thi.ng/strings/radix"; * @param digits * @param prefix */ -export const hex = (digits = 2, prefix = "") => radix(16, digits, prefix); +export const hex = (digits = 2, prefix = ""): (x: number) => string => radix(16, digits, prefix); From 45e49930aed7647a2e53fb446b810f01f4e4d50e Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 22:52:40 +0100 Subject: [PATCH 09/68] refactor(transducers): add ReductionFn type alias, update Reducer --- packages/transducers/src/api.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/transducers/src/api.ts b/packages/transducers/src/api.ts index f892d9d9ab..3e41b74ad2 100644 --- a/packages/transducers/src/api.ts +++ b/packages/transducers/src/api.ts @@ -6,10 +6,12 @@ export type Fn = (x: A) => B; export type Transducer = (rfn: Reducer) => Reducer; +export type ReductionFn = (acc: A, x: B) => A | Reduced; + export interface Reducer extends Array { [0]: () => A; [1]: (acc: A) => A; - [2]: (acc: A, x: B) => A | Reduced; + [2]: ReductionFn; }; export interface StructField extends Array { From e713704f2af5c15d8c9b11a72fff472cfc63b330 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 22:54:06 +0100 Subject: [PATCH 10/68] refactor(transducers): rename inspect() => trace() BREAKING CHANGE: rename inspect() => trace() --- packages/transducers/src/index.ts | 2 +- packages/transducers/src/xform/{inspect.ts => trace.ts} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename packages/transducers/src/xform/{inspect.ts => trace.ts} (67%) diff --git a/packages/transducers/src/index.ts b/packages/transducers/src/index.ts index 01bb5989dd..d012223abb 100644 --- a/packages/transducers/src/index.ts +++ b/packages/transducers/src/index.ts @@ -47,7 +47,6 @@ export * from "./xform/flatten-with"; export * from "./xform/flatten"; export * from "./xform/hex-dump"; export * from "./xform/indexed"; -export * from "./xform/inspect"; export * from "./xform/interleave"; export * from "./xform/interpose"; export * from "./xform/keep"; @@ -90,6 +89,7 @@ export * from "./xform/take-while"; export * from "./xform/take"; export * from "./xform/throttle"; export * from "./xform/throttle-time"; +export * from "./xform/trace"; export * from "./xform/utf8"; export * from "./xform/word-wrap"; diff --git a/packages/transducers/src/xform/inspect.ts b/packages/transducers/src/xform/trace.ts similarity index 67% rename from packages/transducers/src/xform/inspect.ts rename to packages/transducers/src/xform/trace.ts index 1267a747f3..7f6abe084f 100644 --- a/packages/transducers/src/xform/inspect.ts +++ b/packages/transducers/src/xform/trace.ts @@ -1,6 +1,6 @@ import { Transducer } from "../api"; import { sideEffect } from "./side-effect"; -export function inspect(prefix: string = ""): Transducer { +export function trace(prefix = ""): Transducer { return sideEffect((x) => console.log(prefix, x)); } From bae8a1d8c1853b23f0fb732e9f6915e6fa81456e Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:04:54 +0100 Subject: [PATCH 11/68] feat(transducers): update all xforms to also work as iterator - if input iterable is provided, return iterator version - add opt initial result arg for scan() - utf8Decode() w/ input returns string - update tests BREAKING CHANGE: replace some xform args with options objects, impacted are: - convolve2d() - filterFuzzy() - hexDump() - movingMedian() - partitionSort() - partitionSync() - streamSort() - wordWrap() --- packages/transducers/src/func/lookup.ts | 4 +- packages/transducers/src/iterator.ts | 11 + packages/transducers/src/xform/base64.ts | 200 ++++++++------- packages/transducers/src/xform/benchmark.ts | 29 ++- packages/transducers/src/xform/bits.ts | 46 ++-- packages/transducers/src/xform/cat.ts | 3 + packages/transducers/src/xform/convolve.ts | 73 +++--- packages/transducers/src/xform/dedupe.ts | 42 ++-- packages/transducers/src/xform/delayed.ts | 3 +- packages/transducers/src/xform/distinct.ts | 49 ++-- packages/transducers/src/xform/drop-nth.ts | 8 +- packages/transducers/src/xform/drop-while.ts | 20 +- packages/transducers/src/xform/drop.ts | 19 +- packages/transducers/src/xform/duplicate.ts | 27 ++- .../transducers/src/xform/filter-fuzzy.ts | 30 ++- packages/transducers/src/xform/filter.ts | 17 +- .../transducers/src/xform/flatten-with.ts | 35 +-- packages/transducers/src/xform/flatten.ts | 7 +- packages/transducers/src/xform/hex-dump.ts | 38 ++- packages/transducers/src/xform/indexed.ts | 13 +- packages/transducers/src/xform/interleave.ts | 25 +- packages/transducers/src/xform/interpose.ts | 35 +-- packages/transducers/src/xform/keep.ts | 18 +- packages/transducers/src/xform/labeled.ts | 19 +- packages/transducers/src/xform/map-deep.ts | 11 +- packages/transducers/src/xform/map-indexed.ts | 20 +- packages/transducers/src/xform/map-keys.ts | 21 +- packages/transducers/src/xform/map-nth.ts | 21 +- packages/transducers/src/xform/map-vals.ts | 18 +- packages/transducers/src/xform/map.ts | 17 +- packages/transducers/src/xform/mapcat.ts | 15 +- packages/transducers/src/xform/match-first.ts | 9 +- packages/transducers/src/xform/match-last.ts | 10 +- .../transducers/src/xform/moving-average.ts | 40 +-- .../transducers/src/xform/moving-median.ts | 34 ++- .../transducers/src/xform/multiplex-obj.ts | 18 +- packages/transducers/src/xform/pad-last.ts | 37 +-- packages/transducers/src/xform/page.ts | 17 +- .../transducers/src/xform/partition-bits.ts | 118 +++++---- .../transducers/src/xform/partition-by.ts | 66 ++--- .../transducers/src/xform/partition-of.ts | 31 ++- .../transducers/src/xform/partition-sort.ts | 33 ++- .../transducers/src/xform/partition-sync.ts | 94 ++++--- packages/transducers/src/xform/partition.ts | 21 +- packages/transducers/src/xform/pluck.ts | 9 +- packages/transducers/src/xform/rename.ts | 19 +- packages/transducers/src/xform/sample.ts | 18 +- packages/transducers/src/xform/scan.ts | 57 +++-- packages/transducers/src/xform/select-keys.ts | 15 +- .../transducers/src/xform/stream-shuffle.ts | 51 ++-- packages/transducers/src/xform/stream-sort.ts | 29 ++- packages/transducers/src/xform/struct.ts | 20 +- packages/transducers/src/xform/swizzle.ts | 15 +- packages/transducers/src/xform/take-last.ts | 46 ++-- packages/transducers/src/xform/take-nth.ts | 10 +- packages/transducers/src/xform/take-while.ts | 25 +- packages/transducers/src/xform/take.ts | 23 +- .../transducers/src/xform/throttle-time.ts | 25 +- packages/transducers/src/xform/throttle.ts | 20 +- packages/transducers/src/xform/utf8.ts | 229 +++++++++--------- packages/transducers/src/xform/word-wrap.ts | 31 ++- packages/transducers/test/flatten.ts | 20 +- packages/transducers/test/fuzzy.ts | 20 +- packages/transducers/test/pad-last.ts | 12 +- 64 files changed, 1312 insertions(+), 804 deletions(-) diff --git a/packages/transducers/src/func/lookup.ts b/packages/transducers/src/func/lookup.ts index d3e8e9941b..9adbd24da2 100644 --- a/packages/transducers/src/func/lookup.ts +++ b/packages/transducers/src/func/lookup.ts @@ -3,7 +3,7 @@ * lookup value in given array. No bounds checks are done. * * ``` - * [...iterator(map(lookup1d([10, 20, 30])), [2,0,1])] + * [...map(lookup1d([10, 20, 30]), [2,0,1])] * // [ 30, 10, 20 ] * ``` * @@ -21,7 +21,7 @@ export function lookup1d(src: T[]) { * (pixel buffer). No bounds checks are done. * * ``` - * [...iterator(map(lookup2d([...range(9)], 3)), range2d(2, -1, 0, 3))] + * [...map(lookup2d([...range(9)], 3), range2d(2, -1, 0, 3))] * // [ 2, 1, 0, 5, 4, 3, 8, 7, 6 ] * ``` * diff --git a/packages/transducers/src/iterator.ts b/packages/transducers/src/iterator.ts index e78b692b4f..aebd96a0b6 100644 --- a/packages/transducers/src/iterator.ts +++ b/packages/transducers/src/iterator.ts @@ -1,3 +1,5 @@ +import { isIterable } from "@thi.ng/checks/is-iterable"; + import { Reducer, Transducer } from "./api"; import { isReduced, unreduced } from "./reduced"; import { push } from "./rfn/push"; @@ -16,3 +18,12 @@ export function* iterator(tx: Transducer, xs: Iterable): Iterable } yield* unreduced(complete([])); } + +export const $iter = (xform: (...xs: any[]) => Transducer, args: any[]) => { + const n = args.length - 1; + return isIterable(args[n]) ? + args.length > 1 ? + iterator(xform.apply(null, args.slice(0, n)), args[n]) : + iterator(xform(), args[0]) : + undefined; +}; \ No newline at end of file diff --git a/packages/transducers/src/xform/base64.ts b/packages/transducers/src/xform/base64.ts index 13e48bf7ee..df7d737129 100644 --- a/packages/transducers/src/xform/base64.ts +++ b/packages/transducers/src/xform/base64.ts @@ -1,5 +1,6 @@ -import { Transducer, Reducer } from "../api"; +import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { $iter, iterator } from "../iterator"; import { isReduced, reduced } from "../reduced"; const B64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -9,106 +10,119 @@ const B64_SAFE = B64_CHARS.substr(0, 62) + "-_"; * Stateful transducer. Decodes base64 chars into bytes. * Supports URL safe & unsafe flavors. */ -export function base64Decode(): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - let bc = 0, bs = 0; - return compR(rfn, - (acc, x: string) => { - switch (x) { - case "-": - x = "+"; - break; - case "_": - x = "/"; - break; - case "=": - return reduced(acc); - default: - } - let y = B64_CHARS.indexOf(x); - bs = bc & 3 ? (bs << 6) + y : y; - if (bc++ & 3) { - acc = r(acc, 255 & bs >> (-2 * bc & 6)); - } - return acc; - }); - }; +export function base64Decode(): Transducer; +export function base64Decode(src: string): IterableIterator; +export function base64Decode(src?: string): any { + return src ? + iterator(base64Decode(), src) : + (rfn: Reducer) => { + const r = rfn[2]; + let bc = 0, bs = 0; + return compR(rfn, + (acc, x: string) => { + switch (x) { + case "-": + x = "+"; + break; + case "_": + x = "/"; + break; + case "=": + return reduced(acc); + default: + } + let y = B64_CHARS.indexOf(x); + bs = bc & 3 ? (bs << 6) + y : y; + if (bc++ & 3) { + acc = r(acc, 255 & bs >> (-2 * bc & 6)); + } + return acc; + }); + }; +} + +export interface Base64EncodeOpts { + safe: boolean; + buffer: number; } /** - * Stateful transducer. Encodes bytes into base64 chars. - * Supports URL safe & unsafe flavors. Uses internal - * buffer to store intermediate results and repeatedly - * calls reducer to drain buffer whenever it's been filled. + * Stateful transducer. Encodes bytes into base64 chars. Supports URL + * safe & unsafe flavors, configurable via provided options. Uses + * internal buffer (size also configurable, default = 1024) to store + * intermediate results. Then repeatedly calls reducer to drain buffer + * whenever it's been filled. * * @param urlSafe * @param bufSize */ -export function base64Encode(urlSafe = false, bufSize = 1024): Transducer { - return ([init, complete, reduce]: Reducer) => { - let a = 0, b; - const chars = urlSafe ? B64_SAFE : B64_CHARS; - const buf: string[] = []; - return [ - init, - (acc) => { - switch (a) { - case 1: - buf.push( - chars[b >> 18 & 0x3f], - chars[b >> 12 & 0x3f], - "=", - "=" - ); - break; - case 2: - buf.push( - chars[b >> 18 & 0x3f], - chars[b >> 12 & 0x3f], - chars[b >> 6 & 0x3f], - "=" - ); - break; - default: - } - while (buf.length && !isReduced(acc)) { - acc = reduce(acc, buf.shift()); - } - return complete(acc); - }, - (acc, x) => { - switch (a) { - case 0: - a = 1; - b = x << 16; - break; - case 1: - a = 2; - b += x << 8; - break; - default: - a = 0; - b += x; - buf.push( - chars[b >> 18 & 0x3f], - chars[b >> 12 & 0x3f], - chars[b >> 6 & 0x3f], - chars[b & 0x3f] - ); - if (buf.length >= bufSize) { - for (let i = 0, n = buf.length; i < n; i++) { - acc = reduce(acc, buf[i]); - if (isReduced(acc)) { - buf.length = 0; - return acc; +export function base64Encode(): Transducer; +export function base64Encode(opts: Partial): Transducer; +export function base64Encode(src: Iterable): IterableIterator; +export function base64Encode(opts: Partial, src: Iterable): IterableIterator; +export function base64Encode(...args: any[]): any { + return $iter(base64Encode, args) || + (([init, complete, reduce]: Reducer) => { + let state = 0; + let b: number; + const opts = { safe: false, buffer: 1024, ...args[0] }; + const chars = opts.safe ? B64_SAFE : B64_CHARS; + const buf: string[] = []; + return [ + init, + (acc) => { + switch (state) { + case 1: + buf.push( + chars[b >> 18 & 0x3f], + chars[b >> 12 & 0x3f], + "=", + "=" + ); + break; + case 2: + buf.push( + chars[b >> 18 & 0x3f], + chars[b >> 12 & 0x3f], + chars[b >> 6 & 0x3f], + "=" + ); + break; + default: + } + while (buf.length && !isReduced(acc)) { + acc = reduce(acc, buf.shift()); + } + return complete(acc); + }, + (acc, x) => { + switch (state) { + case 0: + state = 1; + b = x << 16; + break; + case 1: + state = 2; + b += x << 8; + break; + default: + state = 0; + b += x; + buf.push( + chars[b >> 18 & 0x3f], + chars[b >> 12 & 0x3f], + chars[b >> 6 & 0x3f], + chars[b & 0x3f] + ); + if (buf.length >= opts.buffer) { + for (let i = 0, n = buf.length; i < n && !isReduced(acc); i++) { + acc = reduce(acc, buf[i]); } + buf.length = 0; } - buf.length = 0; - } + } + return acc; } - return acc; - } - ]; - }; + ]; + }); } diff --git a/packages/transducers/src/xform/benchmark.ts b/packages/transducers/src/xform/benchmark.ts index c8758ecfb4..6d428a171c 100644 --- a/packages/transducers/src/xform/benchmark.ts +++ b/packages/transducers/src/xform/benchmark.ts @@ -1,5 +1,6 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; /** * Stateful transducer. Ignores the actual input values, but @@ -16,16 +17,20 @@ import { compR } from "../func/compr"; * ) * ``` */ -export function benchmark(): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - let prev = Date.now(); - return compR(rfn, - (acc, _) => { - const t = Date.now(); - const x = t - prev; - prev = t; - return r(acc, x); - }); - }; +export function benchmark(): Transducer; +export function benchmark(src: Iterable): IterableIterator; +export function benchmark(src?: Iterable): any { + return src ? + iterator(benchmark(), src) : + (rfn: Reducer) => { + const r = rfn[2]; + let prev = Date.now(); + return compR(rfn, + (acc, _) => { + const t = Date.now(); + const x = t - prev; + prev = t; + return r(acc, x); + }); + }; } diff --git a/packages/transducers/src/xform/bits.ts b/packages/transducers/src/xform/bits.ts index 6e7521bb04..67989187c8 100644 --- a/packages/transducers/src/xform/bits.ts +++ b/packages/transducers/src/xform/bits.ts @@ -1,5 +1,6 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { $iter } from "../iterator"; import { isReduced } from "../reduced"; /** @@ -17,28 +18,29 @@ import { isReduced } from "../reduced"; * @param wordSize * @param msbFirst */ -export function bits(wordSize = 8, msbFirst = true): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - return compR(rfn, - msbFirst ? - (acc, x: number) => { - for (let i = wordSize - 1; i >= 0; i--) { - acc = r(acc, (x >>> i) & 1); - if (isReduced(acc)) { - break; +export function bits(size?: number, msb?: boolean): Transducer; +export function bits(src: Iterable): IterableIterator; +export function bits(size: number, src: Iterable): IterableIterator; +export function bits(size: number, msb: boolean, src: Iterable): IterableIterator; +export function bits(...args: any[]): any { + return $iter(bits, args) || + ((rfn: Reducer) => { + const reduce = rfn[2]; + const size = (args[0] || 8) - 1; + const msb = args[1] !== false; + return compR(rfn, + msb ? + (acc, x: number) => { + for (let i = size; i >= 0 && !isReduced(acc); i--) { + acc = reduce(acc, (x >>> i) & 1); } - } - return acc; - } : - (acc, x: number) => { - for (let i = 0; i < wordSize; i++) { - acc = r(acc, (x >>> i) & 1); - if (isReduced(acc)) { - break; + return acc; + } : + (acc, x: number) => { + for (let i = 0; i <= size && !isReduced(acc); i++) { + acc = reduce(acc, (x >>> i) & 1); } - } - return acc; - }); - }; + return acc; + }); + }); } diff --git a/packages/transducers/src/xform/cat.ts b/packages/transducers/src/xform/cat.ts index 751c8109cf..6883cbf0f3 100644 --- a/packages/transducers/src/xform/cat.ts +++ b/packages/transducers/src/xform/cat.ts @@ -2,6 +2,9 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; import { isReduced } from "../reduced"; +/** + * Transducer to concatenate iterable values. + */ export function cat(): Transducer, T> { return (rfn: Reducer) => { const r = rfn[2]; diff --git a/packages/transducers/src/xform/convolve.ts b/packages/transducers/src/xform/convolve.ts index f57783ba7f..0f530d8a73 100644 --- a/packages/transducers/src/xform/convolve.ts +++ b/packages/transducers/src/xform/convolve.ts @@ -1,52 +1,71 @@ -import { illegalArity } from "@thi.ng/errors/illegal-arity"; +import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { ConvolutionKernel2D, Transducer } from "../api"; import { range2d } from "../iter/range2d"; import { tuples } from "../iter/tuples"; +import { iterator } from "../iterator"; import { add } from "../rfn/add"; import { transduce } from "../transduce"; import { map } from "./map"; -export function buildKernel2d(weights: Iterable, w: number, h: number): ConvolutionKernel2D { +export interface Convolution2DOpts { + src: number[]; + width: number; + height: number; + weights?: number[]; + kernel?: ConvolutionKernel2D; + kwidth?: number; + kheight?: number; + wrap?: boolean; + border?: number; +} + +export const buildKernel2d = (weights: Iterable, w: number, h: number): ConvolutionKernel2D => { const w2 = w >> 1; const h2 = h >> 1; return [...tuples(weights, range2d(-w2, w2 + 1, -h2, h2 + 1))]; -} +}; -function kernelLookup2d(src, x, y, width, height, wrap) { - return wrap ? +const kernelLookup2d = ( + src: number[], + x: number, + y: number, + width: number, + height: number, + wrap: boolean, + border: number) => + wrap ? ([w, [ox, oy]]) => { const xx = x < -ox ? width + ox : x >= width - ox ? ox - 1 : x + ox; const yy = y < -oy ? height + oy : y >= height - oy ? oy - 1 : y + oy; return w * src[yy * width + xx]; } : ([w, [ox, oy]]) => { - return (x < -ox || y < -oy || x >= width - ox || y >= height - oy) ? 0 : w * src[(y + oy) * width + x + ox]; - } -} + return (x < -ox || y < -oy || x >= width - ox || y >= height - oy) ? + border : + w * src[(y + oy) * width + x + ox]; + }; -export function convolve2d(src: number[], width: number, height: number, kernel: ConvolutionKernel2D, wrap?: boolean): Transducer; -export function convolve2d(src: number[], width: number, height: number, weights: number[], kwidth: number, kheight: number, wrap?: boolean): Transducer; -export function convolve2d(src: number[], width: number, height: number, ...args: any[]): Transducer { - let kernel; - let wrap = false; - switch (args.length) { - case 1: - case 2: - [kernel, wrap] = args; - break; - case 4: - wrap = args[3]; - case 3: - kernel = buildKernel2d.apply(null, args); - break; - default: - illegalArity(args.length + 3); +export function convolve2d(opts: Convolution2DOpts): Transducer; +export function convolve2d(opts: Convolution2DOpts, src: Iterable): IterableIterator; +export function convolve2d(opts: Convolution2DOpts, _src?: Iterable): any { + if (_src) { + return iterator(convolve2d(opts), _src); + } + const { src, width, height } = opts; + const wrap = opts.wrap !== false; + const border = opts.border || 0; + let kernel = opts.kernel; + if (!kernel) { + if (!(opts.weights && opts.kwidth && opts.kheight)) { + illegalArgs(`no kernel or kernel config`); + } + kernel = buildKernel2d(opts.weights, opts.kwidth, opts.kheight); } return map( - ([x, y]) => + (p: number[]) => transduce( - map(kernelLookup2d(src, x, y, width, height, wrap)), + map(kernelLookup2d(src, p[0], p[1], width, height, wrap, border)), add(), kernel ) diff --git a/packages/transducers/src/xform/dedupe.ts b/packages/transducers/src/xform/dedupe.ts index 9c8a487649..59a005cbfb 100644 --- a/packages/transducers/src/xform/dedupe.ts +++ b/packages/transducers/src/xform/dedupe.ts @@ -1,23 +1,29 @@ import { Predicate2 } from "@thi.ng/api/api"; -import { Reducer, Transducer, SEMAPHORE } from "../api"; +import { Reducer, SEMAPHORE, Transducer } from "../api"; import { compR } from "../func/compr"; +import { $iter } from "../iterator"; -export function dedupe(equiv?: Predicate2): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - let prev: any = SEMAPHORE; - return compR(rfn, - equiv ? - (acc, x) => { - acc = equiv(prev, x) ? acc : r(acc, x); - prev = x; - return acc; - } : - (acc, x) => { - acc = prev === x ? acc : r(acc, x); - prev = x; - return acc; - }); - }; +export function dedupe(equiv?: Predicate2): Transducer; +export function dedupe(src: Iterable): IterableIterator; +export function dedupe(equiv: Predicate2, src: Iterable): IterableIterator; +export function dedupe(...args: any[]): any { + return $iter(dedupe, args) || + ((rfn: Reducer) => { + const r = rfn[2]; + const equiv = args[0]; + let prev: any = SEMAPHORE; + return compR(rfn, + equiv ? + (acc, x: T) => { + acc = equiv(prev, x) ? acc : r(acc, x); + prev = x; + return acc; + } : + (acc, x: T) => { + acc = prev === x ? acc : r(acc, x); + prev = x; + return acc; + }); + }); } diff --git a/packages/transducers/src/xform/delayed.ts b/packages/transducers/src/xform/delayed.ts index 04037addc9..b9c3c44967 100644 --- a/packages/transducers/src/xform/delayed.ts +++ b/packages/transducers/src/xform/delayed.ts @@ -6,7 +6,8 @@ import { map } from "./map"; * Yields transducer which wraps incoming values in promises, which * resolve after specified delay time (in ms). * - * **Only to be used in async contexts and NOT with `transduce` directly.** + * **Only to be used in async contexts and NOT with `transduce` + * directly.** * * @param t */ diff --git a/packages/transducers/src/xform/distinct.ts b/packages/transducers/src/xform/distinct.ts index 27dc23e99e..02ea3a606c 100644 --- a/packages/transducers/src/xform/distinct.ts +++ b/packages/transducers/src/xform/distinct.ts @@ -1,18 +1,39 @@ + import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; -import { identity } from "../func/identity"; +import { $iter } from "../iterator"; + +export interface DistinctOpts { + key: (x: T) => any; + cache: () => Set; +} -export function distinct(mapfn: ((x: T) => any) = identity): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - const seen = new Set(); - return compR(rfn, - mapfn ? - (acc, x) => { - const k = mapfn(x); - return !seen.has(k) ? (seen.add(k), r(acc, x)) : acc; - } : - (acc, x) => !seen.has(x) ? (seen.add(x), r(acc, x)) : acc - ); - }; +/** + * + * ``` + * [...tx.distinct({ key: (x) => x.id }, [{id: 1, x: 2}, {id: 1, x: 3}])] + * // [ { id: 1, x: 2 } ] + * ``` + * + * @param opts + */ +export function distinct(opts?: Partial>): Transducer; +export function distinct(src: Iterable): IterableIterator; +export function distinct(opts: Partial>, src: Iterable): IterableIterator; +export function distinct(...args: any[]): any { + return $iter(distinct, args) || + ((rfn: Reducer) => { + const r = rfn[2]; + const opts = >(args[0] || {}); + const key = opts.key; + const seen = (opts.cache || (() => new Set()))(); + return compR(rfn, + key ? + (acc, x: T) => { + const k = key(x); + return !seen.has(k) ? (seen.add(k), r(acc, x)) : acc; + } : + (acc, x: T) => !seen.has(x) ? (seen.add(x), r(acc, x)) : acc + ); + }); } diff --git a/packages/transducers/src/xform/drop-nth.ts b/packages/transducers/src/xform/drop-nth.ts index 7077118311..afb8513c7f 100644 --- a/packages/transducers/src/xform/drop-nth.ts +++ b/packages/transducers/src/xform/drop-nth.ts @@ -1,7 +1,13 @@ import { Transducer } from "../api"; import { throttle } from "./throttle"; +import { iterator } from "../iterator"; -export function dropNth(n: number): Transducer { +export function dropNth(n: number): Transducer; +export function dropNth(n: number, src: Iterable): IterableIterator; +export function dropNth(n: number, src?: Iterable): any { + if (src) { + return iterator(dropNth(n), src); + } n = Math.max(0, n - 1); return throttle( () => { diff --git a/packages/transducers/src/xform/drop-while.ts b/packages/transducers/src/xform/drop-while.ts index df32ab8e1e..a950d72180 100644 --- a/packages/transducers/src/xform/drop-while.ts +++ b/packages/transducers/src/xform/drop-while.ts @@ -2,12 +2,18 @@ import { Predicate } from "@thi.ng/api/api"; import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { $iter } from "../iterator"; -export function dropWhile(pred: Predicate): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - let ok = true; - return compR(rfn, - (acc, x) => (ok = ok && pred(x)) ? acc : r(acc, x)); - }; +export function dropWhile(pred?: Predicate): Transducer; +export function dropWhile(src: Iterable): IterableIterator; +export function dropWhile(pred: Predicate, src: Iterable): IterableIterator; +export function dropWhile(...args: any[]): any { + return $iter(dropWhile, args) || + ((rfn: Reducer) => { + const r = rfn[2]; + const pred = args[0]; + let ok = true; + return compR(rfn, + (acc, x: T) => (ok = ok && pred(x)) ? acc : r(acc, x)); + }); } diff --git a/packages/transducers/src/xform/drop.ts b/packages/transducers/src/xform/drop.ts index f354ddb9ec..548a7da386 100644 --- a/packages/transducers/src/xform/drop.ts +++ b/packages/transducers/src/xform/drop.ts @@ -1,11 +1,16 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; -export function drop(n: number): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - let m = n; - return compR(rfn, - (acc, x) => m > 0 ? (m-- , acc) : r(acc, x)); - }; +export function drop(n: number): Transducer; +export function drop(n: number, src: Iterable): IterableIterator; +export function drop(n: number, src?: Iterable): any { + return src ? + iterator(drop(n), src) : + (rfn: Reducer) => { + const r = rfn[2]; + let m = n; + return compR(rfn, + (acc, x: T) => m > 0 ? (m-- , acc) : r(acc, x)); + }; } diff --git a/packages/transducers/src/xform/duplicate.ts b/packages/transducers/src/xform/duplicate.ts index 8e2a7009b1..6fce41e050 100644 --- a/packages/transducers/src/xform/duplicate.ts +++ b/packages/transducers/src/xform/duplicate.ts @@ -1,16 +1,21 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; import { isReduced } from "../reduced"; -export function duplicate(n = 1): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - return compR(rfn, - (acc, x) => { - for (let i = n; i >= 0 && !isReduced(acc); i--) { - acc = r(acc, x); - } - return acc; - }); - } +export function duplicate(n?: number): Transducer; +export function duplicate(n: number, src: Iterable): IterableIterator; +export function duplicate(n = 1, src?: Iterable): any { + return src ? + iterator(duplicate(n), src) : + (rfn: Reducer) => { + const r = rfn[2]; + return compR(rfn, + (acc, x: T) => { + for (let i = n; i >= 0 && !isReduced(acc); i--) { + acc = r(acc, x); + } + return acc; + }); + } } diff --git a/packages/transducers/src/xform/filter-fuzzy.ts b/packages/transducers/src/xform/filter-fuzzy.ts index f7762ceb5b..aae1ad14a8 100644 --- a/packages/transducers/src/xform/filter-fuzzy.ts +++ b/packages/transducers/src/xform/filter-fuzzy.ts @@ -1,9 +1,15 @@ import { Predicate2 } from "@thi.ng/api/api"; -import { Transducer } from "../api"; +import { Fn, Transducer } from "../api"; import { fuzzyMatch } from "../func/fuzzy-match"; +import { $iter } from "../iterator"; import { filter } from "./filter"; +export interface FilterFuzzyOpts { + key: Fn>; + equiv: Predicate2; +} + /** * Returns transducer which calls `fuzzyMatch()` for each value and * discards all non-matching values. The optional `key` fn can be used @@ -12,18 +18,24 @@ import { filter } from "./filter"; * @thi.ng/equiv by default. * * ``` - * [...iterator(filterFuzzy("ho"), ["hello", "hallo", "hey", "heyoka"])] + * [...iterator(filterFuzzy({query: "ho"}), ["hello", "hallo", "hey", "heyoka"])] * // ["hello", "hallo", "heyoka"] * ``` * - * @param query - * @param key - * @param eq + * @param opts + * @param src */ -export function filterFuzzy(query: ArrayLike, key?: (x: A) => ArrayLike, eq?: Predicate2): Transducer { +export function filterFuzzy(query: ArrayLike, opts?: Partial>): Transducer; +export function filterFuzzy(query: ArrayLike, src: Iterable): IterableIterator; +export function filterFuzzy(query: ArrayLike, opts: Partial>, src: Iterable): IterableIterator; +export function filterFuzzy(...args: any[]): any { + const iter = args.length > 1 && $iter(filterFuzzy, args); + if (iter) { + return iter; + } + const query: ArrayLike = args[0]; + const { key, equiv } = >(args[1] || {}); return filter( - key ? - (x: A) => fuzzyMatch(key(x), query, eq) : - (x: A) => fuzzyMatch(x, query, eq) + (x: A) => fuzzyMatch(key != null ? key(x) : x, query, equiv) ); } diff --git a/packages/transducers/src/xform/filter.ts b/packages/transducers/src/xform/filter.ts index 0f5b82ce60..6e154569d8 100644 --- a/packages/transducers/src/xform/filter.ts +++ b/packages/transducers/src/xform/filter.ts @@ -1,12 +1,17 @@ import { Predicate } from "@thi.ng/api"; import { Reducer, Transducer } from "../api"; +import { iterator } from "../iterator"; import { compR } from "../func/compr"; -export function filter(pred: Predicate): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - return compR(rfn, - (acc, x) => pred(x) ? r(acc, x) : acc); - } +export function filter(pred: Predicate): Transducer; +export function filter(pred: Predicate, src: Iterable): IterableIterator; +export function filter(pred: Predicate, src?: Iterable): any { + return src ? + iterator(filter(pred), src) : + (rfn: Reducer) => { + const r = rfn[2]; + return compR(rfn, + (acc, x: T) => pred(x) ? r(acc, x) : acc); + } } diff --git a/packages/transducers/src/xform/flatten-with.ts b/packages/transducers/src/xform/flatten-with.ts index ba715646b0..dbdf94df3a 100644 --- a/packages/transducers/src/xform/flatten-with.ts +++ b/packages/transducers/src/xform/flatten-with.ts @@ -1,23 +1,28 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; import { isReduced } from "../reduced"; -export function flattenWith(fn: (x: T) => Iterable): Transducer, T> { - return (rfn: Reducer) => { - const r = rfn[2]; - const flatten = (acc, x) => { - const xx = fn(x); - if (xx) { - for (let y of xx) { - acc = flatten(acc, y); - if (isReduced(acc)) { - break; +export function flattenWith(fn: (x: T) => Iterable): Transducer, T>; +export function flattenWith(fn: (x: T) => Iterable, src: Iterable>): IterableIterator; +export function flattenWith(fn: (x: T) => Iterable, src?: Iterable>): any { + return src ? + iterator(flattenWith(fn), src) : + (rfn: Reducer) => { + const reduce = rfn[2]; + const flatten = (acc, x) => { + const xx = fn(x); + if (xx) { + for (let y of xx) { + acc = flatten(acc, y); + if (isReduced(acc)) { + break; + } } + return acc; } - return acc; - } - return r(acc, x); + return reduce(acc, x); + }; + return compR(rfn, flatten); }; - return compR(rfn, flatten); - }; } diff --git a/packages/transducers/src/xform/flatten.ts b/packages/transducers/src/xform/flatten.ts index 3ca549bac8..492969fe94 100644 --- a/packages/transducers/src/xform/flatten.ts +++ b/packages/transducers/src/xform/flatten.ts @@ -1,8 +1,11 @@ import { Transducer } from "../api"; import { flattenWith } from "./flatten-with"; -export function flatten(): Transducer, T> { +export function flatten(): Transducer, T>; +export function flatten(src: Iterable>): IterableIterator; +export function flatten(src?: Iterable>): any { return flattenWith( - (x) => x != null && x[Symbol.iterator] && typeof x !== "string" ? x : undefined + (x) => x != null && x[Symbol.iterator] && typeof x !== "string" ? x : undefined, + src ); } diff --git a/packages/transducers/src/xform/hex-dump.ts b/packages/transducers/src/xform/hex-dump.ts index 5f9b3bc594..6eb23f59b1 100644 --- a/packages/transducers/src/xform/hex-dump.ts +++ b/packages/transducers/src/xform/hex-dump.ts @@ -1,15 +1,27 @@ -import { U8, U32 } from "@thi.ng/strings/radix"; +import { U32, U8 } from "@thi.ng/strings/radix"; import { Transducer } from "../api"; - import { comp } from "../func/comp"; import { juxt } from "../func/juxt"; - +import { $iter } from "../iterator"; import { map } from "./map"; import { mapIndexed } from "./map-indexed"; import { padLast } from "./pad-last"; import { partition } from "./partition"; +export interface HexDumpOpts { + /** + * Number of bytes per line. + * Default: 16 + */ + cols: number; + /** + * Start address. + * Default: 0 + */ + address: number; +} + /** * Transforms bytes into a sequence of hexdump lines with configurable * number of `columns` and `address` offset. Uses `partition()` internally, @@ -24,20 +36,28 @@ import { partition } from "./partition"; * // '00000408 | 49 4a 21 30 31 32 33 7e | IJ!0123~', * // '00000410 | 7a 79 78 00 00 00 00 00 | zyx.....' ] * ``` - * @param cols - * @param addr + * @param opts + * @param src */ -export function hexDump(cols = 16, addr = 0): Transducer { +export function hexDump(opts?: Partial): Transducer; +export function hexDump(src: Iterable): IterableIterator; +export function hexDump(opts: Partial, src: Iterable): IterableIterator; +export function hexDump(...args: any[]): any { + const iter = $iter(hexDump, args); + if (iter) { + return iter; + } + const { cols, address } = { cols: 16, address: 0, ...args[0] }; return comp( padLast(cols, 0), map(juxt(U8, (x) => x > 31 && x < 128 ? String.fromCharCode(x) : ".")), partition(cols, true), map( juxt( - (x) => x.map(y => y[0]).join(" "), - (x) => x.map(y => y[1]).join("") + (x) => x.map((y) => y[0]).join(" "), + (x) => x.map((y) => y[1]).join("") ) ), - mapIndexed((i, [h, a]) => `${U32(addr + i * cols)} | ${h} | ${a}`) + mapIndexed((i, [h, a]) => `${U32(address + i * cols)} | ${h} | ${a}`) ); } diff --git a/packages/transducers/src/xform/indexed.ts b/packages/transducers/src/xform/indexed.ts index b645f58675..773752712f 100644 --- a/packages/transducers/src/xform/indexed.ts +++ b/packages/transducers/src/xform/indexed.ts @@ -1,6 +1,15 @@ import { Transducer } from "../api"; +import { $iter } from "../iterator"; import { mapIndexed } from "./map-indexed"; -export function indexed(from = 0): Transducer { - return mapIndexed((i, x) => [from + i, x]); +export function indexed(from?: number): Transducer; +export function indexed(src: Iterable): IterableIterator<[number, T]>; +export function indexed(from: number, src: Iterable): IterableIterator<[number, T]>; +export function indexed(...args: any[]): any { + const iter = $iter(indexed, args); + if (iter) { + return iter; + } + const from: number = args[0] || 0; + return mapIndexed((i, x: T) => [from + i, x]); } diff --git a/packages/transducers/src/xform/interleave.ts b/packages/transducers/src/xform/interleave.ts index 04318049e8..526c1d2b18 100644 --- a/packages/transducers/src/xform/interleave.ts +++ b/packages/transducers/src/xform/interleave.ts @@ -1,15 +1,20 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; import { isReduced } from "../reduced"; -export function interleave(sep: B | (() => B)): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - const _sep = typeof sep === "function" ? sep : () => sep; - return compR(rfn, - (acc, x) => { - acc = r(acc, _sep()); - return isReduced(acc) ? acc : r(acc, x); - }); - }; +export function interleave(sep: B | (() => B)): Transducer; +export function interleave(sep: B | (() => B), src: Iterable): IterableIterator; +export function interleave(sep: B | (() => B), src?: Iterable): any { + return src ? + iterator(interleave(sep), src) : + (rfn: Reducer) => { + const r = rfn[2]; + const _sep = typeof sep === "function" ? sep : () => sep; + return compR(rfn, + (acc, x: A) => { + acc = r(acc, _sep()); + return isReduced(acc) ? acc : r(acc, x); + }); + }; } diff --git a/packages/transducers/src/xform/interpose.ts b/packages/transducers/src/xform/interpose.ts index b3dca6d443..daab88ac73 100644 --- a/packages/transducers/src/xform/interpose.ts +++ b/packages/transducers/src/xform/interpose.ts @@ -1,20 +1,25 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; import { isReduced } from "../reduced"; -export function interpose(sep: B | (() => B)): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - const _sep = typeof sep === "function" ? sep : () => sep; - let first = true; - return compR(rfn, - (acc, x) => { - if (first) { - first = false; - return r(acc, x); - } - acc = r(acc, _sep()); - return isReduced(acc) ? acc : r(acc, x); - }); - }; +export function interpose(sep: B | (() => B)): Transducer; +export function interpose(sep: B | (() => B), src: Iterable): IterableIterator; +export function interpose(sep: B | (() => B), src?: Iterable): any { + return src ? + iterator(interpose(sep), src) : + (rfn: Reducer) => { + const r = rfn[2]; + const _sep = typeof sep === "function" ? sep : () => sep; + let first = true; + return compR(rfn, + (acc, x: A) => { + if (first) { + first = false; + return r(acc, x); + } + acc = r(acc, _sep()); + return isReduced(acc) ? acc : r(acc, x); + }); + }; } diff --git a/packages/transducers/src/xform/keep.ts b/packages/transducers/src/xform/keep.ts index d8f271bf9a..56110331d0 100644 --- a/packages/transducers/src/xform/keep.ts +++ b/packages/transducers/src/xform/keep.ts @@ -1,11 +1,17 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; import { identity } from "../func/identity"; +import { $iter } from "../iterator"; -export function keep(f: ((x: T) => any) = identity): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - return compR(rfn, - (acc, x) => f(x) != null ? r(acc, x) : acc); - } +export function keep(pred?: (x: T) => any): Transducer; +export function keep(src: Iterable): IterableIterator; +export function keep(pred: (x: T) => any, src: Iterable): IterableIterator; +export function keep(...args: any[]): any { + return $iter(keep, args) || + ((rfn: Reducer) => { + const r = rfn[2]; + const pred: (x: T) => any = args[0] || identity; + return compR(rfn, + (acc, x: T) => pred(x) != null ? r(acc, x) : acc); + }) } diff --git a/packages/transducers/src/xform/labeled.ts b/packages/transducers/src/xform/labeled.ts index e67ee575d2..508af493d5 100644 --- a/packages/transducers/src/xform/labeled.ts +++ b/packages/transducers/src/xform/labeled.ts @@ -1,12 +1,19 @@ import { isFunction } from "@thi.ng/checks/is-function"; import { Transducer } from "../api"; +import { iterator } from "../iterator"; import { map } from "./map"; -export function labeled(id: L | ((x: T) => L)): Transducer { - return map( - isFunction(id) ? - (x) => [id(x), x] : - (x) => [id, x] - ); +export type LabelFn = L | ((x: T) => L); + +export function labeled(id: LabelFn): Transducer; +export function labeled(id: LabelFn, src: Iterable): IterableIterator<[L, T]>; +export function labeled(id: LabelFn, src?: Iterable): any { + return src ? + iterator(labeled(id), src) : + map( + isFunction(id) ? + (x: T) => [id(x), x] : + (x: T) => [id, x] + ); } diff --git a/packages/transducers/src/xform/map-deep.ts b/packages/transducers/src/xform/map-deep.ts index 0326db0338..a4dc4596bd 100644 --- a/packages/transducers/src/xform/map-deep.ts +++ b/packages/transducers/src/xform/map-deep.ts @@ -1,6 +1,6 @@ import { Transducer, TransformSpec } from "../api"; import { deepTransform } from "../func/deep-transform"; - +import { iterator } from "../iterator"; import { map } from "./map"; /** @@ -9,7 +9,12 @@ import { map } from "./map"; * See `deepTransform()` for details. * * @param spec + * @param src */ -export function mapDeep(spec: TransformSpec): Transducer { - return map(deepTransform(spec)); +export function mapDeep(spec: TransformSpec): Transducer; +export function mapDeep(spec: TransformSpec, src: Iterable): IterableIterator; +export function mapDeep(spec: TransformSpec, src?: Iterable): any { + return src ? + iterator(mapDeep(spec), src) : + map(deepTransform(spec)); } diff --git a/packages/transducers/src/xform/map-indexed.ts b/packages/transducers/src/xform/map-indexed.ts index 75cd871f28..08597fa3b2 100644 --- a/packages/transducers/src/xform/map-indexed.ts +++ b/packages/transducers/src/xform/map-indexed.ts @@ -1,5 +1,6 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { $iter } from "../iterator"; /** * Transducer. Similar to `map`, but given `fn` takes two arguments: @@ -18,11 +19,16 @@ import { compR } from "../func/compr"; * @param fn transformation function * @param offset initial index */ -export function mapIndexed(fn: (i: number, x: A) => B, offset = 0): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - let i = offset; - return compR(rfn, - (acc, x: A) => r(acc, fn(i++, x))); - }; +export function mapIndexed(fn: (i: number, x: A) => B, offset?: number): Transducer; +export function mapIndexed(fn: (i: number, x: A) => B, src: Iterable): IterableIterator; +export function mapIndexed(fn: (i: number, x: A) => B, offset: number, src: Iterable): IterableIterator; +export function mapIndexed(...args: any[]): any { + return $iter(mapIndexed, args) || + ((rfn: Reducer) => { + const r = rfn[2]; + const fn: (i: number, x: A) => B = args[0]; + let i: number = args[1] || 0; + return compR(rfn, + (acc, x: A) => r(acc, fn(i++, x))); + }); } diff --git a/packages/transducers/src/xform/map-keys.ts b/packages/transducers/src/xform/map-keys.ts index 1a43974e89..f9e4d76d19 100644 --- a/packages/transducers/src/xform/map-keys.ts +++ b/packages/transducers/src/xform/map-keys.ts @@ -1,6 +1,7 @@ import { IObjectOf } from "@thi.ng/api/api"; import { Transducer } from "../api"; +import { $iter } from "../iterator"; import { map } from "./map"; /** @@ -11,20 +12,30 @@ import { map } from "./map"; * copy of each `x`. * * ``` - * [...iterator( - * mapKeys({ + * [...mapKeys( + * { * a: (x) => x != null ? x * 10 : x, * b: (x) => x != null ? x * 100: "n/a" - * }), + * }, * [{a: 1, b: 2}, {c: 3, d: 4}] * )] * // [ { a: 10, b: 200 }, { c: 3, d: 4, b: 'n/a', a: undefined } ] * ``` * * @param keys object of transformation functions - * @param copy if true, creates a shallow copy of each incoming value + * @param copy if true (default), creates a shallow copy of each incoming value + * @param src */ -export function mapKeys(keys: IObjectOf<(x: any) => any>, copy = true): Transducer { +export function mapKeys(keys: IObjectOf<(x: any) => any>, copy?: boolean): Transducer; +export function mapKeys(keys: IObjectOf<(x: any) => any>, src: Iterable): IterableIterator; +export function mapKeys(keys: IObjectOf<(x: any) => any>, copy: boolean, src: Iterable): IterableIterator; +export function mapKeys(...args: any[]): any { + const iter = $iter(mapKeys, args); + if (iter) { + return iter; + } + const keys: IObjectOf<(x: any) => any> = args[0]; + const copy = args[1] !== false; return map((x) => { const res = copy ? Object.assign({}, x) : x; for (let k in keys) { diff --git a/packages/transducers/src/xform/map-nth.ts b/packages/transducers/src/xform/map-nth.ts index 101eb0c796..ed4515e22d 100644 --- a/packages/transducers/src/xform/map-nth.ts +++ b/packages/transducers/src/xform/map-nth.ts @@ -1,5 +1,6 @@ -import { Reducer, Transducer } from "../api"; +import { Fn, Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { $iter } from "../iterator"; /** * Transducer. Similar to `map`, but only transforms every `n`-th input @@ -8,20 +9,26 @@ import { compR } from "../func/compr"; * before the first transformation occurs (default 0). * * ``` - * [...iterator(mapNth(3, (x) => x * 10), range(1,10))] + * [...mapNth(3, (x) => x * 10, range(1,10))] * // [ 10, 2, 3, 40, 5, 6, 70, 8, 9 ] * * // with offset - * [...iterator(mapNth(3, 5, (x) => x * 10), range(1,10))] + * [...mapNth(3, 5, (x) => x * 10, range(1,10))] * // [ 1, 2, 3, 4, 5, 60, 7, 8, 90 ] * ``` * * @param n step size * @param fn transformation function */ -export function mapNth(n: number, fn: (x: A) => B): Transducer; -export function mapNth(n: number, offset: number, fn: (x: A) => B): Transducer; -export function mapNth(...args: any[]): Transducer { +export function mapNth(n: number, fn: Fn): Transducer; +export function mapNth(n: number, offset: number, fn: Fn): Transducer; +export function mapNth(n: number, fn: Fn, src: Iterable): IterableIterator; +export function mapNth(n: number, offset: number, fn: Fn, src: Iterable): IterableIterator; +export function mapNth(...args: any[]): any { + const iter = $iter(mapNth, args); + if (iter) { + return iter; + } let n = args[0] - 1, offset, fn; if (typeof args[1] === "number") { offset = args[1]; @@ -34,7 +41,7 @@ export function mapNth(...args: any[]): Transducer { const r = rfn[2]; let skip = 0, off = offset; return compR(rfn, - (acc, x) => { + (acc, x: A) => { if (off === 0) { if (skip === 0) { skip = n; diff --git a/packages/transducers/src/xform/map-vals.ts b/packages/transducers/src/xform/map-vals.ts index d7480a4d57..02cb350e3a 100644 --- a/packages/transducers/src/xform/map-vals.ts +++ b/packages/transducers/src/xform/map-vals.ts @@ -1,6 +1,7 @@ import { IObjectOf } from "@thi.ng/api/api"; -import { Transducer } from "../api"; +import { Fn, Transducer } from "../api"; +import { $iter } from "../iterator"; import { map } from "./map"; /** @@ -11,14 +12,23 @@ import { map } from "./map"; * the result of this transducer. * * ``` - * [...iterator(mapVals((x)=> x * 10), [{a: 1, b: 2}, {c: 3, d: 4}])] + * [...mapVals((x)=> x * 10, [{a: 1, b: 2}, {c: 3, d: 4}])] * // [ { a: 10, b: 20 }, { c: 30, d: 40 } ] * ``` * * @param fn - * @param copy if true, creates a shallow copy of each incoming value + * @param copy if true (default), creates a shallow copy of each incoming value */ -export function mapVals(fn: (v: A) => B, copy = true): Transducer, IObjectOf> { +export function mapVals(fn: Fn, copy?: boolean): Transducer, IObjectOf>; +export function mapVals(fn: Fn, src: Iterable>): IterableIterator>; +export function mapVals(fn: Fn, copy: boolean, src: Iterable>): IterableIterator>; +export function mapVals(...args: any[]): any { + const iter = $iter(mapVals, args); + if (iter) { + return iter; + } + const fn: Fn = args[0]; + const copy = args[1] !== false; return map((x) => { const res: any = copy ? {} : x; for (let k in x) { diff --git a/packages/transducers/src/xform/map.ts b/packages/transducers/src/xform/map.ts index 45cb5f446d..b79d37b0bc 100644 --- a/packages/transducers/src/xform/map.ts +++ b/packages/transducers/src/xform/map.ts @@ -1,5 +1,6 @@ -import { Reducer, Transducer } from "../api"; +import { Fn, Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; /** * Transducer. Applies mapping function `fn` to each received value and @@ -12,9 +13,13 @@ import { compR } from "../func/compr"; * * @param fn transformation function */ -export function map(fn: (x: A) => B): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - return compR(rfn, (acc, x: A) => r(acc, fn(x))); - }; +export function map(fn: Fn): Transducer; +export function map(fn: Fn, src: Iterable): IterableIterator +export function map(fn: Fn, src?: Iterable): any { + return src ? + iterator(map(fn), src) : + (rfn: Reducer) => { + const r = rfn[2]; + return compR(rfn, (acc, x: A) => r(acc, fn(x))); + }; } diff --git a/packages/transducers/src/xform/mapcat.ts b/packages/transducers/src/xform/mapcat.ts index b5af25690f..1f1771a95e 100644 --- a/packages/transducers/src/xform/mapcat.ts +++ b/packages/transducers/src/xform/mapcat.ts @@ -1,5 +1,6 @@ -import { Transducer } from "../api"; +import { Fn, Transducer } from "../api"; import { comp } from "../func/comp"; +import { iterator } from "../iterator"; import { cat } from "./cat"; import { map } from "./map"; @@ -11,15 +12,19 @@ import { map } from "./map"; * * @example * ``` - * [...iterator(mapcat((x) => [x, x]), [1, 2, 3])] + * [...mapcat((x) => [x, x], [1, 2, 3])] * // [ 1, 1, 2, 2, 3, 3 ] * - * [...iterator(mapcat((x) => x > 2 ? [x, x, x] : null), [1, 2, 3])] + * [...mapcat((x) => x > 2 ? [x, x, x] : null, [1, 2, 3])] * // [ 3, 3, 3 ] * ``` * * @param fn mapping function */ -export function mapcat(fn: (x: A) => Iterable): Transducer { - return comp(map(fn), cat()); +export function mapcat(fn: Fn>): Transducer; +export function mapcat(fn: Fn>, src: Iterable): IterableIterator; +export function mapcat(fn: Fn>, src?: Iterable): any { + return src ? + iterator(mapcat(fn), src) : + comp(map(fn), cat()); } diff --git a/packages/transducers/src/xform/match-first.ts b/packages/transducers/src/xform/match-first.ts index 021d8543c6..512814496f 100644 --- a/packages/transducers/src/xform/match-first.ts +++ b/packages/transducers/src/xform/match-first.ts @@ -2,6 +2,7 @@ import { Predicate } from "@thi.ng/api"; import { Transducer } from "../api"; import { comp } from "../func/comp"; +import { iterator } from "../iterator"; import { filter } from "./filter"; import { take } from "./take"; @@ -17,6 +18,10 @@ import { take } from "./take"; * * @param pred predicate function */ -export function matchFirst(pred: Predicate): Transducer { - return comp(filter(pred), take(1)); +export function matchFirst(pred: Predicate): Transducer; +export function matchFirst(pred: Predicate, src: Iterable): IterableIterator; +export function matchFirst(pred: Predicate, src?: Iterable): any { + return src ? + iterator(matchFirst(pred), src) : + comp(filter(pred), take(1)); } diff --git a/packages/transducers/src/xform/match-last.ts b/packages/transducers/src/xform/match-last.ts index 274fdfaa34..07e8723e3e 100644 --- a/packages/transducers/src/xform/match-last.ts +++ b/packages/transducers/src/xform/match-last.ts @@ -2,6 +2,7 @@ import { Predicate } from "@thi.ng/api"; import { Transducer } from "../api"; import { comp } from "../func/comp"; +import { iterator } from "../iterator"; import { filter } from "./filter"; import { takeLast } from "./take-last"; @@ -15,7 +16,12 @@ import { takeLast } from "./take-last"; * Yields none or only the last value which passed the predicate check. * * @param pred predicate function + * @param src */ -export function matchLast(pred: Predicate): Transducer { - return comp(filter(pred), takeLast(1)); +export function matchLast(pred: Predicate): Transducer; +export function matchLast(pred: Predicate, src: Iterable): IterableIterator; +export function matchLast(pred: Predicate, src?: Iterable): any { + return src ? + iterator(matchLast(pred), src) : + comp(filter(pred), takeLast(1)); } diff --git a/packages/transducers/src/xform/moving-average.ts b/packages/transducers/src/xform/moving-average.ts index 0ad62f4459..ad4feb991a 100644 --- a/packages/transducers/src/xform/moving-average.ts +++ b/packages/transducers/src/xform/moving-average.ts @@ -2,6 +2,7 @@ import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; /** * Computes the Simple Moving Average of given period. @@ -15,22 +16,27 @@ import { compR } from "../func/compr"; * alternative MAs. * * @param period + * @param src */ -export function movingAverage(period: number): Transducer { - period |= 0; - period < 2 && illegalArgs("period must be >= 2"); - return (rfn: Reducer) => { - const reduce = rfn[2]; - const window = []; - let sum = 0; - return compR( - rfn, - (acc, x) => { - const n = window.push(x); - sum += x; - n > period && (sum -= window.shift()); - return n >= period ? reduce(acc, sum / period) : acc; - } - ); - } +export function movingAverage(period: number): Transducer; +export function movingAverage(period: number, src: Iterable): IterableIterator; +export function movingAverage(period: number, src?: Iterable): any { + return src ? + iterator(movingAverage(period), src) : + (rfn: Reducer) => { + period |= 0; + period < 2 && illegalArgs("period must be >= 2"); + const reduce = rfn[2]; + const window = []; + let sum = 0; + return compR( + rfn, + (acc, x: number) => { + const n = window.push(x); + sum += x; + n > period && (sum -= window.shift()); + return n >= period ? reduce(acc, sum / period) : acc; + } + ); + }; }; diff --git a/packages/transducers/src/xform/moving-median.ts b/packages/transducers/src/xform/moving-median.ts index 78ec7cebdc..f521efbf3f 100644 --- a/packages/transducers/src/xform/moving-median.ts +++ b/packages/transducers/src/xform/moving-median.ts @@ -1,12 +1,18 @@ import { Comparator } from "@thi.ng/api/api"; -import { compare } from "@thi.ng/compare"; +import { compare as cmp } from "@thi.ng/compare"; -import { Transducer } from "../api"; +import { Fn, Transducer } from "../api"; import { comp } from "../func/comp"; import { identity } from "../func/identity"; +import { $iter } from "../iterator"; import { map } from "./map"; import { partition } from "./partition"; +export interface MovingMedianOpts { + key: Fn; + compare: Comparator; +} + /** * Transducer. Similar to `movingAverage()`, but yields median of * sliding window and supports non-numeric inputs. The optional `key` @@ -14,10 +20,26 @@ import { partition } from "./partition"; * value and change sorting behavior. * * @param n window size - * @param key sort key lookup - * @param cmp comparator + * @param opts + * @param src */ -export function movingMedian(n: number, key: ((x: A) => B) = identity, cmp: Comparator = compare): Transducer { +export function movingMedian(n: number, opts?: Partial>): Transducer; +export function movingMedian(n: number, src: Iterable): IterableIterator; +export function movingMedian(n: number, opts: Partial>, src: Iterable): IterableIterator; +export function movingMedian(...args: any[]): any { + const iter = $iter(movingMedian, args); + if (iter) { + return iter; + } + const { key, compare } = >{ + key: identity, + compare: cmp, + ...args[1] + }; + const n = args[0]; const m = n >> 1; - return comp(partition(n, 1, true), map((window) => [...window].sort((a, b) => cmp(key(a), key(b)))[m])); + return comp( + partition(n, 1, true), + map((window: A[]) => window.slice().sort((a, b) => compare(key(a), key(b)))[m]) + ); } diff --git a/packages/transducers/src/xform/multiplex-obj.ts b/packages/transducers/src/xform/multiplex-obj.ts index 4a0af1a9e8..d0b9680df8 100644 --- a/packages/transducers/src/xform/multiplex-obj.ts +++ b/packages/transducers/src/xform/multiplex-obj.ts @@ -2,6 +2,7 @@ import { IObjectOf } from "@thi.ng/api/api"; import { Reducer, Transducer } from "../api"; import { comp } from "../func/comp"; +import { $iter } from "../iterator"; import { multiplex } from "./multiplex"; import { rename } from "./rename"; @@ -10,12 +11,12 @@ import { rename } from "./rename"; * object of transducers and produces a result object for each input. * * ``` - * [...iterator( - * multiplexObj({ + * [...multiplexObj( + * { * initial: map(x => x.charAt(0)), * upper: map(x => x.toUpperCase()), * length: map(x => x.length) - * }), + * }, * ["Alice", "Bob", "Charlie", "Andy"] * )] * // [ { length: 5, upper: 'ALICE', initial: 'A' }, @@ -26,8 +27,17 @@ import { rename } from "./rename"; * * @param xforms object of transducers * @param rfn + * @param src */ -export function multiplexObj(xforms: IObjectOf>, rfn?: Reducer): Transducer { +export function multiplexObj(xforms: IObjectOf>, rfn?: Reducer): Transducer; +export function multiplexObj(xforms: IObjectOf>, src: Iterable): IterableIterator; +export function multiplexObj(xforms: IObjectOf>, rfn: Reducer, src: Iterable): IterableIterator; +export function multiplexObj(...args: any[]): any { + const iter = $iter(multiplexObj, args); + if (iter) { + return iter; + } + const [xforms, rfn] = args; const ks = Object.keys(xforms); return comp( multiplex.apply(null, ks.map((k) => xforms[k])), diff --git a/packages/transducers/src/xform/pad-last.ts b/packages/transducers/src/xform/pad-last.ts index 205ccccfb5..db6f4a6405 100644 --- a/packages/transducers/src/xform/pad-last.ts +++ b/packages/transducers/src/xform/pad-last.ts @@ -1,4 +1,5 @@ import { Reducer, Transducer } from "../api"; +import { iterator } from "../iterator"; import { isReduced } from "../reduced"; /** @@ -29,21 +30,25 @@ import { isReduced } from "../reduced"; * @param n * @param fill */ -export function padLast(n: number, fill: T): Transducer { - return ([init, complete, reduce]: Reducer) => { - let m = 0; - return [ - init, - (acc) => { - let rem = m % n; - if (rem > 0) { - while (++rem <= n && !isReduced(acc)) { - acc = reduce(acc, fill); +export function padLast(n: number, fill: T): Transducer; +export function padLast(n: number, fill: T, src: Iterable): IterableIterator; +export function padLast(n: number, fill: T, src?: Iterable): any { + return src ? + iterator(padLast(n, fill), src) : + ([init, complete, reduce]: Reducer) => { + let m = 0; + return [ + init, + (acc) => { + let rem = m % n; + if (rem > 0) { + while (++rem <= n && !isReduced(acc)) { + acc = reduce(acc, fill); + } } - } - return complete(acc); - }, - (acc, x) => (m++ , reduce(acc, x)) - ]; - }; + return complete(acc); + }, + (acc, x) => (m++ , reduce(acc, x)) + ]; + }; } diff --git a/packages/transducers/src/xform/page.ts b/packages/transducers/src/xform/page.ts index 6c52eba193..c24e8d2d4a 100644 --- a/packages/transducers/src/xform/page.ts +++ b/packages/transducers/src/xform/page.ts @@ -1,5 +1,6 @@ import { Transducer } from "../api"; import { comp } from "../func/comp"; +import { $iter } from "../iterator"; import { drop } from "./drop"; import { take } from "./take"; @@ -11,22 +12,26 @@ import { take } from "./take"; * any heavy processing steps. * * ``` - * [...iterator(page(0, 5), range(12))] + * [...page(0, 5, range(12))] * // [ 0, 1, 2, 3, 4 ] * - * [...iterator(page(1, 5), range(12))] + * [...page(1, 5, range(12))] * // [ 5, 6, 7, 8, 9 ] * - * [...iterator(page(2, 5), range(12))] + * [...page(2, 5, range(12))] * // [ 10, 11 ] * - * [...iterator(page(3, 5), range(12))] + * [...page(3, 5, range(12))] * // [] * ``` * * @param page * @param pageLen */ -export function page(page: number, pageLen = 10): Transducer { - return comp(drop(page * pageLen), take(pageLen)); +export function page(page: number, pageLen?: number): Transducer; +export function page(page: number, src: Iterable): IterableIterator; +export function page(page: number, pageLen: number, src: Iterable): IterableIterator; +export function page(...args: any[]): any { + return $iter(page, args) || + comp(drop(args[0] * (args[1] || 10)), take(args[1] || 10)); } diff --git a/packages/transducers/src/xform/partition-bits.ts b/packages/transducers/src/xform/partition-bits.ts index bc33d25408..ad651a61e8 100644 --- a/packages/transducers/src/xform/partition-bits.ts +++ b/packages/transducers/src/xform/partition-bits.ts @@ -1,56 +1,76 @@ -import { Transducer } from "../api"; +import { Reducer, Transducer } from "../api"; +import { $iter } from "../iterator"; import { isReduced } from "../reduced"; /** * Transducer. * - * @param fn - * @param stateful + * @param destSize target word size (bits) + * @param srcSize source word size (bits) */ -export function partitionBits(n: number, wordSize = 8): Transducer { - return ([init, complete, reduce]) => { - const maxb = wordSize - n; - const m1 = (1 << wordSize) - 1; - const m2 = (1 << n) - 1; - let r = 0; - let y = 0; - return [ - init, - (acc) => complete(r > 0 ? reduce(acc, y) : acc), - n < wordSize ? - (acc, x) => { - let b = 0; - do { - acc = reduce(acc, y + ((x >>> (maxb + r)) & m2)); - b += n - r; - x = (x << (n - r)) & m1; - y = 0; - r = 0; - } while (b <= maxb && !isReduced(acc)); - r = wordSize - b; - y = r > 0 ? (x >>> maxb) & m2 : 0; - return acc; - } : - n > wordSize ? - (acc, x) => { - if (r + wordSize <= n) { - y |= (x & m1) << (n - wordSize - r); - r += wordSize; - if (r === n) { - acc = reduce(acc, y); - y = 0; - r = 0; - } - } - else { - const k = n - r; - r = wordSize - k; - acc = reduce(acc, y | ((x >>> r) & ((1 << k) - 1))); - y = (x & ((1 << r) - 1)) << (n - r); - } - return acc; - } : - reduce - ]; - }; +export function partitionBits(destSize: number, srcSize?: number): Transducer; +export function partitionBits(destSize: number, src: Iterable): IterableIterator; +export function partitionBits(destSize: number, srcSize: number, src: Iterable): IterableIterator; +export function partitionBits(...args: any[]): any { + return $iter(partitionBits, args) || + ((rfn: Reducer) => { + const destSize = args[0]; + const srcSize = args[1] || 8; + return destSize < srcSize ? + small(rfn, destSize, srcSize) : + destSize > srcSize ? + large(rfn, destSize, srcSize) : + rfn; + }); } + +const small = ([init, complete, reduce]: Reducer, n: number, wordSize: number): Reducer => { + const maxb = wordSize - n; + const m1 = (1 << wordSize) - 1; + const m2 = (1 << n) - 1; + let r = 0; + let y = 0; + return [ + init, + (acc) => complete(r > 0 ? reduce(acc, y) : acc), + (acc, x) => { + let b = 0; + do { + acc = reduce(acc, y + ((x >>> (maxb + r)) & m2)); + b += n - r; + x = (x << (n - r)) & m1; + y = 0; + r = 0; + } while (b <= maxb && !isReduced(acc)); + r = wordSize - b; + y = r > 0 ? (x >>> maxb) & m2 : 0; + return acc; + }]; +}; + +const large = ([init, complete, reduce]: Reducer, n: number, wordSize: number): Reducer => { + const m1 = (1 << wordSize) - 1; + let r = 0; + let y = 0; + return [ + init, + (acc) => complete(r > 0 ? reduce(acc, y) : acc), + (acc, x) => { + if (r + wordSize <= n) { + y |= (x & m1) << (n - wordSize - r); + r += wordSize; + if (r === n) { + acc = reduce(acc, y); + y = 0; + r = 0; + } + } + else { + const k = n - r; + r = wordSize - k; + acc = reduce(acc, y | ((x >>> r) & ((1 << k) - 1))); + y = (x & ((1 << r) - 1)) << (n - r); + } + return acc; + }]; +}; \ No newline at end of file diff --git a/packages/transducers/src/xform/partition-by.ts b/packages/transducers/src/xform/partition-by.ts index b4a3d90020..05919ef0ac 100644 --- a/packages/transducers/src/xform/partition-by.ts +++ b/packages/transducers/src/xform/partition-by.ts @@ -1,4 +1,5 @@ -import { SEMAPHORE, Transducer } from "../api"; +import { Fn, SEMAPHORE, Transducer } from "../api"; +import { $iter } from "../iterator"; import { isReduced } from "../reduced"; /** @@ -14,33 +15,38 @@ import { isReduced } from "../reduced"; * @param fn * @param stateful */ -export function partitionBy(fn: (x?: T) => any, stateful = false): Transducer { - return ([init, complete, reduce]) => { - const f = stateful ? fn() : fn; - let prev: any = SEMAPHORE, - chunk; - return [ - init, - (acc) => { - if (chunk && chunk.length) { - acc = reduce(acc, chunk); - chunk = null; - } - return complete(acc); - }, - (acc, x) => { - const curr = f(x); - if (prev === SEMAPHORE) { - prev = curr; - chunk = [x]; - } else if (curr === prev) { - chunk.push(x); - } else { - chunk && (acc = reduce(acc, chunk)); - chunk = isReduced(acc) ? null : [x]; - prev = curr; - } - return acc; - }]; - }; +export function partitionBy(fn: Fn | (() => Fn), stateful?: boolean): Transducer; +export function partitionBy(fn: Fn | (() => Fn), src: Iterable): IterableIterator; +export function partitionBy(fn: Fn | (() => Fn), stateful: boolean, src: Iterable): IterableIterator; +export function partitionBy(...args: any[]): any { + return $iter(partitionBy, args) || + (([init, complete, reduce]) => { + const fn: Fn | (() => Fn) = args[0]; + const f = args[1] === true ? (<() => Fn>fn)() : fn; + let prev: any = SEMAPHORE, + chunk; + return [ + init, + (acc) => { + if (chunk && chunk.length) { + acc = reduce(acc, chunk); + chunk = null; + } + return complete(acc); + }, + (acc, x) => { + const curr = f(x); + if (prev === SEMAPHORE) { + prev = curr; + chunk = [x]; + } else if (curr === prev) { + chunk.push(x); + } else { + chunk && (acc = reduce(acc, chunk)); + chunk = isReduced(acc) ? null : [x]; + prev = curr; + } + return acc; + }]; + }); } diff --git a/packages/transducers/src/xform/partition-of.ts b/packages/transducers/src/xform/partition-of.ts index b24f887f36..c514863af5 100644 --- a/packages/transducers/src/xform/partition-of.ts +++ b/packages/transducers/src/xform/partition-of.ts @@ -1,4 +1,5 @@ import { Transducer } from "../api"; +import { iterator } from "../iterator"; import { partitionBy } from "./partition-by"; /** @@ -6,7 +7,7 @@ import { partitionBy } from "./partition-by"; * chunks. The last partition emitted is allowed to be incomplete. * * ``` - * [...iterator(partitionOf([3,2,4]), range(20))] + * [...partitionOf([3,2,4], range(20))] * // [ [ 0, 1, 2 ], * // [ 3, 4 ], * // [ 5, 6, 7, 8 ], @@ -18,16 +19,20 @@ import { partitionBy } from "./partition-by"; * * @param sizes */ -export function partitionOf(sizes: number[]): Transducer { - return partitionBy( - () => { - let i = 0, j = 0; - return () => { - if (i++ === sizes[j]) { - i = 1; - j = (j + 1) % sizes.length; - } - return j; - }; - }, true); +export function partitionOf(sizes: number[]): Transducer; +export function partitionOf(sizes: number[], src: Iterable): IterableIterator; +export function partitionOf(sizes: number[], src?: Iterable): any { + return src ? + iterator(partitionOf(sizes), src) : + partitionBy( + () => { + let i = 0, j = 0; + return () => { + if (i++ === sizes[j]) { + i = 1; + j = (j + 1) % sizes.length; + } + return j; + }; + }, true); } diff --git a/packages/transducers/src/xform/partition-sort.ts b/packages/transducers/src/xform/partition-sort.ts index e9a570c8cc..a1bdc72ef3 100644 --- a/packages/transducers/src/xform/partition-sort.ts +++ b/packages/transducers/src/xform/partition-sort.ts @@ -1,12 +1,18 @@ import { Comparator } from "@thi.ng/api/api"; -import { compare } from "@thi.ng/compare"; +import { compare as cmp } from "@thi.ng/compare"; -import { Transducer } from "../api"; +import { Fn, Transducer } from "../api"; import { comp } from "../func/comp"; import { identity } from "../func/identity"; +import { $iter } from "../iterator"; import { mapcat } from "./mapcat"; import { partition } from "./partition"; +export interface PartitionSortOpts { + key: Fn; + compare: Comparator; +} + /** * Transducer. Composition of `partition` and `mapcat` which yields a * **partially** sorted sequence of input values. Sorting is performed on @@ -15,12 +21,11 @@ import { partition } from "./partition"; * value and change sorting behavior. * * ``` - * [...iterator(partitionSort(4), [5,9,2,6,4,1,3,8,7,0])] + * [...partitionSort(4, [5,9,2,6,4,1,3,8,7,0])] * // [ 2, 5, 6, 9, 1, 3, 4, 8, 0, 7 ] * * // with key fn and custom comparator - * [...iterator( - * partitionSort(3, (x) => x.val, (a, b) => b - a), + * [...partitionSort(3, (x) => x.val, (a, b) => b - a, * [ * { id: "a", val: 5 }, * { id: "b", val: 7 }, @@ -34,9 +39,21 @@ import { partition } from "./partition"; * @param key sort key lookup * @param cmp comparator */ -export function partitionSort(n: number, key: ((x: A) => B) = identity, cmp: Comparator = compare): Transducer { +export function partitionSort(n: number, opts?: Partial>): Transducer; +export function partitionSort(n: number, src: Iterable): IterableIterator; +export function partitionSort(n: number, opts: Partial>, src: Iterable): IterableIterator; +export function partitionSort(...args: any[]): any { + const iter = $iter(partitionSort, args); + if (iter) { + return iter; + } + const { key, compare } = >{ + key: identity, + compare: cmp, + ...args[1] + }; return comp( - partition(n, true), - mapcat((chunk: A[]) => chunk.sort((a, b) => cmp(key(a), key(b)))) + partition(args[0], true), + mapcat((window: A[]) => window.slice().sort((a, b) => compare(key(a), key(b)))) ); } diff --git a/packages/transducers/src/xform/partition-sync.ts b/packages/transducers/src/xform/partition-sync.ts index 14656ffa8f..dd1eecc29b 100644 --- a/packages/transducers/src/xform/partition-sync.ts +++ b/packages/transducers/src/xform/partition-sync.ts @@ -2,6 +2,14 @@ import { IObjectOf } from "@thi.ng/api/api"; import { isArray } from "@thi.ng/checks/is-array"; import { Reducer, Transducer } from "../api"; +import { identity } from "../func/identity"; +import { $iter } from "../iterator"; + +export interface PartitionSyncOpts { + key: (x: T) => PropertyKey; + reset: boolean; + all: boolean; +} /** * This transducer is intended for synchronization and provenance @@ -21,9 +29,10 @@ import { Reducer, Transducer } from "../api"; * ["a", 1], ["a", 2], ["d", 100], ["b", 10], * ["b", 11], ["c", 0], ["a", 3] * ]; + * * // form tuples for values only from sources "a" & "b" * // here the label is the first element of each input item - * [...iterator(partitionSync(["a", "b"], (x) => x[0]), src)] + * [...partitionSync(["a", "b"], { key: (x) => x[0] }, src)] * // [ { a: ["a", 2], b: ["b", 10] }, * // { b: ["b", 11], a: ["a", 3] } ] * ``` @@ -37,7 +46,14 @@ import { Reducer, Transducer } from "../api"; * * ``` * // passing `false` to disable tuple reset - * [...iterator(partitionSync(["a", "b"], (x) => x[0], false), src)] + * [...partitionSync( + * ["a", "b"], + * { + * key: (x) => x[0], + * reset: false + * }, + * src + * )] * // [ { a: ["a", 2], b: ["b", 10] }, * // { a: ["a", 2], b: ["b", 11] }, * // { a: ["a", 3], b: ["b", 11] } ] @@ -55,40 +71,50 @@ import { Reducer, Transducer } from "../api"; * @param reset true if each tuple should contain only new values * @param all true if last tuple is allowed to be incomplete */ -export function partitionSync(keys: PropertyKey[] | Set, keyfn: (x: T) => PropertyKey, reset = true, all = true): Transducer> { - return ([init, complete, reduce]: Reducer>) => { - let curr = {}; - let first = true; - const currKeys = new Set(); - const ks = isArray(keys) ? new Set(keys) : keys; - return [ - init, - (acc) => { - if ((reset && all && currKeys.size > 0) || (!reset && first)) { - acc = reduce(acc, curr); - curr = undefined; - currKeys.clear(); - first = false; - } - return complete(acc); - }, - (acc, x: T) => { - const k = keyfn(x); - if (ks.has(k)) { - curr[k] = x; - currKeys.add(k); - if (currKeys.size >= ks.size) { +export function partitionSync(keys: PropertyKey[] | Set, opts?: Partial>): Transducer>; +export function partitionSync(keys: PropertyKey[] | Set, src: Iterable): IterableIterator>; +export function partitionSync(keys: PropertyKey[] | Set, opts: Partial>, src: Iterable): IterableIterator>; +export function partitionSync(...args: any[]): any { + return $iter(partitionSync, args) || + (([init, complete, reduce]: Reducer>) => { + let curr = {}; + let first = true; + const currKeys = new Set(); + const { key, reset, all } = >{ + key: identity, + reset: true, + all: true, + ...args[1] + }; + const ks = isArray(args[0]) ? new Set(args[0]) : args[0]; + return [ + init, + (acc) => { + if ((reset && all && currKeys.size > 0) || (!reset && first)) { acc = reduce(acc, curr); + curr = undefined; + currKeys.clear(); first = false; - if (reset) { - curr = {}; - currKeys.clear(); - } else { - curr = { ...curr }; + } + return complete(acc); + }, + (acc, x: T) => { + const k = key(x); + if (ks.has(k)) { + curr[k] = x; + currKeys.add(k); + if (currKeys.size >= ks.size) { + acc = reduce(acc, curr); + first = false; + if (reset) { + curr = {}; + currKeys.clear(); + } else { + curr = { ...curr }; + } } } - } - return acc; - }]; - }; + return acc; + }]; + }); } \ No newline at end of file diff --git a/packages/transducers/src/xform/partition.ts b/packages/transducers/src/xform/partition.ts index 33e7e3d4b0..6189ef6c6e 100644 --- a/packages/transducers/src/xform/partition.ts +++ b/packages/transducers/src/xform/partition.ts @@ -1,4 +1,5 @@ import { Reducer, Transducer } from "../api"; +import { $iter } from "../iterator"; /** * Transducer to create overlapping and non-overlapping sliding windows @@ -8,13 +9,13 @@ import { Reducer, Transducer } from "../api"; * be incomplete / partially filled only. * * ``` - * [...iterator(partition(3), range(10))] + * [...partition(3, range(10))] * // [ [ 0, 1, 2 ], [ 3, 4, 5 ], [ 6, 7, 8 ] ] * - * [...iterator(partition(3, true), range(10))] + * [...partition(3, true, range(10))] * // [ [ 0, 1, 2 ], [ 3, 4, 5 ], [ 6, 7, 8 ], [ 9 ] ] * - * [...iterator(partition(3, 1), range(10))] + * [...partition(3, 1, range(10))] * // [ [ 0, 1, 2 ], * // [ 1, 2, 3 ], * // [ 2, 3, 4 ], @@ -29,9 +30,17 @@ import { Reducer, Transducer } from "../api"; */ export function partition(size: number): Transducer; export function partition(size: number, all: boolean): Transducer; -export function partition(size: number, step: number): Transducer -export function partition(size: number, step: number, all: boolean): Transducer -export function partition(...args: any[]): Transducer { +export function partition(size: number, step: number): Transducer; +export function partition(size: number, step: number, all: boolean): Transducer; +export function partition(size: number, src: Iterable): IterableIterator; +export function partition(size: number, all: boolean, src: Iterable): IterableIterator; +export function partition(size: number, step: number, src: Iterable): IterableIterator; +export function partition(size: number, step: number, all: boolean, src: Iterable): IterableIterator; +export function partition(...args: any[]): any { + const iter = $iter(partition, args); + if (iter) { + return iter; + } let size = args[0], all, step; if (typeof args[1] == "number") { step = args[1]; diff --git a/packages/transducers/src/xform/pluck.ts b/packages/transducers/src/xform/pluck.ts index a72131da4e..12abdc1cf8 100644 --- a/packages/transducers/src/xform/pluck.ts +++ b/packages/transducers/src/xform/pluck.ts @@ -1,4 +1,5 @@ import { Transducer } from "../api"; +import { iterator } from "../iterator"; import { map } from "./map"; /** @@ -12,6 +13,10 @@ import { map } from "./map"; * * @param key property key */ -export function pluck(key: PropertyKey): Transducer { - return map((x: A) => x[key]); +export function pluck(key: PropertyKey): Transducer; +export function pluck(key: PropertyKey, src: Iterable): IterableIterator; +export function pluck(key: PropertyKey, src?: Iterable): any { + return src ? + iterator(pluck(key), src) : + map((x: A) => x[key]); } diff --git a/packages/transducers/src/xform/rename.ts b/packages/transducers/src/xform/rename.ts index 35587d8c57..c5adfbb8ab 100644 --- a/packages/transducers/src/xform/rename.ts +++ b/packages/transducers/src/xform/rename.ts @@ -4,15 +4,24 @@ import { isArray } from "@thi.ng/checks/is-array"; import { Reducer, Transducer } from "../api"; import { comp } from "../func/comp"; import { renamer } from "../func/renamer"; +import { $iter } from "../iterator"; import { transduce } from "../transduce"; import { filter } from "./filter"; import { map } from "./map"; -export function rename(kmap: IObjectOf | Array, rfn?: Reducer): Transducer { - if (isArray(kmap)) { - kmap = kmap.reduce((acc, k, i) => (acc[k] = i, acc), {}); +export function rename(kmap: IObjectOf | Array, rfn?: Reducer): Transducer; +export function rename(kmap: IObjectOf | Array, src: Iterable): IterableIterator; +export function rename(kmap: IObjectOf | Array, rfn: Reducer, src: Iterable): IterableIterator; +export function rename(...args: any[]): any { + const iter = $iter(rename, args); + if (iter) { + return iter; } - if (rfn) { + let kmap; + if (isArray(args[0])) { + kmap = args[0].reduce((acc, k, i) => (acc[k] = i, acc), {}); + } + if (args[1]) { const ks = Object.keys(kmap); return map( (y) => transduce( @@ -20,7 +29,7 @@ export function rename(kmap: IObjectOf | Array, map((k: PropertyKey) => [k, y[kmap[k]]]), filter(x => x[1] !== undefined) ), - rfn, ks + args[1], ks ) ); } else { diff --git a/packages/transducers/src/xform/sample.ts b/packages/transducers/src/xform/sample.ts index beb21cf3ed..afa64109f8 100644 --- a/packages/transducers/src/xform/sample.ts +++ b/packages/transducers/src/xform/sample.ts @@ -1,5 +1,6 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; /** * Transducer which only yields values with given `prob` probability @@ -12,11 +13,16 @@ import { compR } from "../func/compr"; * ``` * * @param prob + * @param src */ -export function sample(prob: number): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - return compR(rfn, - (acc, x) => Math.random() < prob ? r(acc, x) : acc); - } +export function sample(prob: number): Transducer; +export function sample(prob: number, src: Iterable): IterableIterator; +export function sample(prob: number, src?: Iterable): any { + return src ? + iterator(sample(prob), src) : + (rfn: Reducer) => { + const r = rfn[2]; + return compR(rfn, + (acc, x: T) => Math.random() < prob ? r(acc, x) : acc); + } } diff --git a/packages/transducers/src/xform/scan.ts b/packages/transducers/src/xform/scan.ts index 1d015728f1..8f9d5bcd80 100644 --- a/packages/transducers/src/xform/scan.ts +++ b/packages/transducers/src/xform/scan.ts @@ -1,38 +1,51 @@ import { Reducer, Transducer } from "../api"; +import { $iter } from "../iterator"; import { ensureReduced, isReduced, unreduced } from "../reduced"; /** - * Transducer which performs "scan" operation via given reducer. + * Transducer which performs "scan" operation via given reducer. Note: + * If an input `src` is given an initial result `init` must be provided + * too as arg. Use `null` or `undefined` to use the given reducer's + * default. * * https://en.wikipedia.org/wiki/Prefix_sum#Scan_higher_order_function * * ``` * [...iterator(scan(add()), range(10))] * // [ 0, 1, 3, 6, 10, 15, 21, 28, 36, 45 ] + * + * [...scan(add(), null, range(10))] + * // [ 0, 1, 3, 6, 10, 15, 21, 28, 36, 45 ] * ``` * * @param rfn reducer used as scan operator + * @param init + * @param src */ -export function scan([initi, completei, reducei]: Reducer): Transducer { - return ([inito, completeo, reduceo]: Reducer) => { - let acc = initi(); - return [ - inito, - (_acc) => { - let a = completei(acc); - if (a !== acc) { - _acc = unreduced(reduceo(_acc, a)); - } - acc = a; - return completeo(_acc); - }, - (_acc, x) => { - acc = reducei(acc, x); - if (isReduced(acc)) { - return ensureReduced(reduceo(_acc, (acc).deref())); +export function scan(rfn: Reducer, init?: B): Transducer; +export function scan(rfn: Reducer, init: B, src: Iterable): IterableIterator; +export function scan(...args: any[]): any { + return (args.length > 2 && $iter(scan, args)) || + (([inito, completeo, reduceo]: Reducer) => { + const [initi, completei, reducei]: Reducer = args[0]; + let acc: B = args.length > 1 && args[1] != null ? args[1] : initi(); + return [ + inito, + (_acc) => { + let a = completei(acc); + if (a !== acc) { + _acc = unreduced(reduceo(_acc, a)); + } + acc = a; + return completeo(_acc); + }, + (_acc, x: A) => { + acc = reducei(acc, x); + if (isReduced(acc)) { + return ensureReduced(reduceo(_acc, (acc).deref())); + } + return reduceo(_acc, acc); } - return reduceo(_acc, acc); - } - ]; - }; + ]; + }); } diff --git a/packages/transducers/src/xform/select-keys.ts b/packages/transducers/src/xform/select-keys.ts index 91ce852432..b5dfcb54f4 100644 --- a/packages/transducers/src/xform/select-keys.ts +++ b/packages/transducers/src/xform/select-keys.ts @@ -1,6 +1,6 @@ import { Transducer } from "../api"; import { keySelector } from "../func/key-selector"; - +import { iterator } from "../iterator"; import { map } from "./map"; /** @@ -11,8 +11,8 @@ import { map } from "./map"; * Note: For single key extraction `pluck()` is a faster alternative. * * ``` - * [...iterator( - * selectKeys(["id", "age"]), + * [...selectKeys( + * ["id", "age"], * [ * {id: 1, age: 23, name: "alice"}, * {id: 2, age: 42, name: "bob"}, @@ -23,7 +23,12 @@ import { map } from "./map"; * ``` * * @param keys + * @param src */ -export function selectKeys(keys: PropertyKey[]): Transducer { - return map(keySelector(keys)); +export function selectKeys(keys: PropertyKey[]): Transducer; +export function selectKeys(keys: PropertyKey[], src: Iterable): IterableIterator; +export function selectKeys(keys: PropertyKey[], src?: Iterable): any { + return src ? + iterator(selectKeys(keys), src) : + map(keySelector(keys)); } diff --git a/packages/transducers/src/xform/stream-shuffle.ts b/packages/transducers/src/xform/stream-shuffle.ts index 8d40a0b84b..d6902a8e61 100644 --- a/packages/transducers/src/xform/stream-shuffle.ts +++ b/packages/transducers/src/xform/stream-shuffle.ts @@ -1,5 +1,6 @@ import { Reducer, Transducer } from "../api"; import { shuffleN } from "../func/shuffle"; +import { $iter } from "../iterator"; import { isReduced } from "../reduced"; /** @@ -9,34 +10,40 @@ import { isReduced } from "../reduced"; * the chosen chunk size. * * ``` - * [...iterator(streamShuffle(5), range(10))] + * [...streamShuffle(5, range(10))] * // [ 3, 2, 5, 0, 8, 7, 1, 6, 4, 9 ] * ``` * * @param n sliding window size * @param maxSwaps number of swaps per input */ -export function streamShuffle(n: number, maxSwaps = n): Transducer { - return ([init, complete, reduce]: Reducer) => { - const buf: T[] = []; - return [ - init, - (acc) => { - while (buf.length && !isReduced(acc)) { +export function streamShuffle(n: number, maxSwaps?: number): Transducer; +export function streamShuffle(n: number, src: Iterable): IterableIterator; +export function streamShuffle(n: number, maxSwaps: number, src: Iterable): IterableIterator; +export function streamShuffle(...args: any[]): any { + return $iter(streamShuffle, args) || + (([init, complete, reduce]: Reducer) => { + const n: number = args[0]; + const maxSwaps: number = args[1] || n; + const buf: T[] = []; + return [ + init, + (acc) => { + while (buf.length && !isReduced(acc)) { + shuffleN(buf, maxSwaps); + acc = reduce(acc, buf.shift()); + } + acc = complete(acc); + return acc; + }, + (acc, x: T) => { + buf.push(x); shuffleN(buf, maxSwaps); - acc = reduce(acc, buf.shift()); + if (buf.length === n) { + acc = reduce(acc, buf.shift()); + } + return acc; } - acc = complete(acc); - return acc; - }, - (acc, x) => { - buf.push(x); - shuffleN(buf, maxSwaps); - if (buf.length === n) { - acc = reduce(acc, buf.shift()); - } - return acc; - } - ]; - }; + ]; + }); } diff --git a/packages/transducers/src/xform/stream-sort.ts b/packages/transducers/src/xform/stream-sort.ts index fab0d5cda5..423221de63 100644 --- a/packages/transducers/src/xform/stream-sort.ts +++ b/packages/transducers/src/xform/stream-sort.ts @@ -1,18 +1,24 @@ import { Comparator } from "@thi.ng/api/api"; -import { compare } from "@thi.ng/compare"; +import { compare as cmp } from "@thi.ng/compare"; -import { Reducer, Transducer } from "../api"; +import { Reducer, Transducer, Fn } from "../api"; import { binarySearch } from "../func/binary-search"; import { identity } from "../func/identity"; +import { $iter } from "../iterator"; import { isReduced } from "../reduced"; +export interface StreamSortOpts { + key: Fn; + compare: Comparator; +} + /** * Transducer. Similar to `partitionSort()`, however uses proper sliding * window and insertion sort instead of fully sorting window as done by * `partitionSort()`. * * ``` - * [...iterator(streamSort(4), [5,9,2,6,4,1,3,8,7,0])] + * [...streamSort(4, [5,9,2,6,4,1,3,8,7,0])] * // [ 2, 4, 1, 3, 5, 6, 0, 7, 8, 9 ] * ``` * @@ -20,7 +26,20 @@ import { isReduced } from "../reduced"; * @param key * @param cmp */ -export function streamSort(n: number, key: ((x: A) => B) = identity, cmp: Comparator = compare): Transducer { +export function streamSort(n: number, opts?: Partial>): Transducer; +export function streamSort(n: number, src: Iterable): IterableIterator; +export function streamSort(n: number, opts: Partial>, src: Iterable): IterableIterator; +export function streamSort(...args: any[]): any { + const iter = $iter(streamSort, args); + if (iter) { + return iter; + } + const { key, compare } = >{ + key: identity, + compare: cmp, + ...args[1] + }; + const n = args[0]; return ([init, complete, reduce]: Reducer) => { const buf: A[] = []; return [ @@ -32,7 +51,7 @@ export function streamSort(n: number, key: ((x: A) => B) = identity, return complete(acc); }, (acc, x) => { - const idx = binarySearch(buf, key, cmp, x); + const idx = binarySearch(buf, key, compare, x); buf.splice(Math.abs(idx), 0, x); if (buf.length === n) { acc = reduce(acc, buf.shift()); diff --git a/packages/transducers/src/xform/struct.ts b/packages/transducers/src/xform/struct.ts index 6998ac6098..8815503de0 100644 --- a/packages/transducers/src/xform/struct.ts +++ b/packages/transducers/src/xform/struct.ts @@ -1,5 +1,6 @@ import { StructField, Transducer } from "../api"; import { comp } from "../func/comp"; +import { iterator } from "../iterator"; import { mapKeys } from "./map-keys"; import { partition } from "./partition"; import { partitionOf } from "./partition-of"; @@ -29,12 +30,17 @@ import { rename } from "./rename"; * ``` * * @param fields + * @param src */ -export function struct(fields: StructField[]): Transducer { - return comp( - partitionOf(fields.map((f) => f[1])), - partition(fields.length), - rename(fields.map((f) => f[0])), - mapKeys(fields.reduce((acc, f) => (f[2] ? (acc[f[0]] = f[2], acc) : acc), {}), false) - ); +export function struct(fields: StructField[]): Transducer; +export function struct(fields: StructField[], src: Iterable): IterableIterator; +export function struct(fields: StructField[], src?: Iterable): any { + return src ? + iterator(struct(fields), src) : + comp( + partitionOf(fields.map((f) => f[1])), + partition(fields.length), + rename(fields.map((f) => f[0])), + mapKeys(fields.reduce((acc, f) => (f[2] ? (acc[f[0]] = f[2], acc) : acc), {}), false) + ); } diff --git a/packages/transducers/src/xform/swizzle.ts b/packages/transducers/src/xform/swizzle.ts index f1c0dedbf8..9b13556c8a 100644 --- a/packages/transducers/src/xform/swizzle.ts +++ b/packages/transducers/src/xform/swizzle.ts @@ -1,5 +1,6 @@ import { Transducer } from "../api"; import { swizzler } from "../func/swizzler"; +import { iterator } from "../iterator"; import { map } from "./map"; /** @@ -10,18 +11,22 @@ import { map } from "./map"; * Also see `swizzler()` for standalone (non-transducer) usage. * * ``` - * [...iterator(swizzle([3,0,2,1]), [[1,2,3,4], [10,20,30,40]])] + * [...swizzle([3,0,2,1], [[1,2,3,4], [10,20,30,40]])] * // [ [ 4, 1, 3, 2 ], [ 40, 10, 30, 20 ] ] * - * [...iterator(swizzle([0,0,1,1]), [[1,2,3,4], [10,20,30,40]])] + * [...swizzle([0,0,1,1], [[1,2,3,4], [10,20,30,40]])] * // [ [ 1, 1, 2, 2 ], [ 10, 10, 20, 20 ] ] * - * [...iterator(swizzle(["z","x"]), [{x: 1, y: 2, z: 3}])] + * [...swizzle(["z","x"], [{x: 1, y: 2, z: 3}])] * // [ [ 3, 1 ] ] * ``` * * @param order key order */ -export function swizzle(order: PropertyKey[]): Transducer { - return map(swizzler(order)); +export function swizzle(order: PropertyKey[]): Transducer; +export function swizzle(order: PropertyKey[], src: Iterable): IterableIterator; +export function swizzle(order: PropertyKey[], src?: Iterable): any { + return src ? + iterator(swizzle(order), src) : + map(swizzler(order)); } diff --git a/packages/transducers/src/xform/take-last.ts b/packages/transducers/src/xform/take-last.ts index 9331cc542a..0afd5ed1b5 100644 --- a/packages/transducers/src/xform/take-last.ts +++ b/packages/transducers/src/xform/take-last.ts @@ -1,4 +1,5 @@ import { Reducer, Transducer } from "../api"; +import { iterator } from "../iterator"; import { isReduced } from "../reduced"; /** @@ -6,30 +7,35 @@ import { isReduced } from "../reduced"; * input source is finite (of course). * * ``` - * [...iterator(takeLast(3), range(10))] + * [...takeLast(3, range(10))] * // [ 7, 8, 9 ] * ``` * * @param n + * @param src */ -export function takeLast(n: number): Transducer { - return ([init, complete, reduce]: Reducer) => { - const buf: T[] = []; - return [ - init, - (acc) => { - while (buf.length && !isReduced(acc)) { - acc = reduce(acc, buf.shift()); +export function takeLast(n: number): Transducer; +export function takeLast(n: number, src: Iterable): IterableIterator; +export function takeLast(n: number, src?: Iterable): any { + return src ? + iterator(takeLast(n), src) : + ([init, complete, reduce]: Reducer) => { + const buf: T[] = []; + return [ + init, + (acc) => { + while (buf.length && !isReduced(acc)) { + acc = reduce(acc, buf.shift()); + } + return complete(acc); + }, + (acc, x) => { + if (buf.length === n) { + buf.shift(); + } + buf.push(x); + return acc; } - return complete(acc); - }, - (acc, x) => { - if (buf.length === n) { - buf.shift(); - } - buf.push(x); - return acc; - } - ]; - } + ]; + } } diff --git a/packages/transducers/src/xform/take-nth.ts b/packages/transducers/src/xform/take-nth.ts index 6ea2f02c17..feac92715c 100644 --- a/packages/transducers/src/xform/take-nth.ts +++ b/packages/transducers/src/xform/take-nth.ts @@ -1,4 +1,5 @@ import { Transducer } from "../api"; +import { iterator } from "../iterator"; import { throttle } from "./throttle"; /** @@ -6,13 +7,18 @@ import { throttle } from "./throttle"; * source. * * ``` - * [...iterator(takeNth(3), range(10))] + * [...takeNth(3, range(10))] * // [ 0, 3, 6, 9 ] * ``` * * @param n */ -export function takeNth(n: number): Transducer { +export function takeNth(n: number): Transducer; +export function takeNth(n: number, src: Iterable): IterableIterator; +export function takeNth(n: number, src?: Iterable): any { + if (src) { + return iterator(takeNth(n), src); + } n = Math.max(0, n - 1); return throttle( () => { diff --git a/packages/transducers/src/xform/take-while.ts b/packages/transducers/src/xform/take-while.ts index 4ce78eb2fd..5a6e3798ba 100644 --- a/packages/transducers/src/xform/take-while.ts +++ b/packages/transducers/src/xform/take-while.ts @@ -2,6 +2,7 @@ import { Predicate } from "@thi.ng/api/api"; import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { $iter } from "../iterator"; import { reduced } from "../reduced"; /** @@ -11,17 +12,23 @@ import { reduced } from "../reduced"; * `reduced()` value). * * ``` - * [...iterator(takeWhile((x) => x < 5), range(10))] + * [...takeWhile((x) => x < 5, range(10))] * // [ 0, 1, 2, 3, 4 ] * ``` * - * @param n + * @param pred + * @param src */ -export function takeWhile(pred: Predicate): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - let ok = true; - return compR(rfn, - (acc, x) => (ok = ok && pred(x)) ? r(acc, x) : reduced(acc)); - }; +export function takeWhile(pred?: Predicate): Transducer; +export function takeWhile(src: Iterable): IterableIterator; +export function takeWhile(pred: Predicate, src: Iterable): IterableIterator; +export function takeWhile(...args: any[]): any { + return $iter(takeWhile, args) || + ((rfn: Reducer) => { + const r = rfn[2]; + const pred = args[0]; + let ok = true; + return compR(rfn, + (acc, x: T) => (ok = ok && pred(x)) ? r(acc, x) : reduced(acc)); + }); } diff --git a/packages/transducers/src/xform/take.ts b/packages/transducers/src/xform/take.ts index 3df3c36043..d07c4d8b7f 100644 --- a/packages/transducers/src/xform/take.ts +++ b/packages/transducers/src/xform/take.ts @@ -1,5 +1,6 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; import { ensureReduced, reduced } from "../reduced"; /** @@ -13,13 +14,17 @@ import { ensureReduced, reduced } from "../reduced"; * * @param n */ -export function take(n: number): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - let m = n; - return compR(rfn, - (acc, x) => --m > 0 ? r(acc, x) : - m === 0 ? ensureReduced(r(acc, x)) : - reduced(acc)); - } +export function take(n: number): Transducer; +export function take(n: number, src: Iterable): IterableIterator; +export function take(n: number, src?: Iterable): any { + return src ? + iterator(take(n), src) : + (rfn: Reducer) => { + const r = rfn[2]; + let m = n; + return compR(rfn, + (acc, x: T) => --m > 0 ? r(acc, x) : + m === 0 ? ensureReduced(r(acc, x)) : + reduced(acc)); + } } diff --git a/packages/transducers/src/xform/throttle-time.ts b/packages/transducers/src/xform/throttle-time.ts index 7495d74cd3..5d744cc79f 100644 --- a/packages/transducers/src/xform/throttle-time.ts +++ b/packages/transducers/src/xform/throttle-time.ts @@ -1,4 +1,5 @@ import { Transducer } from "../api"; +import { iterator } from "../iterator"; import { throttle } from "./throttle"; /** @@ -7,17 +8,21 @@ import { throttle } from "./throttle"; * * **Only to be used in async contexts and NOT with `transduce` directly.** * - * Also see: `@thi.ng/rstream` and `@thi.ng/csp` packages. + * Also see: `thi.ng/rstream` and `thi.ng/csp` packages. * * @param delay */ -export function throttleTime(delay: number): Transducer { - return throttle( - () => { - let last = 0; - return () => { - const t = Date.now(); - return t - last >= delay ? (last = t, true) : false; - }; - }); +export function throttleTime(delay: number): Transducer; +export function throttleTime(delay: number, src: Iterable): IterableIterator; +export function throttleTime(delay: number, src?: Iterable): any { + return src ? + iterator(throttleTime(delay), src) : + throttle( + () => { + let last = 0; + return () => { + const t = Date.now(); + return t - last >= delay ? (last = t, true) : false; + }; + }); } diff --git a/packages/transducers/src/xform/throttle.ts b/packages/transducers/src/xform/throttle.ts index 745cbd9775..8e5c4b5320 100644 --- a/packages/transducers/src/xform/throttle.ts +++ b/packages/transducers/src/xform/throttle.ts @@ -2,6 +2,7 @@ import { StatefulPredicate } from "@thi.ng/api/api"; import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; /** * Similar to `filter`, but works with possibly stateful predicates @@ -17,12 +18,17 @@ import { compR } from "../func/compr"; * Also see: `throttleTime()`. * * @param pred + * @param src */ -export function throttle(pred: StatefulPredicate): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - const _pred = pred(); - return compR(rfn, - (acc, x) => _pred(x) ? r(acc, x) : acc); - }; +export function throttle(pred: StatefulPredicate): Transducer; +export function throttle(pred: StatefulPredicate, src: Iterable): IterableIterator; +export function throttle(pred: StatefulPredicate, src?: Iterable): any { + return src ? + iterator(throttle(pred), src) : + (rfn: Reducer) => { + const r = rfn[2]; + const _pred = pred(); + return compR(rfn, + (acc, x: T) => _pred(x) ? r(acc, x) : acc); + }; } diff --git a/packages/transducers/src/xform/utf8.ts b/packages/transducers/src/xform/utf8.ts index 59f296a76d..b4c6e3d998 100644 --- a/packages/transducers/src/xform/utf8.ts +++ b/packages/transducers/src/xform/utf8.ts @@ -1,67 +1,70 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; +import { iterator } from "../iterator"; import { isReduced } from "../reduced"; /** * Transducer which decodes a byte input sequence into UTF-8 characters. * Also see `utf8Encode()` for reverse transformation. - * - * TODO refactor using @thi.ng/transducers-fsm */ -export function utf8Decode(): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - let state = 0, u0, u1, u2, u3, u4; - return compR(rfn, - (acc, x) => { - switch (state) { - case 0: - default: - if (x < 0x80) { - return r(acc, String.fromCharCode(x)); - } - u0 = x; - state = 1; - break; - case 1: - u1 = x & 0x3f; - if ((u0 & 0xe0) === 0xc0) { - state = 0; - return r(acc, String.fromCharCode(((u0 & 0x1f) << 6) | u1)); - } - state = 2; - break; - case 2: - u2 = x & 0x3f; - if ((u0 & 0xf0) === 0xe0) { +export function utf8Decode(): Transducer; +export function utf8Decode(src: Iterable): string; +export function utf8Decode(src?: Iterable): any { + return src ? + [...iterator(utf8Decode(), src)].join("") : + (rfn: Reducer) => { + const r = rfn[2]; + let state = 0, u0, u1, u2, u3, u4; + return compR(rfn, + (acc, x: number) => { + switch (state) { + case 0: + default: + if (x < 0x80) { + return r(acc, String.fromCharCode(x)); + } + u0 = x; + state = 1; + break; + case 1: + u1 = x & 0x3f; + if ((u0 & 0xe0) === 0xc0) { + state = 0; + return r(acc, String.fromCharCode(((u0 & 0x1f) << 6) | u1)); + } + state = 2; + break; + case 2: + u2 = x & 0x3f; + if ((u0 & 0xf0) === 0xe0) { + state = 0; + return r(acc, String.fromCharCode(((u0 & 0x0f) << 12) | (u1 << 6) | u2)); + } + state = 3; + break; + case 3: + u3 = x & 0x3f; + if ((u0 & 0xf8) === 0xf0) { + state = 0; + return r(acc, codePoint(((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | u3)); + } + state = 4; + break; + case 4: + u4 = x & 0x3f; + if ((u0 & 0xfc) === 0xf8) { + state = 0; + return r(acc, codePoint(((u0 & 3) << 24) | (u1 << 18) | (u2 << 12) | (u3 << 6) | u4)); + } + state = 5; + break; + case 5: state = 0; - return r(acc, String.fromCharCode(((u0 & 0x0f) << 12) | (u1 << 6) | u2)); - } - state = 3; - break; - case 3: - u3 = x & 0x3f; - if ((u0 & 0xf8) === 0xf0) { - state = 0; - return r(acc, codePoint(((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | u3)); - } - state = 4; - break; - case 4: - u4 = x & 0x3f; - if ((u0 & 0xfc) === 0xf8) { - state = 0; - return r(acc, codePoint(((u0 & 3) << 24) | (u1 << 18) | (u2 << 12) | (u3 << 6) | u4)); - } - state = 5; - break; - case 5: - state = 0; - return r(acc, codePoint(((u0 & 1) << 30) | (u1 << 24) | (u2 << 18) | (u3 << 12) | (u4 << 6) | (x & 0x3f))); - } - return acc; - }); - }; + return r(acc, codePoint(((u0 & 1) << 30) | (u1 << 24) | (u2 << 18) | (u3 << 12) | (u4 << 6) | (x & 0x3f))); + } + return acc; + }); + }; } /** @@ -71,7 +74,7 @@ export function utf8Decode(): Transducer { * * ``` * transduce( - * comp(utf8Encode(), hexDump(8)), + * comp(utf8Encode(), hexDump()), * str("\n"), * "¡Hola niña! 😀" * ) @@ -80,62 +83,66 @@ export function utf8Decode(): Transducer { * // 00000010 | 98 80 00 00 00 00 00 00 | ........ * ``` */ -export function utf8Encode(): Transducer { - return (rfn: Reducer) => { - const r = rfn[2]; - return compR(rfn, - (acc, x) => { - let u = x.charCodeAt(0), buf; - if (u >= 0xd800 && u <= 0xdfff) { - u = 0x10000 + ((u & 0x3ff) << 10) | (x.charCodeAt(1) & 0x3ff); - } - if (u < 0x80) { - return r(acc, u); - } else if (u < 0x800) { - buf = [ - 0xc0 | (u >> 6), - 0x80 | (u & 0x3f) - ]; - } else if (u < 0x10000) { - buf = [ - 0xe0 | (u >> 12), - 0x80 | ((u >> 6) & 0x3f), - 0x80 | (u & 0x3f) - ]; - } else if (u < 0x200000) { - buf = [ - 0xf0 | (u >> 18), - 0x80 | ((u >> 12) & 0x3f), - 0x80 | ((u >> 6) & 0x3f), - 0x80 | (u & 0x3f) - ]; - } else if (u < 0x4000000) { - buf = [ - 0xf8 | (u >> 24), - 0x80 | ((u >> 18) & 0x3f), - 0x80 | ((u >> 12) & 0x3f), - 0x80 | ((u >> 6) & 0x3f), - 0x80 | (u & 0x3f) - ]; - } else { - buf = [ - 0xfc | (u >> 30), - 0x80 | ((u >> 24) & 0x3f), - 0x80 | ((u >> 18) & 0x3f), - 0x80 | ((u >> 12) & 0x3f), - 0x80 | ((u >> 6) & 0x3f), - 0x80 | (u & 0x3f) - ]; - } - for (let i = 0, n = buf.length; i < n; i++) { - acc = r(acc, buf[i]); - if (isReduced(acc)) { - break; +export function utf8Encode(): Transducer; +export function utf8Encode(src: string): IterableIterator; +export function utf8Encode(src?: string): any { + return src != null ? + iterator(utf8Encode(), src) : + (rfn: Reducer) => { + const r = rfn[2]; + return compR(rfn, + (acc, x: string) => { + let u = x.charCodeAt(0), buf; + if (u >= 0xd800 && u <= 0xdfff) { + u = 0x10000 + ((u & 0x3ff) << 10) | (x.charCodeAt(1) & 0x3ff); + } + if (u < 0x80) { + return r(acc, u); + } else if (u < 0x800) { + buf = [ + 0xc0 | (u >> 6), + 0x80 | (u & 0x3f) + ]; + } else if (u < 0x10000) { + buf = [ + 0xe0 | (u >> 12), + 0x80 | ((u >> 6) & 0x3f), + 0x80 | (u & 0x3f) + ]; + } else if (u < 0x200000) { + buf = [ + 0xf0 | (u >> 18), + 0x80 | ((u >> 12) & 0x3f), + 0x80 | ((u >> 6) & 0x3f), + 0x80 | (u & 0x3f) + ]; + } else if (u < 0x4000000) { + buf = [ + 0xf8 | (u >> 24), + 0x80 | ((u >> 18) & 0x3f), + 0x80 | ((u >> 12) & 0x3f), + 0x80 | ((u >> 6) & 0x3f), + 0x80 | (u & 0x3f) + ]; + } else { + buf = [ + 0xfc | (u >> 30), + 0x80 | ((u >> 24) & 0x3f), + 0x80 | ((u >> 18) & 0x3f), + 0x80 | ((u >> 12) & 0x3f), + 0x80 | ((u >> 6) & 0x3f), + 0x80 | (u & 0x3f) + ]; + } + for (let i = 0, n = buf.length; i < n; i++) { + acc = r(acc, buf[i]); + if (isReduced(acc)) { + break; + } } - } - return acc; - }); - }; + return acc; + }); + }; } const codePoint = (x) => diff --git a/packages/transducers/src/xform/word-wrap.ts b/packages/transducers/src/xform/word-wrap.ts index f4918eb6bd..b8c1eeacae 100644 --- a/packages/transducers/src/xform/word-wrap.ts +++ b/packages/transducers/src/xform/word-wrap.ts @@ -1,27 +1,46 @@ import { Transducer } from "../api"; +import { $iter } from "../iterator"; import { partitionBy } from "./partition-by"; +export interface WordWrapOpts { + delim: number; + always: boolean; +} + /** * Returns transducer partitioning words into variable sized arrays * based on given `lineLength` (default 80). The optional `delim` and - * `alwaysDelim` args can be used to adjust the length and usage of - * delimiters between each word. If `alwaysDelim` is true, the delimiter + * `always` args can be used to adjust the length and usage of + * delimiters between each word. If `always` is true, the delimiter * length is added to each word, even near line endings. If false * (default), the last word on each line can still fit even if there's * no space for the delimiter. * * @param lineLength - * @param delim - * @param alwaysDelim + * @param opts + * @param src */ -export function wordWrap(lineLength = 80, delim = 1, alwaysDelim = false): Transducer { +export function wordWrap(lineLength: number, opts?: Partial): Transducer; +export function wordWrap(lineLength: number, src: Iterable): IterableIterator; +export function wordWrap(lineLength: number, opts: Partial, src: Iterable): IterableIterator; +export function wordWrap(...args: any[]): any { + const iter = $iter(wordWrap, args); + if (iter) { + return iter; + } + const lineLength = args[0]; + const { delim, always } = { + delim: 1, + always: true, + ...args[1] + }; return partitionBy( () => { let n = 0; let flag = false; return (w: string) => { n += w.length + delim; - if (n > lineLength + (alwaysDelim ? 0 : delim)) { + if (n > lineLength + (always ? 0 : delim)) { flag = !flag; n = w.length + delim; } diff --git a/packages/transducers/test/flatten.ts b/packages/transducers/test/flatten.ts index e0900de1f1..2ae2f686f7 100644 --- a/packages/transducers/test/flatten.ts +++ b/packages/transducers/test/flatten.ts @@ -1,23 +1,23 @@ -import * as tx from "../src"; +import { flatten, range } from "../src"; import * as assert from "assert"; describe("flatten", () => { it("empty arrays", () => { - assert.deepEqual(tx.transduce(tx.flatten(), tx.push(), []), []); - assert.deepEqual(tx.transduce(tx.flatten(), tx.push(), [[], []]), []); + assert.deepEqual([...flatten([])], []); + assert.deepEqual([...flatten([[], []])], []); }); it("arrays", () => { - assert.deepEqual(tx.transduce(tx.flatten(), tx.push(), [undefined]), [undefined]); - assert.deepEqual(tx.transduce(tx.flatten(), tx.push(), [[undefined], null]), [undefined, null]); + assert.deepEqual([...flatten([undefined])], [undefined]); + assert.deepEqual([...flatten([[undefined], null])], [undefined, null]); }); it("strings", () => { - assert.deepEqual(tx.transduce(tx.flatten(), tx.push(), ["", "a"]), ["", "a"]); - assert.deepEqual(tx.transduce(tx.flatten(), tx.push(), [[], ["a"], ""]), ["a", ""]); + assert.deepEqual([...flatten(["", "a"])], ["", "a"]); + assert.deepEqual([...flatten([[], ["a"], ""])], ["a", ""]); }); it("iterators", () => { - assert.deepEqual(tx.transduce(tx.flatten(), tx.push(), tx.range(0)), []); - assert.deepEqual(tx.transduce(tx.flatten(), tx.push(), [tx.range(0)]), []); - assert.deepEqual(tx.transduce(tx.flatten(), tx.push(), [tx.range(2), tx.range(0)]), [0, 1]); + assert.deepEqual([...flatten(range(0))], []); + assert.deepEqual([...flatten([range(0)])], []); + assert.deepEqual([...flatten([range(2), range(0)])], [0, 1]); }) }); diff --git a/packages/transducers/test/fuzzy.ts b/packages/transducers/test/fuzzy.ts index 9014f3592f..2cd3090b0a 100644 --- a/packages/transducers/test/fuzzy.ts +++ b/packages/transducers/test/fuzzy.ts @@ -1,21 +1,21 @@ -import * as tx from "../src"; +import { filterFuzzy } from "../src"; import * as assert from "assert"; describe("fuzzy", () => { it("strings", () => { const opts = ["hello", "hallo", "hey", "heyoka"]; - assert.deepEqual(tx.transduce(tx.filterFuzzy("hl"), tx.push(), opts), ["hello", "hallo"]); - assert.deepEqual(tx.transduce(tx.filterFuzzy("he"), tx.push(), opts), ["hello", "hey", "heyoka"]); - assert.deepEqual(tx.transduce(tx.filterFuzzy("ho"), tx.push(), opts), ["hello", "hallo", "heyoka"]); - assert.deepEqual(tx.transduce(tx.filterFuzzy("hey"), tx.push(), opts), ["hey", "heyoka"]); - assert.deepEqual(tx.transduce(tx.filterFuzzy("hk"), tx.push(), opts), ["heyoka"]); + assert.deepEqual([...filterFuzzy("hl", opts)], ["hello", "hallo"]); + assert.deepEqual([...filterFuzzy("he", opts)], ["hello", "hey", "heyoka"]); + assert.deepEqual([...filterFuzzy("ho", opts)], ["hello", "hallo", "heyoka"]); + assert.deepEqual([...filterFuzzy("hey", opts)], ["hey", "heyoka"]); + assert.deepEqual([...filterFuzzy("hk", opts)], ["heyoka"]); }); it("arrays", () => { const opts = [[1, 2, 3], [1, 3, 4], [4, 5, 6], [1, 3, 6]]; - assert.deepEqual(tx.transduce(tx.filterFuzzy([1, 3]), tx.push(), opts), [[1, 2, 3], [1, 3, 4], [1, 3, 6]]); - assert.deepEqual(tx.transduce(tx.filterFuzzy([4]), tx.push(), opts), [[1, 3, 4], [4, 5, 6]]); - assert.deepEqual(tx.transduce(tx.filterFuzzy([3, 6]), tx.push(), opts), [[1, 3, 6]]); - assert.deepEqual(tx.transduce(tx.filterFuzzy([]), tx.push(), opts), opts); + assert.deepEqual([...filterFuzzy([1, 3], opts)], [[1, 2, 3], [1, 3, 4], [1, 3, 6]]); + assert.deepEqual([...filterFuzzy([4], opts)], [[1, 3, 4], [4, 5, 6]]); + assert.deepEqual([...filterFuzzy([3, 6], opts)], [[1, 3, 6]]); + assert.deepEqual([...filterFuzzy([], opts)], opts); }); }); diff --git a/packages/transducers/test/pad-last.ts b/packages/transducers/test/pad-last.ts index 7710e60be0..4a1aa3b139 100644 --- a/packages/transducers/test/pad-last.ts +++ b/packages/transducers/test/pad-last.ts @@ -1,27 +1,27 @@ -import * as tx from "../src"; +import { padLast } from "../src"; import * as assert from "assert"; describe("padLast", () => { it("all", () => { assert.deepEqual( - [...tx.iterator(tx.padLast(8, 0), [])], + [...padLast(8, 0, [])], [] ); assert.deepEqual( - [...tx.iterator(tx.padLast(8, 0), [1])], + [...padLast(8, 0, [1])], [1, 0, 0, 0, 0, 0, 0, 0] ); assert.deepEqual( - [...tx.iterator(tx.padLast(8, 0), [1, 2, 3, 4, 5])], + [...padLast(8, 0, [1, 2, 3, 4, 5])], [1, 2, 3, 4, 5, 0, 0, 0] ); assert.deepEqual( - [...tx.iterator(tx.padLast(2, 0), [1, 2, 3])], + [...padLast(2, 0, [1, 2, 3])], [1, 2, 3, 0] ); assert.deepEqual( - [...tx.iterator(tx.padLast(2, 0), [1, 2, 3, 4])], + [...padLast(2, 0, [1, 2, 3, 4])], [1, 2, 3, 4] ); }); From cd5c6ff1852e490e7d3e98bc7a72685a5b24d5d4 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:07:50 +0100 Subject: [PATCH 12/68] refactor(rstream): update StreamSync transducer init - fix regression caused by breaking changes in thi.ng/transducers --- packages/rstream/src/stream-sync.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/rstream/src/stream-sync.ts b/packages/rstream/src/stream-sync.ts index 7989f55b08..55232a359e 100644 --- a/packages/rstream/src/stream-sync.ts +++ b/packages/rstream/src/stream-sync.ts @@ -112,7 +112,11 @@ export class StreamSync extends Subscription { constructor(opts: Partial>) { let srcIDs = new Set(); let xform: Transducer = comp( - partitionSync(srcIDs, (x) => x[0], opts.reset === true, opts.all !== false), + partitionSync(srcIDs, { + key: (x) => x[0], + reset: opts.reset === true, + all: opts.all !== false + }), mapVals((x) => x[1]) ); if (opts.xform) { From eb1714f5d50c560e6095127edf6856794b890f80 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:11:53 +0100 Subject: [PATCH 13/68] refactor(rstream-query): simplify transducer uses --- packages/rstream-query/src/convert.ts | 20 +++++++++----------- packages/rstream-query/src/store.ts | 5 ++--- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/rstream-query/src/convert.ts b/packages/rstream-query/src/convert.ts index 49ea82d9fb..0f1e2be710 100644 --- a/packages/rstream-query/src/convert.ts +++ b/packages/rstream-query/src/convert.ts @@ -2,7 +2,6 @@ import { isArray } from "@thi.ng/checks/is-array"; import { isPlainObject } from "@thi.ng/checks/is-plain-object"; import { concat } from "@thi.ng/transducers/iter/concat"; import { pairs } from "@thi.ng/transducers/iter/pairs"; -import { iterator } from "@thi.ng/transducers/iterator"; import { mapcat } from "@thi.ng/transducers/xform/mapcat"; let NEXT_ID = 0; @@ -15,11 +14,11 @@ const mapBNode = (s: any, p: any, o: any) => { const mapSubject = (subject: any) => ([p, o]) => { if (isArray(o)) { - return iterator( - mapcat((o) => + return mapcat( + (o) => isPlainObject(o) ? mapBNode(subject, p, o) : - [[subject, p, o]]), + [[subject, p, o]], o); } else if (isPlainObject(o)) { return mapBNode(subject, p, o); @@ -77,10 +76,9 @@ const mapSubject = (subject: any) => * @param subject internal use only, do not specify! */ export const asTriples = (obj: any, subject?: any) => - iterator( - mapcat( - subject === undefined ? - ([s, v]: any) => iterator(mapcat(mapSubject(s)), pairs(v)) : - mapSubject(subject) - ), - pairs(obj)); + mapcat( + subject === undefined ? + ([s, v]: any) => mapcat(mapSubject(s), pairs(v)) : + mapSubject(subject), + pairs(obj) + ); diff --git a/packages/rstream-query/src/store.ts b/packages/rstream-query/src/store.ts index 172dc7dfd2..b4b7b9f070 100644 --- a/packages/rstream-query/src/store.ts +++ b/packages/rstream-query/src/store.ts @@ -17,7 +17,6 @@ import { Reducer, Transducer } from "@thi.ng/transducers/api"; import { comp } from "@thi.ng/transducers/func/comp"; import { compR } from "@thi.ng/transducers/func/compr"; import { keySelector } from "@thi.ng/transducers/func/key-selector"; -import { iterator } from "@thi.ng/transducers/iterator"; import { assocObj } from "@thi.ng/transducers/rfn/assoc-obj"; import { transduce } from "@thi.ng/transducers/transduce"; import { dedupe } from "@thi.ng/transducers/xform/dedupe"; @@ -397,8 +396,8 @@ export class TripleStore implements } protected addParamQueries(patterns: Iterable) { - return iterator( - map((q) => this.addParamQuery(q)), + return map( + (q) => this.addParamQuery(q), patterns ); } From abe1a8863c81988320f00a8c96eeb52fdcb3b261 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:14:14 +0100 Subject: [PATCH 14/68] refactor(associative): update/replace deps (iterators => transducers) --- packages/associative/package.json | 4 ++-- packages/associative/src/sorted-map.ts | 2 +- packages/associative/src/sorted-set.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/associative/package.json b/packages/associative/package.json index 958b896e81..f9e66bc28a 100644 --- a/packages/associative/package.json +++ b/packages/associative/package.json @@ -34,7 +34,7 @@ "@thi.ng/dcons": "^1.0.7", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/iterators": "^4.1.20" + "@thi.ng/transducers": "1.16.0" }, "keywords": [ "data structures", @@ -54,4 +54,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/packages/associative/src/sorted-map.ts b/packages/associative/src/sorted-map.ts index 76ea48311a..d3414e8256 100644 --- a/packages/associative/src/sorted-map.ts +++ b/packages/associative/src/sorted-map.ts @@ -11,7 +11,7 @@ import { compare } from "@thi.ng/compare"; import { equiv } from "@thi.ng/equiv"; import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { isArray } from "@thi.ng/checks/is-array"; -import { map } from "@thi.ng/iterators/map"; +import { map } from "@thi.ng/transducers/xform/map"; import { Pair, SEMAPHORE, SortedMapOpts } from "./api"; diff --git a/packages/associative/src/sorted-set.ts b/packages/associative/src/sorted-set.ts index 041f9cdf44..d6ac47e278 100644 --- a/packages/associative/src/sorted-set.ts +++ b/packages/associative/src/sorted-set.ts @@ -1,6 +1,6 @@ import { ICompare } from "@thi.ng/api/api"; import { compare } from "@thi.ng/compare"; -import { map } from "@thi.ng/iterators/map"; +import { map } from "@thi.ng/transducers/xform/map"; import { IEquivSet, Pair, SortedSetOpts } from "./api"; import { SortedMap } from "./sorted-map"; @@ -37,7 +37,7 @@ export class SortedSet extends Set implements constructor(values?: Iterable, opts?: Partial>) { super(); __private.set(this, new SortedMap( - values ? map((x) => [x, x], values) : null, + values ? map((x) => >[x, x], values) : null, opts )); } From 065d78bab4215dc0acbdc9338876b491847d0b36 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:16:30 +0100 Subject: [PATCH 15/68] refactor(cache): update/replace deps (iterators => transducers) --- packages/cache/package.json | 4 ++-- packages/cache/src/lru.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cache/package.json b/packages/cache/package.json index d272a579f3..840c5d9d1d 100644 --- a/packages/cache/package.json +++ b/packages/cache/package.json @@ -30,7 +30,7 @@ "dependencies": { "@thi.ng/api": "^4.0.6", "@thi.ng/dcons": "^1.0.7", - "@thi.ng/iterators": "^4.1.20" + "@thi.ng/transducers": "1.16.0" }, "keywords": [ "cache", @@ -46,4 +46,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/packages/cache/src/lru.ts b/packages/cache/src/lru.ts index e931760448..f937a2d199 100644 --- a/packages/cache/src/lru.ts +++ b/packages/cache/src/lru.ts @@ -1,5 +1,5 @@ import { ConsCell, DCons } from "@thi.ng/dcons"; -import { map } from "@thi.ng/iterators/map"; +import { map } from "@thi.ng/transducers/xform/map"; import { CacheEntry, CacheOpts, ICache } from "./api"; @@ -40,7 +40,7 @@ export class LRUCache implements ICache { } *entries(): IterableIterator]>> { - yield* map((e) => [e.k, e], this.items); + yield* map((e) => <[K, CacheEntry]>[e.k, e], this.items); } *keys(): IterableIterator> { From 78d0a8448fa7c8ec60108a7294442acef94ce721 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:17:40 +0100 Subject: [PATCH 16/68] fix(iges): regression to due transducers update --- packages/iges/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/iges/src/index.ts b/packages/iges/src/index.ts index 76f4109ad8..96155b3d12 100644 --- a/packages/iges/src/index.ts +++ b/packages/iges/src/index.ts @@ -193,7 +193,7 @@ const formatParams = ( const lines = transduce( comp( map(doc.$PARAM), - wordWrap(bodyWidth, 1, true), + wordWrap(bodyWidth, { delim: 1, always: true }), map((p) => p.join(doc.globals.delimParam)), ), push(), From d635226781d272f6ae59b632217803ef2e1460dc Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:20:02 +0100 Subject: [PATCH 17/68] refactor(dgraph): update/replace deps (iterators => transducers) --- packages/dgraph/package.json | 4 ++-- packages/dgraph/src/index.ts | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/dgraph/package.json b/packages/dgraph/package.json index 29a14f542c..5da979a877 100644 --- a/packages/dgraph/package.json +++ b/packages/dgraph/package.json @@ -32,7 +32,7 @@ "@thi.ng/associative": "^0.5.11", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/iterators": "^4.1.20" + "@thi.ng/transducers": "1.16.0" }, "keywords": [ "data structure", @@ -45,4 +45,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/packages/dgraph/src/index.ts b/packages/dgraph/src/index.ts index fb200ce05c..369b8725e2 100644 --- a/packages/dgraph/src/index.ts +++ b/packages/dgraph/src/index.ts @@ -1,11 +1,11 @@ import { ICopy } from "@thi.ng/api/api"; -import { equiv } from "@thi.ng/equiv"; -import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { EquivMap } from "@thi.ng/associative/equiv-map"; import { LLSet } from "@thi.ng/associative/ll-set"; import { union } from "@thi.ng/associative/union"; -import { filter } from "@thi.ng/iterators/filter"; -import { reduce } from "@thi.ng/iterators/reduce"; +import { equiv } from "@thi.ng/equiv"; +import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; +import { reduce, reducer } from "@thi.ng/transducers/reduce"; +import { filter } from "@thi.ng/transducers/xform/filter"; export class DGraph implements Iterable, @@ -139,7 +139,7 @@ function transitive(nodes: EquivMap>, x: T): LLSet { const deps: LLSet = nodes.get(x); if (deps) { return reduce( - (acc, k: T) => >union(acc, transitive(nodes, k)), + reducer(null, (acc, k: T) => >union(acc, transitive(nodes, k))), deps, deps ); From 420cfe37e68934cbf0e8adf8b7c2f96eb7b9212d Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:21:25 +0100 Subject: [PATCH 18/68] test(csp): fix regression to due transducers update --- packages/csp/test/async.ts | 3 +-- packages/csp/test/file.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/csp/test/async.ts b/packages/csp/test/async.ts index df34955693..6484325722 100644 --- a/packages/csp/test/async.ts +++ b/packages/csp/test/async.ts @@ -1,5 +1,4 @@ import * as tx from "@thi.ng/transducers"; -import { identity } from "@thi.ng/transducers/func/identity"; import { Channel, PubSub } from "../src"; @@ -85,7 +84,7 @@ async function transducers() { ch.into([1, 2, 2, 2, 1, 5, 3, 3]); await ch.consume(); const src = [5, 2, 8, 10, 20, 15, 12, 18, 27, 78, 35, 16, 2, 99, 123, 42] - ch = Channel.from(src, tx.delayed(100)).pipe(tx.streamSort(8, identity)); + ch = Channel.from(src, tx.delayed(100)).pipe(tx.streamSort(8)); await ch.consume(); } diff --git a/packages/csp/test/file.ts b/packages/csp/test/file.ts index f43a63efc4..3bc5ecf7e0 100644 --- a/packages/csp/test/file.ts +++ b/packages/csp/test/file.ts @@ -34,7 +34,7 @@ const counter = results // words with < 20 occurrences const sorted = results.tap( tx.comp( - tx.streamSort(500, x => x[1]), + tx.streamSort(500, { key: x => x[1] }), tx.dropWhile(x => x[1] < 20) ) ); From c17cb087aea6c7c165f63018d9deb8922b9b7a1d Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:25:44 +0100 Subject: [PATCH 19/68] refactor(hdom-components): update/replace deps (iterators => transducers) --- packages/hdom-components/package.json | 4 ++-- packages/hdom-components/src/pager.ts | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/hdom-components/package.json b/packages/hdom-components/package.json index 2b358d9e65..8c82e1d1a2 100644 --- a/packages/hdom-components/package.json +++ b/packages/hdom-components/package.json @@ -30,7 +30,7 @@ "dependencies": { "@thi.ng/api": "^4.0.6", "@thi.ng/checks": "^1.5.7", - "@thi.ng/iterators": "^4.1.20", + "@thi.ng/transducers": "1.16.0", "@types/webgl2": "^0.0.4" }, "keywords": [ @@ -40,4 +40,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/packages/hdom-components/src/pager.ts b/packages/hdom-components/src/pager.ts index 98d724fe9b..e729868f3f 100644 --- a/packages/hdom-components/src/pager.ts +++ b/packages/hdom-components/src/pager.ts @@ -1,5 +1,5 @@ -import { range } from "@thi.ng/iterators/range"; -import { map } from "@thi.ng/iterators/map"; +import { range } from "@thi.ng/transducers/iter/range"; +import { map } from "@thi.ng/transducers/xform/map"; /** * Configuration options for pager components. @@ -139,9 +139,13 @@ export const pager = (opts: PagerOpts) => { [opts.groupPrev, bt(0, id, maxID, opts.labelFirst, !id), bt(Math.max(id - step, 0), id, maxID, opts.labelPrev, !id)], - [opts.groupPages, - map((i: number) => bt(i, id, maxID, i + 1, i === id), - pageRange(id, maxID, maxBts))], + [ + opts.groupPages, + map( + (i: number) => bt(i, id, maxID, i + 1, i === id), + pageRange(id, maxID, maxBts) + ) + ], [opts.groupNext, bt(Math.min(id + step, maxID), id, maxID, opts.labelNext, id >= maxID), bt(maxID, id, maxID, opts.labelLast, id >= maxID)], From dcccbcba35f48a6aac6bf8d2e59ce49f87411ca0 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:31:04 +0100 Subject: [PATCH 20/68] refactor(examples): simplify transducer usages --- examples/cellular-automata/src/index.ts | 2 +- examples/crypto-chart/src/index.ts | 37 +++++++------------ examples/hdom-benchmark/src/index.ts | 3 +- examples/hdom-dropdown-fuzzy/src/fuzzy.ts | 2 +- examples/rstream-grid/src/dataflow.ts | 13 +++---- examples/svg-waveform/package.json | 2 +- .../svg-waveform/src/components/waveform.ts | 18 +++++---- examples/todo-list/src/index.ts | 3 +- .../src/components/query-results.ts | 8 ++-- examples/triple-query/src/components/table.ts | 12 ++---- 10 files changed, 40 insertions(+), 60 deletions(-) diff --git a/examples/cellular-automata/src/index.ts b/examples/cellular-automata/src/index.ts index 475a9384b8..56d6e44f4b 100644 --- a/examples/cellular-automata/src/index.ts +++ b/examples/cellular-automata/src/index.ts @@ -72,7 +72,7 @@ const randomizeRules = () => { export const convolve = (src: number[], rules: number[], width: number, height: number, rstride = 9, wrap = true) => transduce( comp( - multiplex(convolve2d(src, width, height, kernel, wrap), map(lookup2d(src, width))), + multiplex(convolve2d({ src, width, height, kernel, wrap }), map(lookup2d(src, width))), map(lookup2d(rules, rstride)) ), push(), diff --git a/examples/crypto-chart/src/index.ts b/examples/crypto-chart/src/index.ts index 73a0852cbe..0039ac4aa2 100644 --- a/examples/crypto-chart/src/index.ts +++ b/examples/crypto-chart/src/index.ts @@ -23,7 +23,6 @@ import { wma } from "@thi.ng/transducers-stats/wma"; import { comp } from "@thi.ng/transducers/func/comp"; import { pairs } from "@thi.ng/transducers/iter/pairs"; import { range } from "@thi.ng/transducers/iter/range"; -import { iterator } from "@thi.ng/transducers/iterator"; import { reducer } from "@thi.ng/transducers/reduce"; import { max } from "@thi.ng/transducers/rfn/max"; import { min } from "@thi.ng/transducers/rfn/min"; @@ -278,8 +277,8 @@ const chart = sync({ line([MARGIN_X, MARGIN_Y], [MARGIN_X, by]), line([MARGIN_X, by], [width - MARGIN_X, by]), // Y axis ticks - ...iterator( - mapcat((price: number) => { + mapcat( + (price: number) => { const y = mapY(price); return [ line([MARGIN_X - 10, y], [MARGIN_X, y]), @@ -291,30 +290,27 @@ const chart = sync({ }), text(price.toFixed(4), [MARGIN_X - 15, y + 4], { stroke: "none" }) ]; - }), + }, range(Math.ceil(data.min / tickY) * tickY, data.max, tickY) ), // X axis ticks - ...iterator( - mapcat((t: number) => { + mapcat( + (t: number) => { const x = fit(t, data.tbounds[0], data.tbounds[1], MARGIN_X + w / 2, width - MARGIN_X - w / 2); return [ line([x, by], [x, by + 10]), line([x, MARGIN_Y], [x, by], { stroke: theme.chart.gridMinor, "stroke-dasharray": 2 }), text(fmtTime(t), [x, by + 20], { stroke: "none", "text-anchor": "middle" }) ]; - }), + }, range(Math.ceil(data.tbounds[0] / tickX) * tickX, data.tbounds[1], tickX) ), ), // moving averages - ...iterator( - map(([period, vals]) => sma(vals, theme.chart[`sma${period}`])), - data.sma - ), + map(([period, vals]) => sma(vals, theme.chart[`sma${period}`]), data.sma), // candles - ...iterator( - mapIndexed((i, candle: OHLC) => { + mapIndexed( + (i, candle: OHLC) => { const isBullish = candle.open < candle.close; let y, h; let col; @@ -331,7 +327,7 @@ const chart = sync({ line([mapX(i + 0.5), mapY(candle.low)], [mapX(i + 0.5), mapY(candle.high)]), rect([mapX(i) + 1, y], w - 2, h), ); - }), + }, ohlc ), // price line @@ -357,17 +353,13 @@ sync({ period: period.transform(menu(period, "Time frame", [...pairs(TIMEFRAMES)])), avg: avgMode.transform( menu(avgMode, "Moving average", - [...iterator( - map(([id, mode]) => [id, mode.label]), - pairs(MA_MODES))] + [...map(([id, mode]) => [id, mode.label], pairs(MA_MODES))] ) ), themeSel: theme.transform( map((x) => x.id), menu(theme, "Theme", - [...iterator( - map(([id, theme]) => [id, theme.label]), - pairs(THEMES))] + [...map(([id, theme]) => [id, theme.label], pairs(THEMES))] ) ) }, @@ -386,10 +378,7 @@ sync({ } }, ["div.flex", - ...iterator( - map((x) => ["div.w-25.ph2", x]), - [symbol, period, avg, themeSel] - ), + ...map((x) => ["div.w-25.ph2", x], [symbol, period, avg, themeSel]), ] ], ["div.fixed.tc", diff --git a/examples/hdom-benchmark/src/index.ts b/examples/hdom-benchmark/src/index.ts index ea665bc1d5..ea124cdad6 100644 --- a/examples/hdom-benchmark/src/index.ts +++ b/examples/hdom-benchmark/src/index.ts @@ -5,7 +5,6 @@ import { Stream } from "@thi.ng/rstream/stream"; import { radix } from "@thi.ng/strings/radix"; import { comp } from "@thi.ng/transducers/func/comp"; import { range } from "@thi.ng/transducers/iter/range"; -import { iterator } from "@thi.ng/transducers/iterator"; import { benchmark } from "@thi.ng/transducers/xform/benchmark"; import { map } from "@thi.ng/transducers/xform/map"; import { mapIndexed } from "@thi.ng/transducers/xform/map-indexed"; @@ -94,7 +93,7 @@ const app = () => { let j = (++i) & 0x1ff; return ["div", ["div#stats", fps, menu], - ["grid", iterator(mapIndexed(box), range(j, j + num))] + ["grid", mapIndexed(box, range(j, j + num))] ]; }; }; diff --git a/examples/hdom-dropdown-fuzzy/src/fuzzy.ts b/examples/hdom-dropdown-fuzzy/src/fuzzy.ts index dc36c3e4b8..4c551d0693 100644 --- a/examples/hdom-dropdown-fuzzy/src/fuzzy.ts +++ b/examples/hdom-dropdown-fuzzy/src/fuzzy.ts @@ -33,7 +33,7 @@ export const fuzzyDropdown = (ctx, opts: FuzzyArgs) => { state.items = [ ...iterator( comp( - filterFuzzy(filter, (x: DropdownItem) => x[1].toLowerCase()), + filterFuzzy(filter, { key: (x: DropdownItem) => x[1].toLowerCase() }), map(([id, x]) => [ id, diff --git a/examples/rstream-grid/src/dataflow.ts b/examples/rstream-grid/src/dataflow.ts index 67a395377f..e17ea7ab81 100644 --- a/examples/rstream-grid/src/dataflow.ts +++ b/examples/rstream-grid/src/dataflow.ts @@ -4,7 +4,6 @@ import { rect } from "@thi.ng/hiccup-svg/rect"; import { EventBus } from "@thi.ng/interceptors/event-bus"; import { initGraph, node } from "@thi.ng/rstream-graph/graph"; import { range2d } from "@thi.ng/transducers/iter/range2d"; -import { iterator } from "@thi.ng/transducers/iterator"; import { map } from "@thi.ng/transducers/xform/map"; import * as ev from "./events"; @@ -60,10 +59,8 @@ export function initDataflow(bus: EventBus) { */ const grid = node(map( ({ cols, rows }) => - [...iterator( - map(([x, y]) => ["rect", { x, y, width: 1, height: 1 }]), - range2d(cols, rows) - )])); + [...map(([x, y]) => ["rect", { x, y, width: 1, height: 1 }], range2d(cols, rows))] +)); /** * Implementation for rotate node. Injects SVG `transform` attribute in @@ -71,9 +68,9 @@ const grid = node(map( */ const rotate = node(map( ({ shapes, theta }) => - [...iterator( - map((s) => (s[1].transform = `rotate(${theta} ${s[1].x + 0.5} ${s[1].y + 0.5})`, s)), - shapes)] + shapes.map( + (s) => (s[1].transform = `rotate(${theta} ${s[1].x + 0.5} ${s[1].y + 0.5})`, s) + ) )); /** diff --git a/examples/svg-waveform/package.json b/examples/svg-waveform/package.json index 8bce0245da..11dcd82f02 100644 --- a/examples/svg-waveform/package.json +++ b/examples/svg-waveform/package.json @@ -14,7 +14,7 @@ "@thi.ng/hdom": "latest", "@thi.ng/hiccup-svg": "latest", "@thi.ng/interceptors": "latest", - "@thi.ng/iterators": "latest" + "@thi.ng/transducers": "latest" }, "devDependencies": { "@types/node": "^9.6.2", diff --git a/examples/svg-waveform/src/components/waveform.ts b/examples/svg-waveform/src/components/waveform.ts index 8e119d9371..9a5a7923e2 100644 --- a/examples/svg-waveform/src/components/waveform.ts +++ b/examples/svg-waveform/src/components/waveform.ts @@ -2,9 +2,9 @@ import { svg } from "@thi.ng/hiccup-svg/svg"; import { defs } from "@thi.ng/hiccup-svg/defs"; import { linearGradient } from "@thi.ng/hiccup-svg/gradients"; import { polyline } from "@thi.ng/hiccup-svg/polyline"; -import { map } from "@thi.ng/iterators/map"; -import { range } from "@thi.ng/iterators/range"; -import { reduce } from "@thi.ng/iterators/reduce"; +import { map } from "@thi.ng/transducers/xform/map"; +import { range } from "@thi.ng/transducers/iter/range"; +import { reduce, reducer } from "@thi.ng/transducers/reduce"; import { AppContext } from "../api"; @@ -56,11 +56,13 @@ export function waveform(ctx: AppContext, opts: WaveformOpts) { function osc(x: number, phase: number, fscale: number, amp: number, harmonics: number, hstep: number) { const f = x * fscale; return reduce( - (sum, i) => { - const k = (1 + i * hstep); - return sum + Math.sin(phase + f * k) * amp / k; - }, - 0, + reducer( + () => 0, + (sum, i) => { + const k = (1 + i * hstep); + return sum + Math.sin(phase + f * k) * amp / k; + } + ), range(0, harmonics + 1) ); } diff --git a/examples/todo-list/src/index.ts b/examples/todo-list/src/index.ts index 64a71c1f3e..246b06df30 100644 --- a/examples/todo-list/src/index.ts +++ b/examples/todo-list/src/index.ts @@ -3,7 +3,6 @@ import { Atom, Cursor, History } from "@thi.ng/atom"; import { start } from "@thi.ng/hdom/start"; import { setIn, updateIn } from "@thi.ng/paths"; import { pairs } from "@thi.ng/transducers/iter/pairs"; -import { iterator } from "@thi.ng/transducers/iterator"; import { map } from "@thi.ng/transducers/xform/map"; interface Task { @@ -20,7 +19,7 @@ const nextID = new Cursor(db, "nextID"); // create derived view of tasks transformed into components const items = db.addView( "tasks", - (tasks) => [...iterator(map(([id, t]) => taskItem(id, t)), pairs(tasks))] + (tasks) => [...map(([id, t]) => taskItem(id, t), pairs(tasks))] ); // state updaters diff --git a/examples/triple-query/src/components/query-results.ts b/examples/triple-query/src/components/query-results.ts index 87b6b1041c..c9dcfffc32 100644 --- a/examples/triple-query/src/components/query-results.ts +++ b/examples/triple-query/src/components/query-results.ts @@ -1,5 +1,4 @@ import { repeat } from "@thi.ng/transducers/iter/repeat"; -import { iterator } from "@thi.ng/transducers/iterator"; import { map } from "@thi.ng/transducers/xform/map"; import { mapIndexed } from "@thi.ng/transducers/xform/map-indexed"; @@ -16,10 +15,11 @@ export const queryResults = (_: AppContext, title: string, results: Set) => [table, ["10%", ...repeat(`${(90 / keys.length) | 0}%`, keys.length)], ["id", ...keys], - iterator( - mapIndexed((i, x) => [i + 1, ...iterator(map((k: string) => x[k]), keys)]), + mapIndexed( + (i, x) => [i + 1, ...map((k: string) => x[k], keys)], results - )] + ) + ] ]; } }; \ No newline at end of file diff --git a/examples/triple-query/src/components/table.ts b/examples/triple-query/src/components/table.ts index 694b75ee33..d76fcd6b4b 100644 --- a/examples/triple-query/src/components/table.ts +++ b/examples/triple-query/src/components/table.ts @@ -1,4 +1,3 @@ -import { iterator } from "@thi.ng/transducers/iterator"; import { map } from "@thi.ng/transducers/xform/map"; import { AppContext } from "../api"; @@ -8,12 +7,7 @@ const row = (ctx: AppContext, body: Iterable) => export const table = (ctx: AppContext, layout: any[], head: Iterable, body: Iterable>) => ["table", ctx.ui.table.root, - ...(layout || []).map((x) => ["col", { style: { width: x } }]), - [row, iterator(map((x) => ["th", ctx.ui.table.head, x]), head)], - iterator( - map((cols: any) => - [row, iterator(map((x) => ["td", ctx.ui.table.cell, x]), cols)] - ), - body - ) + map((x) => ["col", { style: { width: x } }], layout || []), + [row, map((x) => ["th", ctx.ui.table.head, x], head)], + map((cols: any) => [row, map((x) => ["td", ctx.ui.table.cell, x], cols)], body) ]; From afb267a0275c5925eda88ea0c8dae6bb93fed2b4 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:35:10 +0100 Subject: [PATCH 21/68] docs: add graphviz dot files --- assets/dot/crypto-dflow.dot | 30 ++++++++++ assets/dot/dot-example.dot | 21 +++++++ assets/dot/q1.dot | 79 +++++++++++++++++++++++++++ assets/dot/q2.dot | 79 +++++++++++++++++++++++++++ assets/{ => dot}/rs-dflow.dot | 0 assets/{ => dot}/rs-dot-example.dot | 0 assets/{ => dot}/rs-query1.dot | 0 assets/dot/transducers-hdom-dflow.dot | 16 ++++++ 8 files changed, 225 insertions(+) create mode 100644 assets/dot/crypto-dflow.dot create mode 100644 assets/dot/dot-example.dot create mode 100644 assets/dot/q1.dot create mode 100644 assets/dot/q2.dot rename assets/{ => dot}/rs-dflow.dot (100%) rename assets/{ => dot}/rs-dot-example.dot (100%) rename assets/{ => dot}/rs-query1.dot (100%) create mode 100644 assets/dot/transducers-hdom-dflow.dot diff --git a/assets/dot/crypto-dflow.dot b/assets/dot/crypto-dflow.dot new file mode 100644 index 0000000000..a7439226be --- /dev/null +++ b/assets/dot/crypto-dflow.dot @@ -0,0 +1,30 @@ +digraph g { + rankdir=LR; + node[fontname=Inconsolata,fontsize=11]; + edge[fontname=Inconsolata,fontsize=9]; + + rank=same { + symbol -> response; + period -> response; + avgmode; + } + market -> response; + refresh -> response[label="every 60 secs"]; + + response -> data; + avgmode -> data; + + data -> chart; + window -> chart[style=dashed, label="resize"]; + theme -> chart; + + symbol -> ui; + period -> ui; + chart -> ui; + theme -> ui; + + ui -> symbol[style=dashed, label="user"]; + ui -> period[style=dashed, label="user"]; + ui -> theme[style=dashed, label="user"]; + ui -> avgmode[style=dashed, label="user"]; +} \ No newline at end of file diff --git a/assets/dot/dot-example.dot b/assets/dot/dot-example.dot new file mode 100644 index 0000000000..b2af0bf274 --- /dev/null +++ b/assets/dot/dot-example.dot @@ -0,0 +1,21 @@ +digraph g { +rankdir="LR"; +fontname="Inconsolata"; +fontsize="9"; +fontcolor="gray"; +label="Generated with @thi.ng/dot"; +labeljust="l"; +labelloc="b"; +node[style="filled", fontname="Inconsolata", fontsize="11"]; +edge[arrowsize="0.75", fontname="Inconsolata", fontsize="9"]; +"x"[color="black", fontcolor="white", label="x (12)"]; +"y"[color="black", fontcolor="white", label="y (23)"]; +"res"[color="black", fontcolor="white", label="res (8050)", peripheries="2"]; +"op1"[fillcolor="green", shape="Mrecord", label="{ <0> a | <1> b } | op1\n(+) | { out }"]; +"op2"[fillcolor="yellow", shape="Mrecord", label="{ <0> a | <1> b } | op2\n(*) | { out }"]; +"x" -> "op1":"1"; +"y" -> "op1":"0"; +"y" -> "op2":"0"[label="xform", color="blue"]; +"op1":"out" -> "op2":"1"; +"op2":"out" -> "res"; +} \ No newline at end of file diff --git a/assets/dot/q1.dot b/assets/dot/q1.dot new file mode 100644 index 0000000000..c7c791cd26 --- /dev/null +++ b/assets/dot/q1.dot @@ -0,0 +1,79 @@ +digraph g { +// rankdir=LR; +node[fontname=Inconsolata,fontsize=11,style=filled,fontcolor=white]; +edge[fontname=Inconsolata,fontsize=11]; +s0[label="S\n(Stream)\n{'index':{},'key':'e'}", color="blue"]; +s1[label="P\n(Stream)\n{'index':{},'key':'age'}", color="blue"]; +s2[label="p\n[0,1,2,3,4]", color="black"]; +s3[label="in-p\n['p',{}]", color="black"]; +s4[label="", color="gray"]; +s5[label="query-0-raw\n(StreamSync)\n[0,1,2,3,4]", color="red"]; +s6[label="xform-1\n[['a','knows','b'],['b','knows','c'],['a','knows','d'],['d','knows','e'],['d','knows','f']]", color="black"]; +s7[label="query-0\n[{'x':'a','y':'b'},{'x':'b','y':'c'},{'x':'a','y':'d'},{'x':'d','y':'e'},{'x':'d','y':'f'}]", color="black"]; +s8[label="in-0\n['0',{}]", color="black"]; +s9[label="", color="gray"]; +s10[label="streamsync-6\n(StreamSync)\n[{'z':'e','a':42,'x':'a','y':'d','age':'42 years'}]", color="red"]; +s11[label="xform-7\n[{'age':'42 years','z':'e','x':'a'}]", color="black"]; +s12[label="sub-8\n[{'age':'42 years','z':'e','x':'a'}]", color="black"]; +s13[label="", color="gray"]; +s14[label="xform-3\n[['a','knows','b'],['b','knows','c'],['a','knows','d'],['d','knows','e'],['d','knows','f']]", color="black"]; +s15[label="query-2\n[{'y':'a','z':'b'},{'y':'b','z':'c'},{'y':'a','z':'d'},{'y':'d','z':'e'},{'y':'d','z':'f'}]", color="black"]; +s16[label="in-1\n['1',{}]", color="black"]; +s17[label="", color="gray"]; +s18[label="p\n[5]", color="black"]; +s19[label="in-p\n['p',{}]", color="black"]; +s20[label="", color="gray"]; +s21[label="query-4-raw\n(StreamSync)\n[5]", color="red"]; +s22[label="xform-5\n[['e','age',42]]", color="black"]; +s23[label="query-4\n[{'z':'e','a':42}]", color="black"]; +s24[label="in-2\n['2',{}]", color="black"]; +s25[label="", color="gray"]; +s26[label="O\n(Stream)\n{'index':{},'key':42}", color="blue"]; +s27[label="ALL\n(Stream)\n[0,1,2,3,4,5]", color="blue"]; +s28[label="in-s\n['s',{}]", color="black"]; +s29[label="", color="gray"]; +s30[label="in-o\n['o',{}]", color="black"]; +s31[label="", color="gray"]; +s32[label="in-s\n['s',{}]", color="black"]; +s33[label="", color="gray"]; +s34[label="in-o\n['o',{}]", color="black"]; +s35[label="", color="gray"]; +s12 -> s13; +s11 -> s12; +s10 -> s11[label="xform"]; +s9 -> s10[label="xform"]; +s8 -> s9; +s7 -> s8[label="xform"]; +s6 -> s7[label="xform"]; +s17 -> s10[label="xform"]; +s16 -> s17; +s15 -> s16[label="xform"]; +s14 -> s15[label="xform"]; +s5 -> s6[label="xform"]; +s5 -> s14[label="xform"]; +s4 -> s5[label="xform"]; +s3 -> s4; +s2 -> s3[label="xform"]; +s25 -> s10[label="xform"]; +s24 -> s25; +s23 -> s24[label="xform"]; +s22 -> s23[label="xform"]; +s21 -> s22[label="xform"]; +s20 -> s21[label="xform"]; +s19 -> s20; +s18 -> s19[label="xform"]; +s1 -> s2[label="xform"]; +s1 -> s18[label="xform"]; +s29 -> s5[label="xform"]; +s28 -> s29; +s31 -> s5[label="xform"]; +s30 -> s31; +s33 -> s21[label="xform"]; +s32 -> s33; +s35 -> s21[label="xform"]; +s34 -> s35; +s27 -> s28[label="xform"]; +s27 -> s30[label="xform"]; +s27 -> s32[label="xform"]; +s27 -> s34[label="xform"]; +} \ No newline at end of file diff --git a/assets/dot/q2.dot b/assets/dot/q2.dot new file mode 100644 index 0000000000..a99965d91d --- /dev/null +++ b/assets/dot/q2.dot @@ -0,0 +1,79 @@ +digraph g { +//rankdir=LR; +node[fontname=Inconsolata,fontsize=11,style=filled,fontcolor=white]; +edge[fontname=Inconsolata,fontsize=11]; +s0[label="S\n(Stream)\n{'index':[6],'key':'f'}", color="blue"]; +s1[label="P\n(Stream)\n{'index':[5,6],'key':'age'}", color="blue"]; +s2[label="p\n[0,1,2,3,4]", color="black"]; +s3[label="in-p\n['p',[0,1,2,3,4]]", color="black"]; +s4[label="", color="gray"]; +s5[label="query-0-raw\n(StreamSync)\n[0,1,2,3,4]", color="red"]; +s6[label="xform-1\n[['a','knows','b'],['b','knows','c'],['a','knows','d'],['d','knows','e'],['d','knows','f']]", color="black"]; +s7[label="query-0\n[{'x':'a','y':'b'},{'x':'b','y':'c'},{'x':'a','y':'d'},{'x':'d','y':'e'},{'x':'d','y':'f'}]", color="black"]; +s8[label="in-0\n['0',[{'x':'a','y':'b'},{'x':'b','y':'c'},{'x':'a','y':'d'},{'x':'d','y':'e'},{'x':'d','y':'f'}]]", color="black"]; +s9[label="", color="gray"]; +s10[label="streamsync-6\n(StreamSync)\n[{'z':'e','a':42,'x':'a','y':'d','age':'42 years'}]", color="red"]; +s11[label="xform-7\n[{'age':'42 years','z':'e','x':'a'}]", color="black"]; +s12[label="sub-8\n[{'age':'42 years','z':'e','x':'a'}]", color="black"]; +s13[label="", color="gray"]; +s14[label="xform-3\n[['a','knows','b'],['b','knows','c'],['a','knows','d'],['d','knows','e'],['d','knows','f']]", color="black"]; +s15[label="query-2\n[{'y':'a','z':'b'},{'y':'b','z':'c'},{'y':'a','z':'d'},{'y':'d','z':'e'},{'y':'d','z':'f'}]", color="black"]; +s16[label="in-1\n['1',[{'y':'a','z':'b'},{'y':'b','z':'c'},{'y':'a','z':'d'},{'y':'d','z':'e'},{'y':'d','z':'f'}]]", color="black"]; +s17[label="", color="gray"]; +s18[label="p\n[5,6]", color="black"]; +s19[label="in-p\n['p',[5,6]]", color="black"]; +s20[label="", color="gray"]; +s21[label="query-4-raw\n(StreamSync)\n[5,6]", color="red"]; +s22[label="xform-5\n[['e','age',42],['f','age',43]]", color="black"]; +s23[label="query-4\n[{'z':'e','a':42},{'z':'f','a':43}]", color="black"]; +s24[label="in-2\n['2',[{'z':'e','a':42},{'z':'f','a':43}]]", color="black"]; +s25[label="", color="gray"]; +s26[label="O\n(Stream)\n{'index':[6],'key':43}", color="blue"]; +s27[label="ALL\n(Stream)\n[0,1,2,3,4,5,6]", color="blue"]; +s28[label="in-s\n['s',[0,1,2,3,4,5,6]]", color="black"]; +s29[label="", color="gray"]; +s30[label="in-o\n['o',[0,1,2,3,4,5,6]]", color="black"]; +s31[label="", color="gray"]; +s32[label="in-s\n['s',[0,1,2,3,4,5,6]]", color="black"]; +s33[label="", color="gray"]; +s34[label="in-o\n['o',[0,1,2,3,4,5,6]]", color="black"]; +s35[label="", color="gray"]; +s12 -> s13; +s11 -> s12; +s10 -> s11[label="xform"]; +s9 -> s10[label="xform"]; +s8 -> s9; +s7 -> s8[label="xform"]; +s6 -> s7[label="xform"]; +s17 -> s10[label="xform"]; +s16 -> s17; +s15 -> s16[label="xform"]; +s14 -> s15[label="xform"]; +s5 -> s6[label="xform"]; +s5 -> s14[label="xform"]; +s4 -> s5[label="xform"]; +s3 -> s4; +s2 -> s3[label="xform"]; +s25 -> s10[label="xform"]; +s24 -> s25; +s23 -> s24[label="xform"]; +s22 -> s23[label="xform"]; +s21 -> s22[label="xform"]; +s20 -> s21[label="xform"]; +s19 -> s20; +s18 -> s19[label="xform"]; +s1 -> s2[label="xform"]; +s1 -> s18[label="xform"]; +s29 -> s5[label="xform"]; +s28 -> s29; +s31 -> s5[label="xform"]; +s30 -> s31; +s33 -> s21[label="xform"]; +s32 -> s33; +s35 -> s21[label="xform"]; +s34 -> s35; +s27 -> s28[label="xform"]; +s27 -> s30[label="xform"]; +s27 -> s32[label="xform"]; +s27 -> s34[label="xform"]; +} \ No newline at end of file diff --git a/assets/rs-dflow.dot b/assets/dot/rs-dflow.dot similarity index 100% rename from assets/rs-dflow.dot rename to assets/dot/rs-dflow.dot diff --git a/assets/rs-dot-example.dot b/assets/dot/rs-dot-example.dot similarity index 100% rename from assets/rs-dot-example.dot rename to assets/dot/rs-dot-example.dot diff --git a/assets/rs-query1.dot b/assets/dot/rs-query1.dot similarity index 100% rename from assets/rs-query1.dot rename to assets/dot/rs-query1.dot diff --git a/assets/dot/transducers-hdom-dflow.dot b/assets/dot/transducers-hdom-dflow.dot new file mode 100644 index 0000000000..85134bb367 --- /dev/null +++ b/assets/dot/transducers-hdom-dflow.dot @@ -0,0 +1,16 @@ +digraph { + rankdir=LR; + node[fontname=Inconsolata,fontsize=11]; + edge[fontname=Inconsolata,fontsize=9]; + + rank=same { + ticks[label="ticks\nfromInterval(1000)"]; + clicks[label="clicks"]; + } + + sync[label="StreamSync\n(hdom UI update)"]; + + ticks -> sync; + clicks -> sync[label="xform\n(counter)"]; + sync -> clicks[style=dashed, label="user"]; +} \ No newline at end of file From 3e6c46249b85fb56af415a5ed0468e65ce86f00b Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:37:10 +0100 Subject: [PATCH 22/68] chore: update .gitignore --- .gitignore | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d394afd896..7cff648e4a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,11 +4,17 @@ coverage build dev doc -docs/site +docs +examples/dataflow-scenegraph +examples/hdc +examples/hdom-class .DS_Store +tachyons.min.css bundle.* *.html *.log *.tgz *.js *.d.ts +*.bak* +*.zip \ No newline at end of file From 8a111efd50edd0588304f0a19544b915bd205f28 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:48:45 +0100 Subject: [PATCH 23/68] refactor(transducers): add shared SortOpts, update xforms - replace opts for movingMedian(), partitionSort(), streamSort() - move convolution types to src/xform/convole.ts - move StructField to src/xform/struct.ts --- packages/transducers/src/api.ts | 25 +++++++++++-------- packages/transducers/src/xform/convolve.ts | 6 ++++- .../transducers/src/xform/moving-median.ts | 15 +++-------- .../transducers/src/xform/partition-sort.ts | 14 +++-------- packages/transducers/src/xform/stream-sort.ts | 14 +++-------- packages/transducers/src/xform/struct.ts | 8 +++++- 6 files changed, 38 insertions(+), 44 deletions(-) diff --git a/packages/transducers/src/api.ts b/packages/transducers/src/api.ts index 3e41b74ad2..0ad1a461c2 100644 --- a/packages/transducers/src/api.ts +++ b/packages/transducers/src/api.ts @@ -1,4 +1,4 @@ -import { IObjectOf } from "@thi.ng/api/api"; +import { Comparator, IObjectOf } from "@thi.ng/api/api"; import { Reduced } from "./reduced"; @@ -14,16 +14,6 @@ export interface Reducer extends Array { [2]: ReductionFn; }; -export interface StructField extends Array { - [0]: string; - [1]: number; - [2]?: Fn; -} - -export type ConvolutionKernel1D = [number, number][]; -export type ConvolutionKernel2D = [number, [number, number]][]; -export type ConvolutionKernel3D = [number, [number, number, number]][]; - export type TransformFn = (x: any) => any; export type TransformSubSpec = IObjectOf; export interface TransformSpec extends Array { @@ -31,4 +21,17 @@ export interface TransformSpec extends Array { [1]?: TransformSubSpec; } +export interface SortOpts { + /** + * Sort key lookup function. + * Default: `identity` + */ + key: Fn; + /** + * Comparator. + * Default: `thi.ng/compare/compare` + */ + compare: Comparator; +} + export const SEMAPHORE = Symbol(); diff --git a/packages/transducers/src/xform/convolve.ts b/packages/transducers/src/xform/convolve.ts index 0f530d8a73..9b48a69f72 100644 --- a/packages/transducers/src/xform/convolve.ts +++ b/packages/transducers/src/xform/convolve.ts @@ -1,6 +1,6 @@ import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; -import { ConvolutionKernel2D, Transducer } from "../api"; +import { Transducer } from "../api"; import { range2d } from "../iter/range2d"; import { tuples } from "../iter/tuples"; import { iterator } from "../iterator"; @@ -8,6 +8,10 @@ import { add } from "../rfn/add"; import { transduce } from "../transduce"; import { map } from "./map"; +export type ConvolutionKernel1D = [number, number][]; +export type ConvolutionKernel2D = [number, [number, number]][]; +export type ConvolutionKernel3D = [number, [number, number, number]][]; + export interface Convolution2DOpts { src: number[]; width: number; diff --git a/packages/transducers/src/xform/moving-median.ts b/packages/transducers/src/xform/moving-median.ts index f521efbf3f..7833f27d1a 100644 --- a/packages/transducers/src/xform/moving-median.ts +++ b/packages/transducers/src/xform/moving-median.ts @@ -1,18 +1,11 @@ -import { Comparator } from "@thi.ng/api/api"; import { compare as cmp } from "@thi.ng/compare"; - -import { Fn, Transducer } from "../api"; +import { SortOpts, Transducer } from "../api"; import { comp } from "../func/comp"; import { identity } from "../func/identity"; import { $iter } from "../iterator"; import { map } from "./map"; import { partition } from "./partition"; -export interface MovingMedianOpts { - key: Fn; - compare: Comparator; -} - /** * Transducer. Similar to `movingAverage()`, but yields median of * sliding window and supports non-numeric inputs. The optional `key` @@ -23,15 +16,15 @@ export interface MovingMedianOpts { * @param opts * @param src */ -export function movingMedian(n: number, opts?: Partial>): Transducer; +export function movingMedian(n: number, opts?: Partial>): Transducer; export function movingMedian(n: number, src: Iterable): IterableIterator; -export function movingMedian(n: number, opts: Partial>, src: Iterable): IterableIterator; +export function movingMedian(n: number, opts: Partial>, src: Iterable): IterableIterator; export function movingMedian(...args: any[]): any { const iter = $iter(movingMedian, args); if (iter) { return iter; } - const { key, compare } = >{ + const { key, compare } = >{ key: identity, compare: cmp, ...args[1] diff --git a/packages/transducers/src/xform/partition-sort.ts b/packages/transducers/src/xform/partition-sort.ts index a1bdc72ef3..f1fba964e6 100644 --- a/packages/transducers/src/xform/partition-sort.ts +++ b/packages/transducers/src/xform/partition-sort.ts @@ -1,18 +1,12 @@ -import { Comparator } from "@thi.ng/api/api"; import { compare as cmp } from "@thi.ng/compare"; -import { Fn, Transducer } from "../api"; +import { SortOpts, Transducer } from "../api"; import { comp } from "../func/comp"; import { identity } from "../func/identity"; import { $iter } from "../iterator"; import { mapcat } from "./mapcat"; import { partition } from "./partition"; -export interface PartitionSortOpts { - key: Fn; - compare: Comparator; -} - /** * Transducer. Composition of `partition` and `mapcat` which yields a * **partially** sorted sequence of input values. Sorting is performed on @@ -39,15 +33,15 @@ export interface PartitionSortOpts { * @param key sort key lookup * @param cmp comparator */ -export function partitionSort(n: number, opts?: Partial>): Transducer; +export function partitionSort(n: number, opts?: Partial>): Transducer; export function partitionSort(n: number, src: Iterable): IterableIterator; -export function partitionSort(n: number, opts: Partial>, src: Iterable): IterableIterator; +export function partitionSort(n: number, opts: Partial>, src: Iterable): IterableIterator; export function partitionSort(...args: any[]): any { const iter = $iter(partitionSort, args); if (iter) { return iter; } - const { key, compare } = >{ + const { key, compare } = >{ key: identity, compare: cmp, ...args[1] diff --git a/packages/transducers/src/xform/stream-sort.ts b/packages/transducers/src/xform/stream-sort.ts index 423221de63..f7d332b8ea 100644 --- a/packages/transducers/src/xform/stream-sort.ts +++ b/packages/transducers/src/xform/stream-sort.ts @@ -1,17 +1,11 @@ -import { Comparator } from "@thi.ng/api/api"; import { compare as cmp } from "@thi.ng/compare"; -import { Reducer, Transducer, Fn } from "../api"; +import { Reducer, SortOpts, Transducer } from "../api"; import { binarySearch } from "../func/binary-search"; import { identity } from "../func/identity"; import { $iter } from "../iterator"; import { isReduced } from "../reduced"; -export interface StreamSortOpts { - key: Fn; - compare: Comparator; -} - /** * Transducer. Similar to `partitionSort()`, however uses proper sliding * window and insertion sort instead of fully sorting window as done by @@ -26,15 +20,15 @@ export interface StreamSortOpts { * @param key * @param cmp */ -export function streamSort(n: number, opts?: Partial>): Transducer; +export function streamSort(n: number, opts?: Partial>): Transducer; export function streamSort(n: number, src: Iterable): IterableIterator; -export function streamSort(n: number, opts: Partial>, src: Iterable): IterableIterator; +export function streamSort(n: number, opts: Partial>, src: Iterable): IterableIterator; export function streamSort(...args: any[]): any { const iter = $iter(streamSort, args); if (iter) { return iter; } - const { key, compare } = >{ + const { key, compare } = >{ key: identity, compare: cmp, ...args[1] diff --git a/packages/transducers/src/xform/struct.ts b/packages/transducers/src/xform/struct.ts index 8815503de0..f0d77441ac 100644 --- a/packages/transducers/src/xform/struct.ts +++ b/packages/transducers/src/xform/struct.ts @@ -1,4 +1,4 @@ -import { StructField, Transducer } from "../api"; +import { Fn, Transducer } from "../api"; import { comp } from "../func/comp"; import { iterator } from "../iterator"; import { mapKeys } from "./map-keys"; @@ -6,6 +6,12 @@ import { partition } from "./partition"; import { partitionOf } from "./partition-of"; import { rename } from "./rename"; +export interface StructField extends Array { + [0]: string; + [1]: number; + [2]?: Fn; +} + /** * Higher-order transducer to converts linear input into structured objects * using given field specs and ordering. A single field spec is an array of From d130aaa18f3bea39f72b88916bac3a235bee2059 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 8 Aug 2018 23:55:52 +0100 Subject: [PATCH 24/68] build: fix transducer versions --- packages/associative/package.json | 2 +- packages/cache/package.json | 2 +- packages/dgraph/package.json | 2 +- packages/hdom-components/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/associative/package.json b/packages/associative/package.json index f9e66bc28a..ac851d44f0 100644 --- a/packages/associative/package.json +++ b/packages/associative/package.json @@ -34,7 +34,7 @@ "@thi.ng/dcons": "^1.0.7", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/transducers": "1.16.0" + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "data structures", diff --git a/packages/cache/package.json b/packages/cache/package.json index 840c5d9d1d..16f30f4c54 100644 --- a/packages/cache/package.json +++ b/packages/cache/package.json @@ -30,7 +30,7 @@ "dependencies": { "@thi.ng/api": "^4.0.6", "@thi.ng/dcons": "^1.0.7", - "@thi.ng/transducers": "1.16.0" + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "cache", diff --git a/packages/dgraph/package.json b/packages/dgraph/package.json index 5da979a877..e5cf2eb535 100644 --- a/packages/dgraph/package.json +++ b/packages/dgraph/package.json @@ -32,7 +32,7 @@ "@thi.ng/associative": "^0.5.11", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/transducers": "1.16.0" + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "data structure", diff --git a/packages/hdom-components/package.json b/packages/hdom-components/package.json index 8c82e1d1a2..56d2f53d5a 100644 --- a/packages/hdom-components/package.json +++ b/packages/hdom-components/package.json @@ -30,7 +30,7 @@ "dependencies": { "@thi.ng/api": "^4.0.6", "@thi.ng/checks": "^1.5.7", - "@thi.ng/transducers": "1.16.0", + "@thi.ng/transducers": "^1.16.0", "@types/webgl2": "^0.0.4" }, "keywords": [ From ab662d8ad51ce149d1ac0ede4fe492561a4cd977 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 01:42:39 +0100 Subject: [PATCH 25/68] perf(transducers): add iterator1(), update various xforms - iterator1() is speed optimized for 0-or-1 result xforms w/o completion step - update $iter to accept iterator impl --- packages/transducers/src/iterator.ts | 58 +++++++++++++++---- packages/transducers/src/xform/base64.ts | 6 +- packages/transducers/src/xform/benchmark.ts | 4 +- packages/transducers/src/xform/bits.ts | 6 +- packages/transducers/src/xform/convolve.ts | 4 +- packages/transducers/src/xform/drop-nth.ts | 4 +- packages/transducers/src/xform/drop.ts | 4 +- .../transducers/src/xform/filter-fuzzy.ts | 2 +- packages/transducers/src/xform/filter.ts | 4 +- packages/transducers/src/xform/hex-dump.ts | 2 +- packages/transducers/src/xform/labeled.ts | 4 +- packages/transducers/src/xform/map-deep.ts | 4 +- packages/transducers/src/xform/map.ts | 6 +- packages/transducers/src/xform/match-first.ts | 4 +- packages/transducers/src/xform/match-last.ts | 4 +- .../transducers/src/xform/moving-average.ts | 4 +- packages/transducers/src/xform/pad-last.ts | 10 ++-- .../transducers/src/xform/partition-bits.ts | 4 +- .../transducers/src/xform/partition-by.ts | 6 +- .../transducers/src/xform/partition-sort.ts | 4 +- .../transducers/src/xform/partition-sync.ts | 4 +- packages/transducers/src/xform/partition.ts | 4 +- packages/transducers/src/xform/pluck.ts | 6 +- packages/transducers/src/xform/sample.ts | 6 +- packages/transducers/src/xform/scan.ts | 4 +- packages/transducers/src/xform/select-keys.ts | 4 +- .../transducers/src/xform/stream-shuffle.ts | 4 +- packages/transducers/src/xform/stream-sort.ts | 4 +- packages/transducers/src/xform/swizzle.ts | 4 +- packages/transducers/src/xform/take-nth.ts | 4 +- .../transducers/src/xform/throttle-time.ts | 4 +- packages/transducers/src/xform/throttle.ts | 4 +- packages/transducers/src/xform/utf8.ts | 4 +- packages/transducers/src/xform/word-wrap.ts | 4 +- 34 files changed, 121 insertions(+), 83 deletions(-) diff --git a/packages/transducers/src/iterator.ts b/packages/transducers/src/iterator.ts index aebd96a0b6..40d3e6b5ce 100644 --- a/packages/transducers/src/iterator.ts +++ b/packages/transducers/src/iterator.ts @@ -1,29 +1,67 @@ import { isIterable } from "@thi.ng/checks/is-iterable"; -import { Reducer, Transducer } from "./api"; +import { Reducer, SEMAPHORE, Transducer } from "./api"; import { isReduced, unreduced } from "./reduced"; import { push } from "./rfn/push"; -export function* iterator(tx: Transducer, xs: Iterable): IterableIterator { - const [_, complete, reduce] = >tx(push()); _; +/** + * Takes a transducer and input iterable. Returns iterator of + * transformed results. + * + * @param xform + * @param xs + */ +export function* iterator(xform: Transducer, xs: Iterable): IterableIterator { + const [_, complete, reduce] = >xform(push()); _; for (let x of xs) { const y = reduce([], x); if (isReduced(y)) { - yield* unreduced(complete((y).deref())); + yield* unreduced(complete(y.deref())); return; } - if ((y).length) { - yield* (y); + if (y.length) { + yield* y; } } yield* unreduced(complete([])); } -export const $iter = (xform: (...xs: any[]) => Transducer, args: any[]) => { +/** + * Optimized version of `iterator()` for transducers which are guaranteed to: + * + * 1) Only produce none or a single result per input + * 2) Do not require a `completion` reduction step + * + * @param xform + * @param xs + */ +export function* iterator1(xform: Transducer, xs: Iterable): IterableIterator { + const reduce = (>xform([null, null, (acc, x) => (acc = x)]))[2]; + for (let x of xs) { + const y = reduce(SEMAPHORE, x); + if (isReduced(y)) { + yield unreduced(y.deref()); + return; + } + if (y !== SEMAPHORE) { + yield y; + } + } +} + +/** + * Helper function used by various transducers to wrap themselves as + * transforming iterators. Delegates to `iterator1()` by default. + * + * @param xform + * @param args + * @param impl + */ +export const $iter = (xform: (...xs: any[]) => Transducer, args: any[], impl = iterator1) => { const n = args.length - 1; return isIterable(args[n]) ? args.length > 1 ? - iterator(xform.apply(null, args.slice(0, n)), args[n]) : - iterator(xform(), args[0]) : + impl(xform.apply(null, args.slice(0, n)), args[n]) : + impl(xform(), args[0]) : undefined; -}; \ No newline at end of file +}; diff --git a/packages/transducers/src/xform/base64.ts b/packages/transducers/src/xform/base64.ts index df7d737129..db5e8b5d84 100644 --- a/packages/transducers/src/xform/base64.ts +++ b/packages/transducers/src/xform/base64.ts @@ -1,6 +1,6 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; -import { $iter, iterator } from "../iterator"; +import { $iter, iterator, iterator1 } from "../iterator"; import { isReduced, reduced } from "../reduced"; const B64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -14,7 +14,7 @@ export function base64Decode(): Transducer; export function base64Decode(src: string): IterableIterator; export function base64Decode(src?: string): any { return src ? - iterator(base64Decode(), src) : + iterator1(base64Decode(), src) : (rfn: Reducer) => { const r = rfn[2]; let bc = 0, bs = 0; @@ -61,7 +61,7 @@ export function base64Encode(opts: Partial): Transducer): IterableIterator; export function base64Encode(opts: Partial, src: Iterable): IterableIterator; export function base64Encode(...args: any[]): any { - return $iter(base64Encode, args) || + return $iter(base64Encode, args, iterator) || (([init, complete, reduce]: Reducer) => { let state = 0; let b: number; diff --git a/packages/transducers/src/xform/benchmark.ts b/packages/transducers/src/xform/benchmark.ts index 6d428a171c..3b6bad8f58 100644 --- a/packages/transducers/src/xform/benchmark.ts +++ b/packages/transducers/src/xform/benchmark.ts @@ -1,6 +1,6 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; /** * Stateful transducer. Ignores the actual input values, but @@ -21,7 +21,7 @@ export function benchmark(): Transducer; export function benchmark(src: Iterable): IterableIterator; export function benchmark(src?: Iterable): any { return src ? - iterator(benchmark(), src) : + iterator1(benchmark(), src) : (rfn: Reducer) => { const r = rfn[2]; let prev = Date.now(); diff --git a/packages/transducers/src/xform/bits.ts b/packages/transducers/src/xform/bits.ts index 67989187c8..52425140d2 100644 --- a/packages/transducers/src/xform/bits.ts +++ b/packages/transducers/src/xform/bits.ts @@ -1,6 +1,6 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; -import { $iter } from "../iterator"; +import { $iter, iterator } from "../iterator"; import { isReduced } from "../reduced"; /** @@ -9,7 +9,7 @@ import { isReduced } from "../reduced"; * lowest `wordSize` bits of each value are used (max 32). * * ``` - * [...iterator(bits(8), [0xf0, 0xaa])] + * [...bits(8, [0xf0, 0xaa])] * // [ 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0 ] * [...iterator(comp(bits(8), partition(4)), [0xf0, 0xaa])] * // [ [ 1, 1, 1, 1 ], [ 0, 0, 0, 0 ], [ 1, 0, 1, 0 ], [ 1, 0, 1, 0 ] ] @@ -23,7 +23,7 @@ export function bits(src: Iterable): IterableIterator; export function bits(size: number, src: Iterable): IterableIterator; export function bits(size: number, msb: boolean, src: Iterable): IterableIterator; export function bits(...args: any[]): any { - return $iter(bits, args) || + return $iter(bits, args, iterator) || ((rfn: Reducer) => { const reduce = rfn[2]; const size = (args[0] || 8) - 1; diff --git a/packages/transducers/src/xform/convolve.ts b/packages/transducers/src/xform/convolve.ts index 9b48a69f72..6953b56044 100644 --- a/packages/transducers/src/xform/convolve.ts +++ b/packages/transducers/src/xform/convolve.ts @@ -3,7 +3,7 @@ import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { Transducer } from "../api"; import { range2d } from "../iter/range2d"; import { tuples } from "../iter/tuples"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; import { add } from "../rfn/add"; import { transduce } from "../transduce"; import { map } from "./map"; @@ -54,7 +54,7 @@ export function convolve2d(opts: Convolution2DOpts): Transducer): IterableIterator; export function convolve2d(opts: Convolution2DOpts, _src?: Iterable): any { if (_src) { - return iterator(convolve2d(opts), _src); + return iterator1(convolve2d(opts), _src); } const { src, width, height } = opts; const wrap = opts.wrap !== false; diff --git a/packages/transducers/src/xform/drop-nth.ts b/packages/transducers/src/xform/drop-nth.ts index afb8513c7f..59951bb05a 100644 --- a/packages/transducers/src/xform/drop-nth.ts +++ b/packages/transducers/src/xform/drop-nth.ts @@ -1,12 +1,12 @@ import { Transducer } from "../api"; import { throttle } from "./throttle"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; export function dropNth(n: number): Transducer; export function dropNth(n: number, src: Iterable): IterableIterator; export function dropNth(n: number, src?: Iterable): any { if (src) { - return iterator(dropNth(n), src); + return iterator1(dropNth(n), src); } n = Math.max(0, n - 1); return throttle( diff --git a/packages/transducers/src/xform/drop.ts b/packages/transducers/src/xform/drop.ts index 548a7da386..57ed3dfec0 100644 --- a/packages/transducers/src/xform/drop.ts +++ b/packages/transducers/src/xform/drop.ts @@ -1,12 +1,12 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; export function drop(n: number): Transducer; export function drop(n: number, src: Iterable): IterableIterator; export function drop(n: number, src?: Iterable): any { return src ? - iterator(drop(n), src) : + iterator1(drop(n), src) : (rfn: Reducer) => { const r = rfn[2]; let m = n; diff --git a/packages/transducers/src/xform/filter-fuzzy.ts b/packages/transducers/src/xform/filter-fuzzy.ts index aae1ad14a8..c70e585fdc 100644 --- a/packages/transducers/src/xform/filter-fuzzy.ts +++ b/packages/transducers/src/xform/filter-fuzzy.ts @@ -18,7 +18,7 @@ export interface FilterFuzzyOpts { * @thi.ng/equiv by default. * * ``` - * [...iterator(filterFuzzy({query: "ho"}), ["hello", "hallo", "hey", "heyoka"])] + * [...filterFuzzy({query: "ho"}, ["hello", "hallo", "hey", "heyoka"])] * // ["hello", "hallo", "heyoka"] * ``` * diff --git a/packages/transducers/src/xform/filter.ts b/packages/transducers/src/xform/filter.ts index 6e154569d8..a876cedda1 100644 --- a/packages/transducers/src/xform/filter.ts +++ b/packages/transducers/src/xform/filter.ts @@ -1,14 +1,14 @@ import { Predicate } from "@thi.ng/api"; import { Reducer, Transducer } from "../api"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; import { compR } from "../func/compr"; export function filter(pred: Predicate): Transducer; export function filter(pred: Predicate, src: Iterable): IterableIterator; export function filter(pred: Predicate, src?: Iterable): any { return src ? - iterator(filter(pred), src) : + iterator1(filter(pred), src) : (rfn: Reducer) => { const r = rfn[2]; return compR(rfn, diff --git a/packages/transducers/src/xform/hex-dump.ts b/packages/transducers/src/xform/hex-dump.ts index 6eb23f59b1..4af3728085 100644 --- a/packages/transducers/src/xform/hex-dump.ts +++ b/packages/transducers/src/xform/hex-dump.ts @@ -31,7 +31,7 @@ export interface HexDumpOpts { * ``` * src = [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 33, 48, 49, 50, 51, 126, 122, 121, 120] * - * [...iterator(hexDump(8, 0x400), src)] + * [...hexDump({ cols: 8, address: 0x400 }, src)] * // [ '00000400 | 41 42 43 44 45 46 47 48 | ABCDEFGH', * // '00000408 | 49 4a 21 30 31 32 33 7e | IJ!0123~', * // '00000410 | 7a 79 78 00 00 00 00 00 | zyx.....' ] diff --git a/packages/transducers/src/xform/labeled.ts b/packages/transducers/src/xform/labeled.ts index 508af493d5..73341868ae 100644 --- a/packages/transducers/src/xform/labeled.ts +++ b/packages/transducers/src/xform/labeled.ts @@ -1,7 +1,7 @@ import { isFunction } from "@thi.ng/checks/is-function"; import { Transducer } from "../api"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; import { map } from "./map"; export type LabelFn = L | ((x: T) => L); @@ -10,7 +10,7 @@ export function labeled(id: LabelFn): Transducer; export function labeled(id: LabelFn, src: Iterable): IterableIterator<[L, T]>; export function labeled(id: LabelFn, src?: Iterable): any { return src ? - iterator(labeled(id), src) : + iterator1(labeled(id), src) : map( isFunction(id) ? (x: T) => [id(x), x] : diff --git a/packages/transducers/src/xform/map-deep.ts b/packages/transducers/src/xform/map-deep.ts index a4dc4596bd..8b8e1a29d4 100644 --- a/packages/transducers/src/xform/map-deep.ts +++ b/packages/transducers/src/xform/map-deep.ts @@ -1,6 +1,6 @@ import { Transducer, TransformSpec } from "../api"; import { deepTransform } from "../func/deep-transform"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; import { map } from "./map"; /** @@ -15,6 +15,6 @@ export function mapDeep(spec: TransformSpec): Transducer; export function mapDeep(spec: TransformSpec, src: Iterable): IterableIterator; export function mapDeep(spec: TransformSpec, src?: Iterable): any { return src ? - iterator(mapDeep(spec), src) : + iterator1(mapDeep(spec), src) : map(deepTransform(spec)); } diff --git a/packages/transducers/src/xform/map.ts b/packages/transducers/src/xform/map.ts index b79d37b0bc..501345c1c8 100644 --- a/packages/transducers/src/xform/map.ts +++ b/packages/transducers/src/xform/map.ts @@ -1,13 +1,13 @@ import { Fn, Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; /** * Transducer. Applies mapping function `fn` to each received value and * passes result downstream to next reducer. * * ``` - * [...iterator(map((x) => x * 10), [1, 2, 3])] + * [...map((x) => x * 10, [1, 2, 3])] * // [ 10, 20, 30 ] * ``` * @@ -17,7 +17,7 @@ export function map(fn: Fn): Transducer; export function map(fn: Fn, src: Iterable): IterableIterator export function map(fn: Fn, src?: Iterable): any { return src ? - iterator(map(fn), src) : + iterator1(map(fn), src) : (rfn: Reducer) => { const r = rfn[2]; return compR(rfn, (acc, x: A) => r(acc, fn(x))); diff --git a/packages/transducers/src/xform/match-first.ts b/packages/transducers/src/xform/match-first.ts index 512814496f..ebdf4ddcff 100644 --- a/packages/transducers/src/xform/match-first.ts +++ b/packages/transducers/src/xform/match-first.ts @@ -2,7 +2,7 @@ import { Predicate } from "@thi.ng/api"; import { Transducer } from "../api"; import { comp } from "../func/comp"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; import { filter } from "./filter"; import { take } from "./take"; @@ -22,6 +22,6 @@ export function matchFirst(pred: Predicate): Transducer; export function matchFirst(pred: Predicate, src: Iterable): IterableIterator; export function matchFirst(pred: Predicate, src?: Iterable): any { return src ? - iterator(matchFirst(pred), src) : + iterator1(matchFirst(pred), src) : comp(filter(pred), take(1)); } diff --git a/packages/transducers/src/xform/match-last.ts b/packages/transducers/src/xform/match-last.ts index 07e8723e3e..0771080a9a 100644 --- a/packages/transducers/src/xform/match-last.ts +++ b/packages/transducers/src/xform/match-last.ts @@ -2,7 +2,7 @@ import { Predicate } from "@thi.ng/api"; import { Transducer } from "../api"; import { comp } from "../func/comp"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; import { filter } from "./filter"; import { takeLast } from "./take-last"; @@ -22,6 +22,6 @@ export function matchLast(pred: Predicate): Transducer; export function matchLast(pred: Predicate, src: Iterable): IterableIterator; export function matchLast(pred: Predicate, src?: Iterable): any { return src ? - iterator(matchLast(pred), src) : + iterator1(matchLast(pred), src) : comp(filter(pred), takeLast(1)); } diff --git a/packages/transducers/src/xform/moving-average.ts b/packages/transducers/src/xform/moving-average.ts index ad4feb991a..3100013a3a 100644 --- a/packages/transducers/src/xform/moving-average.ts +++ b/packages/transducers/src/xform/moving-average.ts @@ -2,7 +2,7 @@ import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; /** * Computes the Simple Moving Average of given period. @@ -22,7 +22,7 @@ export function movingAverage(period: number): Transducer; export function movingAverage(period: number, src: Iterable): IterableIterator; export function movingAverage(period: number, src?: Iterable): any { return src ? - iterator(movingAverage(period), src) : + iterator1(movingAverage(period), src) : (rfn: Reducer) => { period |= 0; period < 2 && illegalArgs("period must be >= 2"); diff --git a/packages/transducers/src/xform/pad-last.ts b/packages/transducers/src/xform/pad-last.ts index db6f4a6405..8b367531e0 100644 --- a/packages/transducers/src/xform/pad-last.ts +++ b/packages/transducers/src/xform/pad-last.ts @@ -11,19 +11,19 @@ import { isReduced } from "../reduced"; * is empty, since length 0 is always a multiple. * * ``` - * [...iterator(padLast(8, 0), [1, 2, 3, 4, 5])] + * [...padLast(8, 0, [1, 2, 3, 4, 5])] * // [ 1, 2, 3, 4, 5, 0, 0, 0 ] * - * [...iterator(padLast(8, 0), [1])] + * [...padLast(8, 0, [1])] * // [ 1, 0, 0, 0, 0, 0, 0, 0 ] * - * [...iterator(padLast(8, 0), [])] + * [...padLast(8, 0, [])] * // [] * - * [...iterator(padLast(2, 0), [1, 2, 3])] + * [...padLast(2, 0, [1, 2, 3])] * // [ 1, 2, 3, 0 ] * - * [...iterator(padLast(2, 0), [1, 2, 3, 4])] + * [...padLast(2, 0, [1, 2, 3, 4])] * // [ 1, 2, 3, 4 ] * ``` * diff --git a/packages/transducers/src/xform/partition-bits.ts b/packages/transducers/src/xform/partition-bits.ts index ad651a61e8..88409fd690 100644 --- a/packages/transducers/src/xform/partition-bits.ts +++ b/packages/transducers/src/xform/partition-bits.ts @@ -1,5 +1,5 @@ import { Reducer, Transducer } from "../api"; -import { $iter } from "../iterator"; +import { $iter, iterator } from "../iterator"; import { isReduced } from "../reduced"; /** @@ -12,7 +12,7 @@ export function partitionBits(destSize: number, srcSize?: number): Transducer): IterableIterator; export function partitionBits(destSize: number, srcSize: number, src: Iterable): IterableIterator; export function partitionBits(...args: any[]): any { - return $iter(partitionBits, args) || + return $iter(partitionBits, args, iterator) || ((rfn: Reducer) => { const destSize = args[0]; const srcSize = args[1] || 8; diff --git a/packages/transducers/src/xform/partition-by.ts b/packages/transducers/src/xform/partition-by.ts index 05919ef0ac..56e7a398e6 100644 --- a/packages/transducers/src/xform/partition-by.ts +++ b/packages/transducers/src/xform/partition-by.ts @@ -1,5 +1,5 @@ import { Fn, SEMAPHORE, Transducer } from "../api"; -import { $iter } from "../iterator"; +import { $iter, iterator } from "../iterator"; import { isReduced } from "../reduced"; /** @@ -8,7 +8,7 @@ import { isReduced } from "../reduced"; * happens yields chunk of buffered values. * * ``` - * [...iterator(partitionBy((x) => x & 1), [1, 2, 4, 6, 3, 5, 8, 4])] + * [...partitionBy((x) => x & 1, [1, 2, 4, 6, 3, 5, 8, 4])] * // [ [ 1 ], [ 2, 4, 6 ], [ 3, 5 ], [ 8, 4 ] ] * ``` * @@ -19,7 +19,7 @@ export function partitionBy(fn: Fn | (() => Fn), stateful?: b export function partitionBy(fn: Fn | (() => Fn), src: Iterable): IterableIterator; export function partitionBy(fn: Fn | (() => Fn), stateful: boolean, src: Iterable): IterableIterator; export function partitionBy(...args: any[]): any { - return $iter(partitionBy, args) || + return $iter(partitionBy, args, iterator) || (([init, complete, reduce]) => { const fn: Fn | (() => Fn) = args[0]; const f = args[1] === true ? (<() => Fn>fn)() : fn; diff --git a/packages/transducers/src/xform/partition-sort.ts b/packages/transducers/src/xform/partition-sort.ts index f1fba964e6..625d3032c5 100644 --- a/packages/transducers/src/xform/partition-sort.ts +++ b/packages/transducers/src/xform/partition-sort.ts @@ -3,7 +3,7 @@ import { compare as cmp } from "@thi.ng/compare"; import { SortOpts, Transducer } from "../api"; import { comp } from "../func/comp"; import { identity } from "../func/identity"; -import { $iter } from "../iterator"; +import { $iter, iterator } from "../iterator"; import { mapcat } from "./mapcat"; import { partition } from "./partition"; @@ -37,7 +37,7 @@ export function partitionSort(n: number, opts?: Partial>): export function partitionSort(n: number, src: Iterable): IterableIterator; export function partitionSort(n: number, opts: Partial>, src: Iterable): IterableIterator; export function partitionSort(...args: any[]): any { - const iter = $iter(partitionSort, args); + const iter = $iter(partitionSort, args, iterator); if (iter) { return iter; } diff --git a/packages/transducers/src/xform/partition-sync.ts b/packages/transducers/src/xform/partition-sync.ts index dd1eecc29b..b6d5c09363 100644 --- a/packages/transducers/src/xform/partition-sync.ts +++ b/packages/transducers/src/xform/partition-sync.ts @@ -3,7 +3,7 @@ import { isArray } from "@thi.ng/checks/is-array"; import { Reducer, Transducer } from "../api"; import { identity } from "../func/identity"; -import { $iter } from "../iterator"; +import { $iter, iterator } from "../iterator"; export interface PartitionSyncOpts { key: (x: T) => PropertyKey; @@ -75,7 +75,7 @@ export function partitionSync(keys: PropertyKey[] | Set, opts?: export function partitionSync(keys: PropertyKey[] | Set, src: Iterable): IterableIterator>; export function partitionSync(keys: PropertyKey[] | Set, opts: Partial>, src: Iterable): IterableIterator>; export function partitionSync(...args: any[]): any { - return $iter(partitionSync, args) || + return $iter(partitionSync, args, iterator) || (([init, complete, reduce]: Reducer>) => { let curr = {}; let first = true; diff --git a/packages/transducers/src/xform/partition.ts b/packages/transducers/src/xform/partition.ts index 6189ef6c6e..3215220a93 100644 --- a/packages/transducers/src/xform/partition.ts +++ b/packages/transducers/src/xform/partition.ts @@ -1,5 +1,5 @@ import { Reducer, Transducer } from "../api"; -import { $iter } from "../iterator"; +import { $iter, iterator } from "../iterator"; /** * Transducer to create overlapping and non-overlapping sliding windows @@ -37,7 +37,7 @@ export function partition(size: number, all: boolean, src: Iterable): Iter export function partition(size: number, step: number, src: Iterable): IterableIterator; export function partition(size: number, step: number, all: boolean, src: Iterable): IterableIterator; export function partition(...args: any[]): any { - const iter = $iter(partition, args); + const iter = $iter(partition, args, iterator); if (iter) { return iter; } diff --git a/packages/transducers/src/xform/pluck.ts b/packages/transducers/src/xform/pluck.ts index 12abdc1cf8..1dd047d42a 100644 --- a/packages/transducers/src/xform/pluck.ts +++ b/packages/transducers/src/xform/pluck.ts @@ -1,5 +1,5 @@ import { Transducer } from "../api"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; import { map } from "./map"; /** @@ -7,7 +7,7 @@ import { map } from "./map"; * sequence of these values. * * ``` - * [...iterator(pluck("id"), [{id: 1}, {id: 2}, {}])] + * [...pluck("id", [{id: 1}, {id: 2}, {}])] * // [ 1, 2, undefined ] * ``` * @@ -17,6 +17,6 @@ export function pluck(key: PropertyKey): Transducer; export function pluck(key: PropertyKey, src: Iterable): IterableIterator; export function pluck(key: PropertyKey, src?: Iterable): any { return src ? - iterator(pluck(key), src) : + iterator1(pluck(key), src) : map((x: A) => x[key]); } diff --git a/packages/transducers/src/xform/sample.ts b/packages/transducers/src/xform/sample.ts index afa64109f8..51e3af2bdf 100644 --- a/packages/transducers/src/xform/sample.ts +++ b/packages/transducers/src/xform/sample.ts @@ -1,6 +1,6 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; /** * Transducer which only yields values with given `prob` probability @@ -8,7 +8,7 @@ import { iterator } from "../iterator"; * * ``` * // 10% probability - * [...iterator(sample(0.1), range(100))] + * [...sample(0.1, range(100))] * // [ 3, 24, 25, 36, 43, 49, 59, 64, 82, 86, 89 ] * ``` * @@ -19,7 +19,7 @@ export function sample(prob: number): Transducer; export function sample(prob: number, src: Iterable): IterableIterator; export function sample(prob: number, src?: Iterable): any { return src ? - iterator(sample(prob), src) : + iterator1(sample(prob), src) : (rfn: Reducer) => { const r = rfn[2]; return compR(rfn, diff --git a/packages/transducers/src/xform/scan.ts b/packages/transducers/src/xform/scan.ts index 8f9d5bcd80..bd77aba2ff 100644 --- a/packages/transducers/src/xform/scan.ts +++ b/packages/transducers/src/xform/scan.ts @@ -1,5 +1,5 @@ import { Reducer, Transducer } from "../api"; -import { $iter } from "../iterator"; +import { $iter, iterator } from "../iterator"; import { ensureReduced, isReduced, unreduced } from "../reduced"; /** @@ -25,7 +25,7 @@ import { ensureReduced, isReduced, unreduced } from "../reduced"; export function scan(rfn: Reducer, init?: B): Transducer; export function scan(rfn: Reducer, init: B, src: Iterable): IterableIterator; export function scan(...args: any[]): any { - return (args.length > 2 && $iter(scan, args)) || + return (args.length > 2 && $iter(scan, args, iterator)) || (([inito, completeo, reduceo]: Reducer) => { const [initi, completei, reducei]: Reducer = args[0]; let acc: B = args.length > 1 && args[1] != null ? args[1] : initi(); diff --git a/packages/transducers/src/xform/select-keys.ts b/packages/transducers/src/xform/select-keys.ts index b5dfcb54f4..6a5306f870 100644 --- a/packages/transducers/src/xform/select-keys.ts +++ b/packages/transducers/src/xform/select-keys.ts @@ -1,6 +1,6 @@ import { Transducer } from "../api"; import { keySelector } from "../func/key-selector"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; import { map } from "./map"; /** @@ -29,6 +29,6 @@ export function selectKeys(keys: PropertyKey[]): Transducer; export function selectKeys(keys: PropertyKey[], src: Iterable): IterableIterator; export function selectKeys(keys: PropertyKey[], src?: Iterable): any { return src ? - iterator(selectKeys(keys), src) : + iterator1(selectKeys(keys), src) : map(keySelector(keys)); } diff --git a/packages/transducers/src/xform/stream-shuffle.ts b/packages/transducers/src/xform/stream-shuffle.ts index d6902a8e61..b0472d45f3 100644 --- a/packages/transducers/src/xform/stream-shuffle.ts +++ b/packages/transducers/src/xform/stream-shuffle.ts @@ -1,6 +1,6 @@ import { Reducer, Transducer } from "../api"; import { shuffleN } from "../func/shuffle"; -import { $iter } from "../iterator"; +import { $iter, iterator } from "../iterator"; import { isReduced } from "../reduced"; /** @@ -21,7 +21,7 @@ export function streamShuffle(n: number, maxSwaps?: number): Transducer export function streamShuffle(n: number, src: Iterable): IterableIterator; export function streamShuffle(n: number, maxSwaps: number, src: Iterable): IterableIterator; export function streamShuffle(...args: any[]): any { - return $iter(streamShuffle, args) || + return $iter(streamShuffle, args, iterator) || (([init, complete, reduce]: Reducer) => { const n: number = args[0]; const maxSwaps: number = args[1] || n; diff --git a/packages/transducers/src/xform/stream-sort.ts b/packages/transducers/src/xform/stream-sort.ts index f7d332b8ea..935fd79ed3 100644 --- a/packages/transducers/src/xform/stream-sort.ts +++ b/packages/transducers/src/xform/stream-sort.ts @@ -3,7 +3,7 @@ import { compare as cmp } from "@thi.ng/compare"; import { Reducer, SortOpts, Transducer } from "../api"; import { binarySearch } from "../func/binary-search"; import { identity } from "../func/identity"; -import { $iter } from "../iterator"; +import { $iter, iterator } from "../iterator"; import { isReduced } from "../reduced"; /** @@ -24,7 +24,7 @@ export function streamSort(n: number, opts?: Partial>): Tra export function streamSort(n: number, src: Iterable): IterableIterator; export function streamSort(n: number, opts: Partial>, src: Iterable): IterableIterator; export function streamSort(...args: any[]): any { - const iter = $iter(streamSort, args); + const iter = $iter(streamSort, args, iterator); if (iter) { return iter; } diff --git a/packages/transducers/src/xform/swizzle.ts b/packages/transducers/src/xform/swizzle.ts index 9b13556c8a..62e5128e3f 100644 --- a/packages/transducers/src/xform/swizzle.ts +++ b/packages/transducers/src/xform/swizzle.ts @@ -1,6 +1,6 @@ import { Transducer } from "../api"; import { swizzler } from "../func/swizzler"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; import { map } from "./map"; /** @@ -27,6 +27,6 @@ export function swizzle(order: PropertyKey[]): Transducer; export function swizzle(order: PropertyKey[], src: Iterable): IterableIterator; export function swizzle(order: PropertyKey[], src?: Iterable): any { return src ? - iterator(swizzle(order), src) : + iterator1(swizzle(order), src) : map(swizzler(order)); } diff --git a/packages/transducers/src/xform/take-nth.ts b/packages/transducers/src/xform/take-nth.ts index feac92715c..016cbedc22 100644 --- a/packages/transducers/src/xform/take-nth.ts +++ b/packages/transducers/src/xform/take-nth.ts @@ -1,5 +1,5 @@ import { Transducer } from "../api"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; import { throttle } from "./throttle"; /** @@ -17,7 +17,7 @@ export function takeNth(n: number): Transducer; export function takeNth(n: number, src: Iterable): IterableIterator; export function takeNth(n: number, src?: Iterable): any { if (src) { - return iterator(takeNth(n), src); + return iterator1(takeNth(n), src); } n = Math.max(0, n - 1); return throttle( diff --git a/packages/transducers/src/xform/throttle-time.ts b/packages/transducers/src/xform/throttle-time.ts index 5d744cc79f..5195363416 100644 --- a/packages/transducers/src/xform/throttle-time.ts +++ b/packages/transducers/src/xform/throttle-time.ts @@ -1,5 +1,5 @@ import { Transducer } from "../api"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; import { throttle } from "./throttle"; /** @@ -16,7 +16,7 @@ export function throttleTime(delay: number): Transducer; export function throttleTime(delay: number, src: Iterable): IterableIterator; export function throttleTime(delay: number, src?: Iterable): any { return src ? - iterator(throttleTime(delay), src) : + iterator1(throttleTime(delay), src) : throttle( () => { let last = 0; diff --git a/packages/transducers/src/xform/throttle.ts b/packages/transducers/src/xform/throttle.ts index 8e5c4b5320..e8564cc139 100644 --- a/packages/transducers/src/xform/throttle.ts +++ b/packages/transducers/src/xform/throttle.ts @@ -2,7 +2,7 @@ import { StatefulPredicate } from "@thi.ng/api/api"; import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; -import { iterator } from "../iterator"; +import { iterator1 } from "../iterator"; /** * Similar to `filter`, but works with possibly stateful predicates @@ -24,7 +24,7 @@ export function throttle(pred: StatefulPredicate): Transducer; export function throttle(pred: StatefulPredicate, src: Iterable): IterableIterator; export function throttle(pred: StatefulPredicate, src?: Iterable): any { return src ? - iterator(throttle(pred), src) : + iterator1(throttle(pred), src) : (rfn: Reducer) => { const r = rfn[2]; const _pred = pred(); diff --git a/packages/transducers/src/xform/utf8.ts b/packages/transducers/src/xform/utf8.ts index b4c6e3d998..36e92fc34c 100644 --- a/packages/transducers/src/xform/utf8.ts +++ b/packages/transducers/src/xform/utf8.ts @@ -1,6 +1,6 @@ import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; -import { iterator } from "../iterator"; +import { iterator, iterator1 } from "../iterator"; import { isReduced } from "../reduced"; /** @@ -11,7 +11,7 @@ export function utf8Decode(): Transducer; export function utf8Decode(src: Iterable): string; export function utf8Decode(src?: Iterable): any { return src ? - [...iterator(utf8Decode(), src)].join("") : + [...iterator1(utf8Decode(), src)].join("") : (rfn: Reducer) => { const r = rfn[2]; let state = 0, u0, u1, u2, u3, u4; diff --git a/packages/transducers/src/xform/word-wrap.ts b/packages/transducers/src/xform/word-wrap.ts index b8c1eeacae..ebfee56302 100644 --- a/packages/transducers/src/xform/word-wrap.ts +++ b/packages/transducers/src/xform/word-wrap.ts @@ -1,5 +1,5 @@ import { Transducer } from "../api"; -import { $iter } from "../iterator"; +import { $iter, iterator } from "../iterator"; import { partitionBy } from "./partition-by"; export interface WordWrapOpts { @@ -24,7 +24,7 @@ export function wordWrap(lineLength: number, opts?: Partial): Tran export function wordWrap(lineLength: number, src: Iterable): IterableIterator; export function wordWrap(lineLength: number, opts: Partial, src: Iterable): IterableIterator; export function wordWrap(...args: any[]): any { - const iter = $iter(wordWrap, args); + const iter = $iter(wordWrap, args, iterator); if (iter) { return iter; } From c9ac981a9ca1942f43586e7fd5c24fefe03aeac5 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 02:57:42 +0100 Subject: [PATCH 26/68] feat(transducers-stats): make xforms iterable if input given --- packages/transducers-stats/src/bollinger.ts | 17 ++++++- packages/transducers-stats/src/donchian.ts | 12 +++-- packages/transducers-stats/src/ema.ts | 10 +++- packages/transducers-stats/src/hma.ts | 19 +++++--- packages/transducers-stats/src/macd.ts | 44 +++++++++-------- packages/transducers-stats/src/momentum.ts | 10 +++- packages/transducers-stats/src/roc.ts | 10 +++- packages/transducers-stats/src/rsi.ts | 27 +++++++---- packages/transducers-stats/src/sd.ts | 16 +++++- packages/transducers-stats/src/sma.ts | 12 +++-- packages/transducers-stats/src/stochastic.ts | 51 ++++++++++++-------- packages/transducers-stats/src/trix.ts | 20 +++++--- packages/transducers-stats/src/wma.ts | 10 +++- 13 files changed, 177 insertions(+), 81 deletions(-) diff --git a/packages/transducers-stats/src/bollinger.ts b/packages/transducers-stats/src/bollinger.ts index 0be29805b4..944547f04e 100644 --- a/packages/transducers-stats/src/bollinger.ts +++ b/packages/transducers-stats/src/bollinger.ts @@ -1,4 +1,5 @@ import { Transducer } from "@thi.ng/transducers/api"; +import { $iter } from "@thi.ng/transducers/iterator"; import { comp } from "@thi.ng/transducers/func/comp"; import { drop } from "@thi.ng/transducers/xform/drop"; import { map } from "@thi.ng/transducers/xform/map"; @@ -24,12 +25,24 @@ export interface BollingerBand { * number of processed inputs. * * @param period + * @param sd + * @param src */ -export function bollinger(period = 20, sd = 2): Transducer { +export function bollinger(period?: number, sd?: number): Transducer; +export function bollinger(src: Iterable): IterableIterator; +export function bollinger(period: number, src: Iterable): IterableIterator; +export function bollinger(period: number, sd: number, src: Iterable): IterableIterator; +export function bollinger(...args: any[]): any { + const iter = $iter(bollinger, args); + if (iter) { + return iter; + } + const period: number = args[0] || 20; + const sd: number = args[1] || 2; return comp( multiplex(partition(period, 1), sma(period)), drop(period - 1), - map(([window, mean]) => { + map(([window, mean]: [number[], number]) => { const std = Math.sqrt(mse(window, mean) / period) * sd; const min = mean - std; const max = mean + std; diff --git a/packages/transducers-stats/src/donchian.ts b/packages/transducers-stats/src/donchian.ts index 5f432e1220..10dc29094c 100644 --- a/packages/transducers-stats/src/donchian.ts +++ b/packages/transducers-stats/src/donchian.ts @@ -1,7 +1,8 @@ import { Transducer } from "@thi.ng/transducers/api"; import { comp } from "@thi.ng/transducers/func/comp"; -import { partition } from "@thi.ng/transducers/xform/partition"; +import { iterator } from "@thi.ng/transducers/iterator"; import { map } from "@thi.ng/transducers/xform/map"; +import { partition } from "@thi.ng/transducers/xform/partition"; import { bounds } from "./bounds"; @@ -14,7 +15,12 @@ import { bounds } from "./bounds"; * number of processed inputs. * * @param period + * @param src */ -export function donchian(period: number): Transducer { - return comp(partition(period, 1), map(bounds)); +export function donchian(period: number): Transducer; +export function donchian(period: number, src: Iterable): IterableIterator<[number, number]>; +export function donchian(period: number, src?: Iterable): any { + return src ? + iterator(donchian(period), src) : + comp(partition(period, 1), map(bounds)); }; diff --git a/packages/transducers-stats/src/ema.ts b/packages/transducers-stats/src/ema.ts index bcb19446f6..005e5f62fa 100644 --- a/packages/transducers-stats/src/ema.ts +++ b/packages/transducers-stats/src/ema.ts @@ -1,6 +1,7 @@ import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { Reducer, Transducer } from "@thi.ng/transducers/api"; import { compR } from "@thi.ng/transducers/func/compr"; +import { iterator1 } from "@thi.ng/transducers/iterator"; /** * https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average @@ -10,7 +11,12 @@ import { compR } from "@thi.ng/transducers/func/compr"; * * @param period */ -export function ema(period: number): Transducer { +export function ema(period: number): Transducer; +export function ema(period: number, src: Iterable): IterableIterator; +export function ema(period: number, src?: Iterable): any { + if (src) { + return iterator1(ema(period), src); + } period |= 0; period < 2 && illegalArgs("period must be >= 2"); const k = 2 / (period + 1); @@ -21,7 +27,7 @@ export function ema(period: number): Transducer { let ema: number; return compR( rfn, - (acc, x) => { + (acc, x: number) => { if (ema != null) { ema += (x - ema) * k; return rfn[2](acc, ema); diff --git a/packages/transducers-stats/src/hma.ts b/packages/transducers-stats/src/hma.ts index 06d8ab069a..ab70bd4282 100644 --- a/packages/transducers-stats/src/hma.ts +++ b/packages/transducers-stats/src/hma.ts @@ -1,5 +1,6 @@ import { Transducer } from "@thi.ng/transducers/api"; import { comp } from "@thi.ng/transducers/func/comp"; +import { iterator1 } from "@thi.ng/transducers/iterator"; import { drop } from "@thi.ng/transducers/xform/drop"; import { map } from "@thi.ng/transducers/xform/map"; import { multiplex } from "@thi.ng/transducers/xform/multiplex"; @@ -14,11 +15,15 @@ import { wma } from "./wma"; * * @param weights period or array of weights */ -export function hma(period: number): Transducer { - return comp( - multiplex(wma(period / 2 | 0), wma(period)), - drop(period - 1), - map((w) => 2 * w[0] - w[1]), - wma(Math.sqrt(period)) - ); +export function hma(period: number): Transducer; +export function hma(period: number, src: Iterable): IterableIterator; +export function hma(period: number, src?: Iterable): any { + return src ? + iterator1(hma(period), src) : + comp( + multiplex(wma(period / 2 | 0), wma(period)), + drop(period - 1), + map((w) => 2 * w[0] - w[1]), + wma(Math.sqrt(period)) + ); }; diff --git a/packages/transducers-stats/src/macd.ts b/packages/transducers-stats/src/macd.ts index f7003e97aa..c6206d4eb7 100644 --- a/packages/transducers-stats/src/macd.ts +++ b/packages/transducers-stats/src/macd.ts @@ -1,5 +1,6 @@ import { Reducer, Transducer } from "@thi.ng/transducers/api"; import { compR } from "@thi.ng/transducers/func/compr"; +import { $iter } from "@thi.ng/transducers/iterator"; import { step } from "@thi.ng/transducers/step"; import { ema } from "./ema"; @@ -40,22 +41,27 @@ export interface MACD { * @param slow slow EMA period * @param smooth signal smoothing EMA period */ -export const macd = (fast = 12, slow = 26, smooth = 9): Transducer => - (rfn: Reducer) => { - const reduce = rfn[2]; - const maFast = step(ema(fast)); - const maSlow = step(ema(slow)); - const maSmooth = step(ema(smooth)); - return compR( - rfn, - (acc, x) => { - const fast = maFast(x); - const slow = maSlow(x); - if (slow == null) return acc; - const macd = fast - slow; - const signal = maSmooth(macd); - if (signal == null) return acc; - return reduce(acc, { macd, signal, div: macd - signal, fast, slow }); - } - ); - }; +export function macd(fast?: number, slow?: number, smooth?: number): Transducer; +export function macd(src: Iterable): IterableIterator; +export function macd(fast: number, slow: number, smooth: number, src: Iterable): IterableIterator; +export function macd(...args: any[]): any { + return $iter(macd, args) || + ((rfn: Reducer) => { + const reduce = rfn[2]; + const maFast = step(ema(args[0] || 12)); + const maSlow = step(ema(args[1] || 26)); + const maSmooth = step(ema(args[2] || 9)); + return compR( + rfn, + (acc, x: number) => { + const fast = maFast(x); + const slow = maSlow(x); + if (slow == null) return acc; + const macd = fast - slow; + const signal = maSmooth(macd); + if (signal == null) return acc; + return reduce(acc, { macd, signal, div: macd - signal, fast, slow }); + } + ); + }); +} diff --git a/packages/transducers-stats/src/momentum.ts b/packages/transducers-stats/src/momentum.ts index 8cd9303baa..5273474dad 100644 --- a/packages/transducers-stats/src/momentum.ts +++ b/packages/transducers-stats/src/momentum.ts @@ -2,6 +2,7 @@ import { DCons } from "@thi.ng/dcons"; import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { Reducer, Transducer } from "@thi.ng/transducers/api"; import { compR } from "@thi.ng/transducers/func/compr"; +import { iterator1 } from "@thi.ng/transducers/iterator"; /** * https://en.wikipedia.org/wiki/Momentum_(technical_analysis) @@ -11,7 +12,12 @@ import { compR } from "@thi.ng/transducers/func/compr"; * * @param period */ -export function momentum(period: number): Transducer { +export function momentum(period: number): Transducer; +export function momentum(period: number, src: Iterable): IterableIterator; +export function momentum(period: number, src?: Iterable): any { + if (src) { + return iterator1(momentum(period), src); + } period |= 0; period < 1 && illegalArgs("period must be >= 1"); return (rfn: Reducer) => { @@ -19,7 +25,7 @@ export function momentum(period: number): Transducer { const window = new DCons(); return compR( rfn, - (acc, x) => { + (acc, x: number) => { window.push(x); if (window.length <= period) { return acc; diff --git a/packages/transducers-stats/src/roc.ts b/packages/transducers-stats/src/roc.ts index 4aef9476ea..b20dbf464a 100644 --- a/packages/transducers-stats/src/roc.ts +++ b/packages/transducers-stats/src/roc.ts @@ -2,6 +2,7 @@ import { DCons } from "@thi.ng/dcons"; import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { Reducer, Transducer } from "@thi.ng/transducers/api"; import { compR } from "@thi.ng/transducers/func/compr"; +import { iterator1 } from "@thi.ng/transducers/iterator"; /** * Rate of change. @@ -14,14 +15,19 @@ import { compR } from "@thi.ng/transducers/func/compr"; * * @param period */ -export function roc(period: number): Transducer { +export function roc(period: number): Transducer; +export function roc(period: number, src: Iterable): IterableIterator; +export function roc(period: number, src?: Iterable): any { + if (src) { + return iterator1(roc(period), src); + } period < 1 && illegalArgs("period must be >= 1"); return (rfn: Reducer) => { const reduce = rfn[2]; const window = new DCons(); return compR( rfn, - (acc, x) => { + (acc, x: number) => { window.push(x); if (window.length <= period) { return acc; diff --git a/packages/transducers-stats/src/rsi.ts b/packages/transducers-stats/src/rsi.ts index 83af4f0ce4..0f6fb8e38d 100644 --- a/packages/transducers-stats/src/rsi.ts +++ b/packages/transducers-stats/src/rsi.ts @@ -1,8 +1,10 @@ import { Transducer } from "@thi.ng/transducers/api"; import { comp } from "@thi.ng/transducers/func/comp"; +import { iterator1 } from "@thi.ng/transducers/iterator"; import { drop } from "@thi.ng/transducers/xform/drop"; import { map } from "@thi.ng/transducers/xform/map"; import { multiplex } from "@thi.ng/transducers/xform/multiplex"; + import { momentum } from "./momentum"; import { sma } from "./sma"; @@ -13,15 +15,20 @@ import { sma } from "./sma"; * number of processed inputs. * * @param period + * @param src */ -export function rsi(period: number): Transducer { - return comp( - momentum(1), - multiplex( - comp(map((x) => x > 0 ? x : 0), sma(period)), - comp(map((x) => x < 0 ? -x : 0), sma(period)), - ), - drop(period - 1), - map((hl) => 100 - 100 / (1 + hl[0] / Math.max(1e-6, hl[1]))) - ); +export function rsi(period: number): Transducer; +export function rsi(period: number, src: Iterable): IterableIterator; +export function rsi(period: number, src?: Iterable): any { + return src ? + iterator1(rsi(period), src) : + comp( + momentum(1), + multiplex( + comp(map((x) => x > 0 ? x : 0), sma(period)), + comp(map((x) => x < 0 ? -x : 0), sma(period)), + ), + drop(period - 1), + map((hl) => 100 - 100 / (1 + hl[0] / Math.max(1e-6, hl[1]))) + ); }; diff --git a/packages/transducers-stats/src/sd.ts b/packages/transducers-stats/src/sd.ts index c8c7861bc2..7c3ae0df08 100644 --- a/packages/transducers-stats/src/sd.ts +++ b/packages/transducers-stats/src/sd.ts @@ -7,6 +7,7 @@ import { partition } from "@thi.ng/transducers/xform/partition"; import { mse } from "./mse"; import { sma } from "./sma"; +import { $iter } from "@thi.ng/transducers/iterator"; /** * Moving standard deviation, calculates mean square error to SMA and @@ -18,11 +19,22 @@ import { sma } from "./sma"; * of processed inputs. * * @param period + * @param scale + * @param src */ -export function sd(period = 20, scale = 1): Transducer { +export function sd(period?: number, scale?: number): Transducer; +export function sd(src: Iterable): IterableIterator; +export function sd(period: number, scale: number, src: Iterable): IterableIterator; +export function sd(...args: any[]): any { + const iter = $iter(sd, args); + if (iter) { + return iter; + } + const period: number = args[0] || 20; + const scale: number = args[1] || 1; return comp( multiplex(partition(period, 1), sma(period)), drop(period - 1), - map(([window, mean]) => Math.sqrt(mse(window, mean) / period) * scale) + map(([window, mean]: [number[], number]) => Math.sqrt(mse(window, mean) / period) * scale) ); }; diff --git a/packages/transducers-stats/src/sma.ts b/packages/transducers-stats/src/sma.ts index bfefdf3381..b76353accd 100644 --- a/packages/transducers-stats/src/sma.ts +++ b/packages/transducers-stats/src/sma.ts @@ -2,6 +2,7 @@ import { DCons } from "@thi.ng/dcons"; import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { Reducer, Transducer } from "@thi.ng/transducers/api"; import { compR } from "@thi.ng/transducers/func/compr"; +import { iterator1 } from "@thi.ng/transducers/iterator"; /** * Like @thi.ng/transducers `movingAverage`, but using more efficient @@ -12,7 +13,12 @@ import { compR } from "@thi.ng/transducers/func/compr"; * * @param period */ -export function sma(period: number): Transducer { +export function sma(period: number): Transducer; +export function sma(period: number, src: Iterable): IterableIterator; +export function sma(period: number, src?: Iterable): any { + if (src) { + return iterator1(sma(period), src); + } period |= 0; period < 2 && illegalArgs("period must be >= 2"); return (rfn: Reducer) => { @@ -21,7 +27,7 @@ export function sma(period: number): Transducer { let sum = 0; return compR( rfn, - (acc, x) => { + (acc, x: number) => { window.push(x); const n = window.length; sum += x; @@ -29,5 +35,5 @@ export function sma(period: number): Transducer { return n >= period ? reduce(acc, sum / period) : acc; } ); - } + }; }; diff --git a/packages/transducers-stats/src/stochastic.ts b/packages/transducers-stats/src/stochastic.ts index 306ff5589c..e3c326de89 100644 --- a/packages/transducers-stats/src/stochastic.ts +++ b/packages/transducers-stats/src/stochastic.ts @@ -1,10 +1,17 @@ import { Reducer, Transducer } from "@thi.ng/transducers/api"; import { compR } from "@thi.ng/transducers/func/compr"; +import { $iter } from "@thi.ng/transducers/iterator"; import { step } from "@thi.ng/transducers/step"; import { donchian } from "./donchian"; import { sma } from "./sma"; +export interface Stochastic { + k: number; + d1: number; + d2: number; +} + /** * Stochastic oscillator. Yields tuples of `[%K, %D1, %D2]`, where: * @@ -18,24 +25,28 @@ import { sma } from "./sma"; * @param periodD1 * @param periodD2 */ -export function stochastic(periodK: number, periodD1: number, periodD2: number): Transducer { - return (rfn: Reducer) => { - const reduce = rfn[2]; - const xfD = step(donchian(periodK)); - const ma1 = step(sma(periodD1)); - const ma2 = step(sma(periodD2)); - return compR( - rfn, - (acc, x) => { - const b = xfD(x); - if (b == null) return acc; - const k = (x - b[0]) / (b[1] - b[0]); - const d1 = ma1(k); - if (d1 == null) return acc; - const d2 = ma2(d1); - if (d2 == null) return acc; - return reduce(acc, [k, d1, d2]); - } - ); - } +export function stochastic(periodK?: number, periodD1?: number, periodD2?: number): Transducer; +export function stochastic(src: Iterable): IterableIterator; +export function stochastic(periodK: number, periodD1: number, periodD2: number, src: Iterable): IterableIterator; +export function stochastic(...args: any[]): any { + return $iter(stochastic, args) || + ((rfn: Reducer) => { + const reduce = rfn[2]; + const xfD = step(donchian(args[0] || 5)); + const ma1 = step(sma(args[1] || 3)); + const ma2 = step(sma(args[2] || 3)); + return compR( + rfn, + (acc, x: number) => { + const b = xfD(x); + if (b == null) return acc; + const k = (x - b[0]) / (b[1] - b[0]); + const d1 = ma1(k); + if (d1 == null) return acc; + const d2 = ma2(d1); + if (d2 == null) return acc; + return reduce(acc, { k, d1, d2 }); + } + ); + }); } diff --git a/packages/transducers-stats/src/trix.ts b/packages/transducers-stats/src/trix.ts index b87e139cc8..15222027c8 100644 --- a/packages/transducers-stats/src/trix.ts +++ b/packages/transducers-stats/src/trix.ts @@ -1,5 +1,7 @@ import { Transducer } from "@thi.ng/transducers/api"; import { comp } from "@thi.ng/transducers/func/comp"; +import { iterator1 } from "@thi.ng/transducers/iterator"; + import { ema } from "./ema"; import { roc } from "./roc"; @@ -11,11 +13,15 @@ import { roc } from "./roc"; * * @param period */ -export function trix(period: number): Transducer { - return comp( - ema(period), - ema(period), - ema(period), - roc(1), - ); +export function trix(period: number): Transducer; +export function trix(period: number, src: Iterable): IterableIterator; +export function trix(period: number, src?: Iterable): any { + return src ? + iterator1(trix(period), src) : + comp( + ema(period), + ema(period), + ema(period), + roc(1), + ); }; diff --git a/packages/transducers-stats/src/wma.ts b/packages/transducers-stats/src/wma.ts index c18acbd44b..8b5c5dea53 100644 --- a/packages/transducers-stats/src/wma.ts +++ b/packages/transducers-stats/src/wma.ts @@ -2,6 +2,7 @@ import { isNumber } from "@thi.ng/checks/is-number"; import { Transducer } from "@thi.ng/transducers/api"; import { comp } from "@thi.ng/transducers/func/comp"; import { range } from "@thi.ng/transducers/iter/range"; +import { iterator1 } from "@thi.ng/transducers/iterator"; import { map } from "@thi.ng/transducers/xform/map"; import { partition } from "@thi.ng/transducers/xform/partition"; @@ -15,7 +16,12 @@ import { dot } from "./dot"; * * @param weights period or array of weights */ -export function wma(weights: number | number[]): Transducer { +export function wma(weights: number | number[]): Transducer; +export function wma(weights: number | number[], src: Iterable): IterableIterator; +export function wma(weights: number | number[], src?: Iterable): any { + if (src) { + return iterator1(wma(weights), src); + } let period, wsum; if (isNumber(weights)) { period = weights | 0; @@ -27,6 +33,6 @@ export function wma(weights: number | number[]): Transducer { } return comp( partition(period, 1), - map((window) => dot(window, weights) / wsum) + map((window: number[]) => dot(window, weights) / wsum) ); }; From cf30ba2654bc3961865f713d0c459b35a88cef13 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 17:30:26 +0100 Subject: [PATCH 27/68] feat(api): add new/move type aliases into api.ts - Fn, FnAny, Pair, SEMAPHORE --- packages/api/src/api.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/api/src/api.ts b/packages/api/src/api.ts index bd88b13385..32b3bd9749 100644 --- a/packages/api/src/api.ts +++ b/packages/api/src/api.ts @@ -4,6 +4,8 @@ export const EVENT_ALL = "*"; export const EVENT_ENABLE = "enable"; export const EVENT_DISABLE = "disable"; +export const SEMAPHORE = Symbol(); + /** * Generic 2-element comparator function type alias. Must follow this * contract and return: @@ -14,6 +16,16 @@ export const EVENT_DISABLE = "disable"; */ export type Comparator = (a: T, b: T) => number; +/** + * A single arg function from A => B. + */ +export type Fn = (x: A) => B; + +/** + * A vararg arg function to type T. + */ +export type FnAny = (...xs: any[]) => T; + /** * Event listener. */ @@ -24,6 +36,11 @@ export type Listener = (e: Event) => void; */ export type Path = PropertyKey | PropertyKey[]; +/** + * A key-value pair / tuple. + */ +export type Pair = [K, V]; + /** * Predicate function mapping given value to true/false. */ From c22ac3ce482439fa9a343a3b4734f9ba260a72f6 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 17:34:17 +0100 Subject: [PATCH 28/68] refactor(associative): replace Pair & SEMAPHORE w/ identical thi.ng/api defs --- packages/associative/src/api.ts | 4 ---- packages/associative/src/array-set.ts | 10 ++-------- packages/associative/src/equiv-map.ts | 11 ++++------- packages/associative/src/ll-set.ts | 11 +++-------- packages/associative/src/sorted-map.ts | 8 +++++--- packages/associative/src/sorted-set.ts | 4 ++-- 6 files changed, 16 insertions(+), 32 deletions(-) diff --git a/packages/associative/src/api.ts b/packages/associative/src/api.ts index e0bbed6a6a..bcb6d9c5cf 100644 --- a/packages/associative/src/api.ts +++ b/packages/associative/src/api.ts @@ -6,10 +6,6 @@ import { Predicate2 } from "@thi.ng/api/api"; -export type Pair = [K, V]; - -export const SEMAPHORE = Symbol("SEMAPHORE"); - export interface IEquivSet extends Set, ICopy>, diff --git a/packages/associative/src/array-set.ts b/packages/associative/src/array-set.ts index 8138cfe2c8..f6da3eeddf 100644 --- a/packages/associative/src/array-set.ts +++ b/packages/associative/src/array-set.ts @@ -1,12 +1,6 @@ -import { Predicate2 } from "@thi.ng/api/api"; +import { Pair, Predicate2, SEMAPHORE } from "@thi.ng/api/api"; import { equiv } from "@thi.ng/equiv"; - -import { - EquivSetOpts, - IEquivSet, - Pair, - SEMAPHORE -} from "./api"; +import { EquivSetOpts, IEquivSet } from "./api"; interface SetProps { vals: T[]; diff --git a/packages/associative/src/equiv-map.ts b/packages/associative/src/equiv-map.ts index ae7fc26b1c..e66f961a9b 100644 --- a/packages/associative/src/equiv-map.ts +++ b/packages/associative/src/equiv-map.ts @@ -2,16 +2,13 @@ import { ICopy, IEmpty, IEquiv, - IObjectOf + IObjectOf, + Pair, + SEMAPHORE } from "@thi.ng/api/api"; import { equiv } from "@thi.ng/equiv"; -import { - EquivMapOpts, - IEquivSet, - Pair, - SEMAPHORE -} from "./api"; +import { EquivMapOpts, IEquivSet } from "./api"; import { ArraySet } from "./array-set"; interface MapProps { diff --git a/packages/associative/src/ll-set.ts b/packages/associative/src/ll-set.ts index 1567a46a39..b537782cd6 100644 --- a/packages/associative/src/ll-set.ts +++ b/packages/associative/src/ll-set.ts @@ -1,13 +1,8 @@ -import { Predicate2 } from "@thi.ng/api/api"; -import { equiv } from "@thi.ng/equiv"; +import { Pair, Predicate2, SEMAPHORE } from "@thi.ng/api/api"; import { DCons } from "@thi.ng/dcons"; +import { equiv } from "@thi.ng/equiv"; -import { - EquivSetOpts, - IEquivSet, - Pair, - SEMAPHORE -} from "./api"; +import { EquivSetOpts, IEquivSet } from "./api"; interface SetProps { vals: DCons; diff --git a/packages/associative/src/sorted-map.ts b/packages/associative/src/sorted-map.ts index d3414e8256..12b7058cd2 100644 --- a/packages/associative/src/sorted-map.ts +++ b/packages/associative/src/sorted-map.ts @@ -5,15 +5,17 @@ import { IEmpty, IEquiv, IObjectOf, - Predicate2 + Pair, + Predicate2, + SEMAPHORE } from "@thi.ng/api/api"; +import { isArray } from "@thi.ng/checks/is-array"; import { compare } from "@thi.ng/compare"; import { equiv } from "@thi.ng/equiv"; import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; -import { isArray } from "@thi.ng/checks/is-array"; import { map } from "@thi.ng/transducers/xform/map"; -import { Pair, SEMAPHORE, SortedMapOpts } from "./api"; +import { SortedMapOpts } from "./api"; // stores private properties for all instances // http://fitzgeraldnick.com/2014/01/13/hiding-implementation-details-with-e6-weakmaps.html diff --git a/packages/associative/src/sorted-set.ts b/packages/associative/src/sorted-set.ts index d6ac47e278..10b6a9dc1d 100644 --- a/packages/associative/src/sorted-set.ts +++ b/packages/associative/src/sorted-set.ts @@ -1,8 +1,8 @@ -import { ICompare } from "@thi.ng/api/api"; +import { ICompare, Pair, } from "@thi.ng/api/api"; import { compare } from "@thi.ng/compare"; import { map } from "@thi.ng/transducers/xform/map"; -import { IEquivSet, Pair, SortedSetOpts } from "./api"; +import { IEquivSet, SortedSetOpts } from "./api"; import { SortedMap } from "./sorted-map"; const __private = new WeakMap, SortedMap>(); From 9b443cb4b52778d799c72064bc6b9ac9b4ff598e Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 17:35:05 +0100 Subject: [PATCH 29/68] refactor(hdom): replace SEMAPHORE const w/ thi.ng/api def --- packages/hdom/src/diff.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/hdom/src/diff.ts b/packages/hdom/src/diff.ts index 552d16a08a..9195b9fa2e 100644 --- a/packages/hdom/src/diff.ts +++ b/packages/hdom/src/diff.ts @@ -1,3 +1,4 @@ +import { SEMAPHORE } from "@thi.ng/api/api"; import * as isa from "@thi.ng/checks/is-array"; import * as iss from "@thi.ng/checks/is-string"; import { DiffLogEntry } from "@thi.ng/diff/api"; @@ -14,8 +15,6 @@ import { const isArray = isa.isArray; const isString = iss.isString; -const SEMAPHORE = Symbol(); - /** * Takes a DOM root element and two hiccup trees, `prev` and `curr`. * Recursively computes diff between both trees and applies any From bea7a1fd3d3dec51625f5281417d9ba4cdb62b1f Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 17:35:35 +0100 Subject: [PATCH 30/68] refactor(resolve-map): replace SEMAPHORE const w/ thi.ng/api def --- packages/resolve-map/src/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/resolve-map/src/index.ts b/packages/resolve-map/src/index.ts index f8ba4ba4b1..fbc66230f6 100644 --- a/packages/resolve-map/src/index.ts +++ b/packages/resolve-map/src/index.ts @@ -1,3 +1,4 @@ +import { SEMAPHORE } from "@thi.ng/api/api"; import { isArray } from "@thi.ng/checks/is-array"; import { isFunction } from "@thi.ng/checks/is-function"; import { isPlainObject } from "@thi.ng/checks/is-plain-object"; @@ -5,8 +6,6 @@ import { isString } from "@thi.ng/checks/is-string"; import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { getIn, mutIn } from "@thi.ng/paths"; -const SEMAPHORE = Symbol("SEMAPHORE"); - const RE_ARGS = /^(function\s+\w+)?\s*\(\{([\w\s,:]+)\}/ export type ResolveFn = (path: string) => any; From ca0a04e7b6954e44dfb3e6483381ea55dac8e9b2 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 17:37:35 +0100 Subject: [PATCH 31/68] feat(compose): extract comp() & juxt() to new @thi.ng/compose package - add compI() using reverse arg order of comp() --- packages/compose/.npmignore | 10 ++ packages/compose/LICENSE | 201 ++++++++++++++++++++++++++++ packages/compose/README.md | 44 ++++++ packages/compose/package.json | 43 ++++++ packages/compose/src/comp.ts | 58 ++++++++ packages/compose/src/index.ts | 2 + packages/compose/src/juxt.ts | 39 ++++++ packages/compose/test/index.ts | 6 + packages/compose/test/tsconfig.json | 10 ++ packages/compose/tsconfig.json | 9 ++ 10 files changed, 422 insertions(+) create mode 100644 packages/compose/.npmignore create mode 100644 packages/compose/LICENSE create mode 100644 packages/compose/README.md create mode 100644 packages/compose/package.json create mode 100644 packages/compose/src/comp.ts create mode 100644 packages/compose/src/index.ts create mode 100644 packages/compose/src/juxt.ts create mode 100644 packages/compose/test/index.ts create mode 100644 packages/compose/test/tsconfig.json create mode 100644 packages/compose/tsconfig.json diff --git a/packages/compose/.npmignore b/packages/compose/.npmignore new file mode 100644 index 0000000000..d703bda97a --- /dev/null +++ b/packages/compose/.npmignore @@ -0,0 +1,10 @@ +build +coverage +dev +doc +src* +test +.nyc_output +tsconfig.json +*.tgz +*.html diff --git a/packages/compose/LICENSE b/packages/compose/LICENSE new file mode 100644 index 0000000000..8dada3edaf --- /dev/null +++ b/packages/compose/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/compose/README.md b/packages/compose/README.md new file mode 100644 index 0000000000..bd0a07b06f --- /dev/null +++ b/packages/compose/README.md @@ -0,0 +1,44 @@ +# @thi.ng/compose + +[![npm (scoped)](https://img.shields.io/npm/v/@thi.ng/compose.svg)](https://www.npmjs.com/package/@thi.ng/compose) + +This project is part of the +[@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo. + + + +- [About](#about) +- [Installation](#installation) +- [Usage examples](#usage-examples) +- [Authors](#authors) +- [License](#license) + + + +## About + +Functional composition helpers: + +- [comp(...)](https://github.com/thi-ng/umbrella/tree/master/packages/compose/src/comp.ts) +- [compI(...)](https://github.com/thi-ng/umbrella/tree/master/packages/compose/src/comp.ts) +- [juxt(...)](https://github.com/thi-ng/umbrella/tree/master/packages/compose/src/juxt.ts) + +## Installation + +```bash +yarn add @thi.ng/compose +``` + +## Usage examples + +```ts +import { comp, compI, juxt } from "@thi.ng/compose"; +``` + +## Authors + +- Karsten Schmidt + +## License + +© 2018 Karsten Schmidt // Apache Software License 2.0 diff --git a/packages/compose/package.json b/packages/compose/package.json new file mode 100644 index 0000000000..34ac7e97e2 --- /dev/null +++ b/packages/compose/package.json @@ -0,0 +1,43 @@ +{ + "name": "@thi.ng/compose", + "version": "0.0.1", + "description": "TODO", + "main": "./index.js", + "typings": "./index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/thi-ng/umbrella.git" + }, + "homepage": "https://github.com/thi-ng/umbrella/tree/master/packages/compose", + "author": "Karsten Schmidt ", + "license": "Apache-2.0", + "scripts": { + "build": "yarn run clean && tsc --declaration", + "clean": "rm -rf *.js *.d.ts .nyc_output build coverage doc", + "cover": "yarn test && nyc report --reporter=lcov", + "doc": "node_modules/.bin/typedoc --mode modules --out doc src", + "pub": "yarn run build && yarn publish --access public", + "test": "rm -rf build && tsc -p test && nyc mocha build/test/*.js" + }, + "devDependencies": { + "@types/mocha": "^5.2.5", + "@types/node": "^10.5.5", + "mocha": "^5.2.0", + "nyc": "^12.0.2", + "typedoc": "^0.11.1", + "typescript": "^3.0.1" + }, + "dependencies": { + "@thi.ng/api": "^4.0.6", + "@thi.ng/errors": "^0.1.6" + }, + "keywords": [ + "composition", + "ES6", + "functional", + "typescript" + ], + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/packages/compose/src/comp.ts b/packages/compose/src/comp.ts new file mode 100644 index 0000000000..78d17174de --- /dev/null +++ b/packages/compose/src/comp.ts @@ -0,0 +1,58 @@ +import { Fn, FnAny } from "@thi.ng/api/api"; +import { illegalArity } from "@thi.ng/errors/illegal-arity"; + +export function comp(a: FnAny): FnAny; +export function comp(a: Fn, b: FnAny): FnAny; +export function comp(a: Fn, b: Fn, c: FnAny): FnAny; +export function comp(a: Fn, b: Fn, c: Fn, d: FnAny): FnAny; +export function comp(a: Fn, b: Fn, c: Fn, d: Fn, e: FnAny): FnAny; +export function comp(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: FnAny): FnAny; +export function comp(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: FnAny): FnAny; +export function comp(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn, h: FnAny): FnAny; +export function comp(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn, h: Fn, i: FnAny): FnAny; +export function comp(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn, h: Fn, i: Fn, j: FnAny): FnAny; +export function comp(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn, h: Fn, i: Fn, j: Fn, ...fns: FnAny[]): FnAny; +export function comp(...fns: any[]): any { + let [a, b, c, d, e, f, g, h, i, j] = fns; + switch (fns.length) { + case 0: + illegalArity(0); + case 1: + return a; + case 2: + return (...xs: any[]) => a(b(...xs)); + case 3: + return (...xs: any[]) => a(b(c(...xs))); + case 4: + return (...xs: any[]) => a(b(c(d(...xs)))); + case 5: + return (...xs: any[]) => a(b(c(d(e(...xs))))); + case 6: + return (...xs: any[]) => a(b(c(d(e(f(...xs)))))); + case 7: + return (...xs: any[]) => a(b(c(d(e(f(g(...xs))))))); + case 8: + return (...xs: any[]) => a(b(c(d(e(f(g(h(...xs)))))))); + case 9: + return (...xs: any[]) => a(b(c(d(e(f(g(h(i(...xs))))))))); + case 10: + default: + const fn = (...xs: any[]) => a(b(c(d(e(f(g(h(i(j(...xs)))))))))); + return fns.length === 10 ? fn : (compI)(fn, ...fns.slice(10)); + } +} + +export function compI(a: FnAny): FnAny; +export function compI(a: FnAny, b: Fn): FnAny; +export function compI(a: FnAny, b: Fn, c: Fn): FnAny; +export function compI(a: FnAny, b: Fn, c: Fn, d: Fn): FnAny; +export function compI(a: FnAny, b: Fn, c: Fn, d: Fn, e: Fn): FnAny; +export function compI(a: FnAny, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn): FnAny; +export function compI(a: FnAny, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn): FnAny; +export function compI(a: FnAny, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn, h: Fn): FnAny; +export function compI(a: FnAny, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn, h: Fn, i: Fn): FnAny; +export function compI(a: FnAny, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn, h: Fn, i: Fn, j: Fn): FnAny; +export function compI(a: FnAny, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn, h: Fn, i: Fn, j: Fn, ...xs: Fn[]): FnAny; +export function compI(...fns: any[]): any { + return comp.apply(null, fns.reverse()); +} diff --git a/packages/compose/src/index.ts b/packages/compose/src/index.ts new file mode 100644 index 0000000000..99ae4c440f --- /dev/null +++ b/packages/compose/src/index.ts @@ -0,0 +1,2 @@ +export * from "./comp"; +export * from "./juxt"; diff --git a/packages/compose/src/juxt.ts b/packages/compose/src/juxt.ts new file mode 100644 index 0000000000..7d6a94145c --- /dev/null +++ b/packages/compose/src/juxt.ts @@ -0,0 +1,39 @@ +import { Fn } from "@thi.ng/api/api"; + +export function juxt(a: Fn): Fn; +export function juxt(a: Fn, b: Fn): Fn; +export function juxt(a: Fn, b: Fn, c: Fn): Fn; +export function juxt(a: Fn, b: Fn, c: Fn, d: Fn): Fn; +export function juxt(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn): Fn; +export function juxt(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn): Fn; +export function juxt(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn): Fn; +export function juxt(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn, h: Fn): Fn; +export function juxt(...fns: Fn[]) { + const [a, b, c, d, e, f, g, h] = fns; + switch (fns.length) { + case 1: + return (x) => [a(x)]; + case 2: + return (x) => [a(x), b(x)]; + case 3: + return (x) => [a(x), b(x), c(x)]; + case 4: + return (x) => [a(x), b(x), c(x), d(x)]; + case 5: + return (x) => [a(x), b(x), c(x), d(x), e(x)]; + case 6: + return (x) => [a(x), b(x), c(x), d(x), e(x), f(x)]; + case 7: + return (x) => [a(x), b(x), c(x), d(x), e(x), f(x), g(x)]; + case 8: + return (x) => [a(x), b(x), c(x), d(x), e(x), f(x), g(x), h(x)]; + default: + return (x: any) => { + let res = new Array(fns.length); + for (let i = fns.length - 1; i >= 0; i--) { + res[i] = fns[i](x); + } + return res; + }; + } +} diff --git a/packages/compose/test/index.ts b/packages/compose/test/index.ts new file mode 100644 index 0000000000..1a976f7f80 --- /dev/null +++ b/packages/compose/test/index.ts @@ -0,0 +1,6 @@ +// import * as assert from "assert"; +// import * as compose from "../src/index"; + +describe("compose", () => { + it("tests pending"); +}); diff --git a/packages/compose/test/tsconfig.json b/packages/compose/test/tsconfig.json new file mode 100644 index 0000000000..bcf29ace54 --- /dev/null +++ b/packages/compose/test/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "../build" + }, + "include": [ + "./**/*.ts", + "../src/**/*.ts" + ] +} diff --git a/packages/compose/tsconfig.json b/packages/compose/tsconfig.json new file mode 100644 index 0000000000..bd6481a5a6 --- /dev/null +++ b/packages/compose/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "." + }, + "include": [ + "./src/**/*.ts" + ] +} From 3a8bd0883e4b8b026a9df9d1dd60820663d4cb31 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 17:45:50 +0100 Subject: [PATCH 32/68] refactor(transducers): replace local types w/ external defs - re-use Fn & SEMAPHORE (thi.ng/api) - replace comp() and juxt() (thi.ng/compose) --- packages/transducers/package.json | 1 + packages/transducers/src/api.ts | 6 +-- packages/transducers/src/func/comp.ts | 33 ++------------- packages/transducers/src/func/hex.ts | 4 +- packages/transducers/src/func/juxt.ts | 40 +------------------ packages/transducers/src/iterator.ts | 3 +- packages/transducers/src/xform/dedupe.ts | 4 +- .../transducers/src/xform/filter-fuzzy.ts | 4 +- packages/transducers/src/xform/hex-dump.ts | 4 +- packages/transducers/src/xform/map-keys.ts | 8 ++-- packages/transducers/src/xform/map-nth.ts | 4 +- packages/transducers/src/xform/map-vals.ts | 4 +- packages/transducers/src/xform/map.ts | 4 +- packages/transducers/src/xform/mapcat.ts | 4 +- packages/transducers/src/xform/match-first.ts | 2 +- .../transducers/src/xform/partition-by.ts | 4 +- packages/transducers/src/xform/struct.ts | 4 +- 17 files changed, 39 insertions(+), 94 deletions(-) diff --git a/packages/transducers/package.json b/packages/transducers/package.json index 525001a0e7..8ac68ee235 100644 --- a/packages/transducers/package.json +++ b/packages/transducers/package.json @@ -31,6 +31,7 @@ "@thi.ng/api": "^4.0.6", "@thi.ng/checks": "^1.5.7", "@thi.ng/compare": "^0.1.6", + "@thi.ng/compose": "^0.0.1", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", "@thi.ng/strings": "^0.1.1" diff --git a/packages/transducers/src/api.ts b/packages/transducers/src/api.ts index 0ad1a461c2..819fa24302 100644 --- a/packages/transducers/src/api.ts +++ b/packages/transducers/src/api.ts @@ -1,9 +1,7 @@ -import { Comparator, IObjectOf } from "@thi.ng/api/api"; +import { Comparator, Fn, IObjectOf } from "@thi.ng/api/api"; import { Reduced } from "./reduced"; -export type Fn = (x: A) => B; - export type Transducer = (rfn: Reducer) => Reducer; export type ReductionFn = (acc: A, x: B) => A | Reduced; @@ -33,5 +31,3 @@ export interface SortOpts { */ compare: Comparator; } - -export const SEMAPHORE = Symbol(); diff --git a/packages/transducers/src/func/comp.ts b/packages/transducers/src/func/comp.ts index c465c1ff53..28c3747252 100644 --- a/packages/transducers/src/func/comp.ts +++ b/packages/transducers/src/func/comp.ts @@ -1,4 +1,4 @@ -import { illegalArity } from "@thi.ng/errors/illegal-arity"; +import { comp as _comp } from "@thi.ng/compose"; import { Transducer } from "../api"; @@ -13,33 +13,6 @@ export function comp(a: Transducer, b: Transduc export function comp(a: Transducer, b: Transducer, c: Transducer, d: Transducer, e: Transducer, f: Transducer, g: Transducer, h: Transducer, i: Transducer): Transducer; export function comp(a: Transducer, b: Transducer, c: Transducer, d: Transducer, e: Transducer, f: Transducer, g: Transducer, h: Transducer, i: Transducer, j: Transducer): Transducer; export function comp(a: Transducer, b: Transducer, c: Transducer, d: Transducer, e: Transducer, f: Transducer, g: Transducer, h: Transducer, i: Transducer, j: Transducer, ...fns: Transducer[]): Transducer; -export function comp(...fns: ((x: any) => any)[]) { - let [a, b, c, d, e, f, g, h, i, j] = fns; - switch (fns.length) { - case 0: - illegalArity(0); - case 1: - return a; - case 2: - return (x) => a(b(x)); - case 3: - return (x) => a(b(c(x))); - case 4: - return (x) => a(b(c(d(x)))); - case 5: - return (x) => a(b(c(d(e(x))))); - case 6: - return (x) => a(b(c(d(e(f(x)))))); - case 7: - return (x) => a(b(c(d(e(f(g(x))))))); - case 8: - return (x) => a(b(c(d(e(f(g(h(x)))))))); - case 9: - return (x) => a(b(c(d(e(f(g(h(i(x))))))))); - case 10: - default: - let ff = (x) => a(b(c(d(e(f(g(h(i(j(x)))))))))); - // TODO TS2.7.* complains about args here? - return fns.length === 10 ? ff : (comp)(ff, ...fns.slice(10)); - } +export function comp(...fns: any[]) { + return _comp.apply(null, fns); } diff --git a/packages/transducers/src/func/hex.ts b/packages/transducers/src/func/hex.ts index 747161cedc..f0c60ec00d 100644 --- a/packages/transducers/src/func/hex.ts +++ b/packages/transducers/src/func/hex.ts @@ -1,3 +1,4 @@ +import { Stringer } from "@thi.ng/strings/api"; import { radix } from "@thi.ng/strings/radix"; /** @@ -6,4 +7,5 @@ import { radix } from "@thi.ng/strings/radix"; * @param digits * @param prefix */ -export const hex = (digits = 2, prefix = ""): (x: number) => string => radix(16, digits, prefix); +export const hex = (digits = 2, prefix = ""): Stringer => + radix(16, digits, prefix); diff --git a/packages/transducers/src/func/juxt.ts b/packages/transducers/src/func/juxt.ts index d3ab58ad0a..6c9a09f973 100644 --- a/packages/transducers/src/func/juxt.ts +++ b/packages/transducers/src/func/juxt.ts @@ -1,39 +1 @@ -import { Fn } from "../api"; - -export function juxt(a: Fn): Fn; -export function juxt(a: Fn, b: Fn): Fn; -export function juxt(a: Fn, b: Fn, c: Fn): Fn; -export function juxt(a: Fn, b: Fn, c: Fn, d: Fn): Fn; -export function juxt(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn): Fn; -export function juxt(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn): Fn; -export function juxt(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn): Fn; -export function juxt(a: Fn, b: Fn, c: Fn, d: Fn, e: Fn, f: Fn, g: Fn, h: Fn): Fn; -export function juxt(...fns: Fn[]) { - const [a, b, c, d, e, f, g, h] = fns; - switch (fns.length) { - case 1: - return (x) => [a(x)]; - case 2: - return (x) => [a(x), b(x)]; - case 3: - return (x) => [a(x), b(x), c(x)]; - case 4: - return (x) => [a(x), b(x), c(x), d(x)]; - case 5: - return (x) => [a(x), b(x), c(x), d(x), e(x)]; - case 6: - return (x) => [a(x), b(x), c(x), d(x), e(x), f(x)]; - case 7: - return (x) => [a(x), b(x), c(x), d(x), e(x), f(x), g(x)]; - case 8: - return (x) => [a(x), b(x), c(x), d(x), e(x), f(x), g(x), h(x)]; - default: - return function (x) { - let res = new Array(fns.length); - for (let i = fns.length - 1; i >= 0; i--) { - res[i] = fns[i](x); - } - return res; - }; - } -} +export * from "@thi.ng/compose/juxt"; diff --git a/packages/transducers/src/iterator.ts b/packages/transducers/src/iterator.ts index 40d3e6b5ce..50b0aaac59 100644 --- a/packages/transducers/src/iterator.ts +++ b/packages/transducers/src/iterator.ts @@ -1,6 +1,7 @@ +import { SEMAPHORE } from "@thi.ng/api/api"; import { isIterable } from "@thi.ng/checks/is-iterable"; -import { Reducer, SEMAPHORE, Transducer } from "./api"; +import { Reducer, Transducer } from "./api"; import { isReduced, unreduced } from "./reduced"; import { push } from "./rfn/push"; diff --git a/packages/transducers/src/xform/dedupe.ts b/packages/transducers/src/xform/dedupe.ts index 59a005cbfb..9834e7bb89 100644 --- a/packages/transducers/src/xform/dedupe.ts +++ b/packages/transducers/src/xform/dedupe.ts @@ -1,6 +1,6 @@ -import { Predicate2 } from "@thi.ng/api/api"; +import { Predicate2, SEMAPHORE } from "@thi.ng/api/api"; -import { Reducer, SEMAPHORE, Transducer } from "../api"; +import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; import { $iter } from "../iterator"; diff --git a/packages/transducers/src/xform/filter-fuzzy.ts b/packages/transducers/src/xform/filter-fuzzy.ts index c70e585fdc..13d91830c3 100644 --- a/packages/transducers/src/xform/filter-fuzzy.ts +++ b/packages/transducers/src/xform/filter-fuzzy.ts @@ -1,6 +1,6 @@ -import { Predicate2 } from "@thi.ng/api/api"; +import { Fn, Predicate2 } from "@thi.ng/api/api"; -import { Fn, Transducer } from "../api"; +import { Transducer } from "../api"; import { fuzzyMatch } from "../func/fuzzy-match"; import { $iter } from "../iterator"; import { filter } from "./filter"; diff --git a/packages/transducers/src/xform/hex-dump.ts b/packages/transducers/src/xform/hex-dump.ts index 4af3728085..a25491038d 100644 --- a/packages/transducers/src/xform/hex-dump.ts +++ b/packages/transducers/src/xform/hex-dump.ts @@ -54,8 +54,8 @@ export function hexDump(...args: any[]): any { partition(cols, true), map( juxt( - (x) => x.map((y) => y[0]).join(" "), - (x) => x.map((y) => y[1]).join("") + (x: string[][]) => x.map((y) => y[0]).join(" "), + (x: string[][]) => x.map((y) => y[1]).join("") ) ), mapIndexed((i, [h, a]) => `${U32(address + i * cols)} | ${h} | ${a}`) diff --git a/packages/transducers/src/xform/map-keys.ts b/packages/transducers/src/xform/map-keys.ts index f9e4d76d19..ff646a9b03 100644 --- a/packages/transducers/src/xform/map-keys.ts +++ b/packages/transducers/src/xform/map-keys.ts @@ -1,4 +1,4 @@ -import { IObjectOf } from "@thi.ng/api/api"; +import { Fn, IObjectOf } from "@thi.ng/api/api"; import { Transducer } from "../api"; import { $iter } from "../iterator"; @@ -26,9 +26,9 @@ import { map } from "./map"; * @param copy if true (default), creates a shallow copy of each incoming value * @param src */ -export function mapKeys(keys: IObjectOf<(x: any) => any>, copy?: boolean): Transducer; -export function mapKeys(keys: IObjectOf<(x: any) => any>, src: Iterable): IterableIterator; -export function mapKeys(keys: IObjectOf<(x: any) => any>, copy: boolean, src: Iterable): IterableIterator; +export function mapKeys(keys: IObjectOf>, copy?: boolean): Transducer; +export function mapKeys(keys: IObjectOf>, src: Iterable): IterableIterator; +export function mapKeys(keys: IObjectOf>, copy: boolean, src: Iterable): IterableIterator; export function mapKeys(...args: any[]): any { const iter = $iter(mapKeys, args); if (iter) { diff --git a/packages/transducers/src/xform/map-nth.ts b/packages/transducers/src/xform/map-nth.ts index ed4515e22d..cc2750b894 100644 --- a/packages/transducers/src/xform/map-nth.ts +++ b/packages/transducers/src/xform/map-nth.ts @@ -1,4 +1,6 @@ -import { Fn, Reducer, Transducer } from "../api"; +import { Fn } from "@thi.ng/api/api"; + +import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; import { $iter } from "../iterator"; diff --git a/packages/transducers/src/xform/map-vals.ts b/packages/transducers/src/xform/map-vals.ts index 02cb350e3a..90eb39f13d 100644 --- a/packages/transducers/src/xform/map-vals.ts +++ b/packages/transducers/src/xform/map-vals.ts @@ -1,6 +1,6 @@ -import { IObjectOf } from "@thi.ng/api/api"; +import { Fn, IObjectOf } from "@thi.ng/api/api"; -import { Fn, Transducer } from "../api"; +import { Transducer } from "../api"; import { $iter } from "../iterator"; import { map } from "./map"; diff --git a/packages/transducers/src/xform/map.ts b/packages/transducers/src/xform/map.ts index 501345c1c8..3a409a5247 100644 --- a/packages/transducers/src/xform/map.ts +++ b/packages/transducers/src/xform/map.ts @@ -1,4 +1,6 @@ -import { Fn, Reducer, Transducer } from "../api"; +import { Fn } from "@thi.ng/api/api"; + +import { Reducer, Transducer } from "../api"; import { compR } from "../func/compr"; import { iterator1 } from "../iterator"; diff --git a/packages/transducers/src/xform/mapcat.ts b/packages/transducers/src/xform/mapcat.ts index 1f1771a95e..5038dac1a6 100644 --- a/packages/transducers/src/xform/mapcat.ts +++ b/packages/transducers/src/xform/mapcat.ts @@ -1,4 +1,6 @@ -import { Fn, Transducer } from "../api"; +import { Fn } from "@thi.ng/api/api"; + +import { Transducer } from "../api"; import { comp } from "../func/comp"; import { iterator } from "../iterator"; import { cat } from "./cat"; diff --git a/packages/transducers/src/xform/match-first.ts b/packages/transducers/src/xform/match-first.ts index ebdf4ddcff..ac28647196 100644 --- a/packages/transducers/src/xform/match-first.ts +++ b/packages/transducers/src/xform/match-first.ts @@ -22,6 +22,6 @@ export function matchFirst(pred: Predicate): Transducer; export function matchFirst(pred: Predicate, src: Iterable): IterableIterator; export function matchFirst(pred: Predicate, src?: Iterable): any { return src ? - iterator1(matchFirst(pred), src) : + [...iterator1(matchFirst(pred), src)][0] : comp(filter(pred), take(1)); } diff --git a/packages/transducers/src/xform/partition-by.ts b/packages/transducers/src/xform/partition-by.ts index 56e7a398e6..d40fd7b025 100644 --- a/packages/transducers/src/xform/partition-by.ts +++ b/packages/transducers/src/xform/partition-by.ts @@ -1,4 +1,6 @@ -import { Fn, SEMAPHORE, Transducer } from "../api"; +import { Fn, SEMAPHORE } from "@thi.ng/api/api"; + +import { Transducer } from "../api"; import { $iter, iterator } from "../iterator"; import { isReduced } from "../reduced"; diff --git a/packages/transducers/src/xform/struct.ts b/packages/transducers/src/xform/struct.ts index f0d77441ac..577f0078c6 100644 --- a/packages/transducers/src/xform/struct.ts +++ b/packages/transducers/src/xform/struct.ts @@ -1,4 +1,6 @@ -import { Fn, Transducer } from "../api"; +import { Fn } from "@thi.ng/api/api"; + +import { Transducer } from "../api"; import { comp } from "../func/comp"; import { iterator } from "../iterator"; import { mapKeys } from "./map-keys"; From 1a20bc2f6beb39f6dbbce49e3efd9c9bf74abfc9 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 17:47:02 +0100 Subject: [PATCH 33/68] feat(strings): add truncateLeft() & wrap() stringers --- packages/strings/src/truncate-left.ts | 12 ++++++++++++ packages/strings/src/wrap.ts | 10 ++++++++++ 2 files changed, 22 insertions(+) create mode 100644 packages/strings/src/truncate-left.ts create mode 100644 packages/strings/src/wrap.ts diff --git a/packages/strings/src/truncate-left.ts b/packages/strings/src/truncate-left.ts new file mode 100644 index 0000000000..27f0d44371 --- /dev/null +++ b/packages/strings/src/truncate-left.ts @@ -0,0 +1,12 @@ +import { memoizeJ } from "@thi.ng/memoize/memoizej"; + +import { Stringer } from "./api"; + +export const truncateLeft: (n: number, prefix?: string) => Stringer = + memoizeJ( + (n: number, prefix = "") => + (x) => + x.length > n ? + prefix + x.substr(x.length - n + prefix.length) : + x + ); diff --git a/packages/strings/src/wrap.ts b/packages/strings/src/wrap.ts new file mode 100644 index 0000000000..95df096538 --- /dev/null +++ b/packages/strings/src/wrap.ts @@ -0,0 +1,10 @@ +import { memoizeJ } from "@thi.ng/memoize/memoizej"; + +import { Stringer } from "./api"; + +/** + * Returns a `Stringer` which wrap inputs with given `pad` string on + * both sides. + */ +export const wrap: (pad: string) => Stringer = + memoizeJ((pad: string) => (x: any) => pad + x + pad); From 5209c42648cae5a764f9fef027a6c38ea2565d11 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 17:48:51 +0100 Subject: [PATCH 34/68] fix(strings): buffer length (for null inputs) (`center()`) - also truncate oversized inputs --- packages/strings/src/center.ts | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/strings/src/center.ts b/packages/strings/src/center.ts index 82e4fa586d..23aa06c956 100644 --- a/packages/strings/src/center.ts +++ b/packages/strings/src/center.ts @@ -2,20 +2,35 @@ import { memoizeJ } from "@thi.ng/memoize/memoizej"; import { Stringer } from "./api"; import { repeat } from "./repeat"; +import { truncate } from "./truncate"; /** - * @param n target length + * Returns stringer which pads given input with `ch` (default: space) on + * both sides and returns fixed width string of given `lineWidth`. + * Returns string of only pad characters for any `null` or `undefined` + * values. If the string version of an input is > `lineWidth`, no + * centering is performed, but the string will be truncated to + * `lineWidth`. + * + * Note: The padding string can contain multiple characters. + * + * ``` + * center(20, "<>")(wrap(" ")("thi.ng")) + * // "<><><> thi.ng <><><>" + * ``` + * + * @param lineWidth target length * @param ch pad character(s) */ -export const center: (n: number, ch?: string | number) => Stringer = +export const center: (lineWidth: number, ch?: string | number) => Stringer = memoizeJ>((n, ch = " ") => { - const buf = repeat(ch, ((n + 1) & ~1) / 2); + const buf = repeat(ch, n); return (x: any) => { if (x == null) return buf; x = x.toString(); const r = (n - x.length) / 2; return x.length < n ? buf.substr(0, r) + x + buf.substr(0, r + ((n & 1) === (x.length & 1) ? 0 : 1)) : - x; + truncate(n)(x); } }); From 653a175a636b5d1d4461fcea65b18766be57d7a2 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 17:49:32 +0100 Subject: [PATCH 35/68] feat(strings): add case converters - camel / kebab / snake --- packages/strings/src/case.ts | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/strings/src/case.ts b/packages/strings/src/case.ts index 53cd218387..7bccb526d5 100644 --- a/packages/strings/src/case.ts +++ b/packages/strings/src/case.ts @@ -23,3 +23,40 @@ export const lower: Stringer = */ export const capitalize: Stringer = (x: string) => x[0].toUpperCase() + x.substr(1); + +/** + * Converts a CamelCase string into kebab case, with optional custom + * delimiter (`-` by default). + * + * ``` + * kebab("FooBar23Baz"); + * // "foo-bar23-baz" + * ``` + * + * @param x + * @param delim + */ +export const kebab: Stringer = + (x: string, delim = "-") => + lower(x.replace(/(?<=\w)(?=[A-Z])/g, delim)); + +/** + * Short for `kebab` using `_` as delimiter. + * + * @param x + */ +export const snake = (x: string) => kebab(x, "_"); + +/** + * Converts a kebab-case or snake_case string into CamelCase. Uses `-` + * as default delimiter. + * + * @param x + * @param delim + */ +export const camel: Stringer = + (x: string, delim = "-") => + lower(x).replace( + new RegExp(`\\${delim}+(\\w)`, "g"), + (_, c) => upper(c) + ); From e9c8ddc6ef39a0685bec3ef58bdc68a278c2a672 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 17:49:57 +0100 Subject: [PATCH 36/68] chore(strings): update exports, add docs --- packages/strings/src/api.ts | 2 +- packages/strings/src/index.ts | 2 ++ packages/strings/src/radix.ts | 23 +++++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/strings/src/api.ts b/packages/strings/src/api.ts index f7b027b5bb..a1e22b34e3 100644 --- a/packages/strings/src/api.ts +++ b/packages/strings/src/api.ts @@ -1 +1 @@ -export type Stringer = (x: T) => string; +export type Stringer = (x: T, ...xs: any[]) => string; diff --git a/packages/strings/src/index.ts b/packages/strings/src/index.ts index 6abe1783b5..8b09d3e2d0 100644 --- a/packages/strings/src/index.ts +++ b/packages/strings/src/index.ts @@ -10,3 +10,5 @@ export * from "./percent"; export * from "./radix"; export * from "./repeat"; export * from "./truncate"; +export * from "./truncate-left"; +export * from "./wrap"; diff --git a/packages/strings/src/radix.ts b/packages/strings/src/radix.ts index 61f81ffd29..1bcc321402 100644 --- a/packages/strings/src/radix.ts +++ b/packages/strings/src/radix.ts @@ -22,8 +22,31 @@ export const radix: (radix: number, len: number, prefix?: string) => Stringer U32(hi) + U32(lo); From f3d464600f7427671d2df61d4ff197fd5c83d3f8 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 18:03:53 +0100 Subject: [PATCH 37/68] refactor(rstream): use SEMAPHORE from thi.ng/api, not transducers --- packages/rstream/src/subscription.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rstream/src/subscription.ts b/packages/rstream/src/subscription.ts index 12a1304f29..0d4fc8caa3 100644 --- a/packages/rstream/src/subscription.ts +++ b/packages/rstream/src/subscription.ts @@ -1,10 +1,10 @@ -import { IDeref } from "@thi.ng/api/api"; +import { IDeref, SEMAPHORE } from "@thi.ng/api/api"; import { implementsFunction } from "@thi.ng/checks/implements-function"; import { isFunction } from "@thi.ng/checks/is-function"; import { isString } from "@thi.ng/checks/is-string"; import { illegalArity } from "@thi.ng/errors/illegal-arity"; import { illegalState } from "@thi.ng/errors/illegal-state"; -import { Reducer, SEMAPHORE, Transducer } from "@thi.ng/transducers/api"; +import { Reducer, Transducer } from "@thi.ng/transducers/api"; import { comp } from "@thi.ng/transducers/func/comp"; import { isReduced, unreduced } from "@thi.ng/transducers/reduced"; import { push } from "@thi.ng/transducers/rfn/push"; From 802c5b444282c7d963c972c24c000ce3174cd0e9 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 18:04:42 +0100 Subject: [PATCH 38/68] build(memoize): update/fix dev deps --- packages/memoize/package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/memoize/package.json b/packages/memoize/package.json index 887336eb4f..d3aa5ad67d 100644 --- a/packages/memoize/package.json +++ b/packages/memoize/package.json @@ -20,8 +20,6 @@ "test": "rm -rf build && tsc -p test && nyc mocha build/test/*.js" }, "devDependencies": { - "@thi.ng/associative": "^0.5.11", - "@thi.ng/cache": "^0.2.15", "@types/mocha": "^5.2.5", "@types/node": "^10.5.5", "mocha": "^5.2.0", @@ -42,4 +40,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file From 1434b0ed3d1866715133b209e835a9e1ac024929 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 18:10:54 +0100 Subject: [PATCH 39/68] refactor(hdom): remove thi.ng/iterators dependency --- packages/hdom/package.json | 5 ++--- packages/hdom/src/dom.ts | 7 +++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/hdom/package.json b/packages/hdom/package.json index e3178131b1..5a08034708 100644 --- a/packages/hdom/package.json +++ b/packages/hdom/package.json @@ -33,8 +33,7 @@ "@thi.ng/checks": "^1.5.7", "@thi.ng/diff": "^1.0.21", "@thi.ng/equiv": "^0.1.7", - "@thi.ng/hiccup": "^2.0.9", - "@thi.ng/iterators": "^4.1.20" + "@thi.ng/hiccup": "^2.0.9" }, "keywords": [ "browser", @@ -49,4 +48,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/packages/hdom/src/dom.ts b/packages/hdom/src/dom.ts index 78d150d318..d9706d9d20 100644 --- a/packages/hdom/src/dom.ts +++ b/packages/hdom/src/dom.ts @@ -4,7 +4,6 @@ import * as isi from "@thi.ng/checks/is-iterable"; import * as iss from "@thi.ng/checks/is-string"; import { SVG_NS, SVG_TAGS } from "@thi.ng/hiccup/api"; import { css } from "@thi.ng/hiccup/css"; -import { map } from "@thi.ng/iterators/map"; const isArray = isa.isArray; const isFunction = isf.isFunction; @@ -43,7 +42,11 @@ export function createDOM(parent: Element, tag: any, insert?: number) { return el; } if (!isString(tag) && isIterable(tag)) { - return [...(map((x) => createDOM(parent, x), tag))]; + const res = []; + for (let t of tag) { + res.push(createDOM(parent, t)); + } + return res; } if (tag == null) { return parent; From 3e65918136d2a2fc5b616ad5aa77865f3f879b6b Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 18:15:05 +0100 Subject: [PATCH 40/68] minor(transducers): fix comp import --- packages/transducers/src/func/comp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/transducers/src/func/comp.ts b/packages/transducers/src/func/comp.ts index 28c3747252..8e17710c1c 100644 --- a/packages/transducers/src/func/comp.ts +++ b/packages/transducers/src/func/comp.ts @@ -1,4 +1,4 @@ -import { comp as _comp } from "@thi.ng/compose"; +import { comp as _comp } from "@thi.ng/compose/comp"; import { Transducer } from "../api"; From 4fdd3c92b5e5a14014594566327fa2a92e4009d7 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 18:19:47 +0100 Subject: [PATCH 41/68] docs(transducers): update readme --- packages/transducers/README.md | 314 ++++++++++++--------------------- 1 file changed, 112 insertions(+), 202 deletions(-) diff --git a/packages/transducers/README.md b/packages/transducers/README.md index 707aff065e..e838b9045f 100644 --- a/packages/transducers/README.md +++ b/packages/transducers/README.md @@ -34,6 +34,7 @@ highly useful operators have been added. See full list below. #### Extended functionality - [@thi.ng/transducers-fsm](https://github.com/thi-ng/umbrella/tree/master/packages/transducers-fsm) - Fine State Machine transducer +- [@thi.ng/transducers-hdom](https://github.com/thi-ng/umbrella/tree/master/packages/transducers-hdom) - Transducer based [@thi.ng/hdom](https://github.com/thi-ng/umbrella/tree/master/packages/hdom) UI updates - [@thi.ng/transducers-stats](https://github.com/thi-ng/umbrella/tree/master/packages/transducers-stats) - Technical / statistical analysis transducers #### Packages utilizing transducers @@ -56,6 +57,7 @@ yarn add @thi.ng/transducers - [@thi.ng/checks](https://github.com/thi-ng/umbrella/tree/master/packages/checks) - [@thi.ng/compare](https://github.com/thi-ng/umbrella/tree/master/packages/compare) - [@thi.ng/errors](https://github.com/thi-ng/umbrella/tree/master/packages/errors) +- [@thi.ng/strings](https://github.com/thi-ng/umbrella/tree/master/packages/strings) ## Usage examples @@ -610,213 +612,121 @@ itself. Returns nothing. ### Transducers -#### `base64Decode(): Transducer` - -#### `base64Encode(urlSafe?: boolean, bufSize?: number): Transducer` - -#### `benchmark(): Transducer` - -#### `bits(wordSize?: number, msbFirst?: boolean): Transducer` - -#### `cat(): Transducer` - -#### `convolve2d(src: number[], width: number, height: number, weights: number[], kwidth: number, kheight: number, wrap?: boolean): Transducer` - -#### `dedupe(equiv?: (a: T, b: T) => boolean): Transducer` - -#### `delayed(t: number): Transducer>` - -#### `distinct(mapfn?: (x: T) => any): Transducer` - -#### `drop(n: number): Transducer` - -#### `dropNth(n: number): Transducer` - -#### `dropWhile(pred: Predicate): Transducer` - -#### `duplicate(n?: number): Transducer` - -#### `filter(pred: Predicate): Transducer` - -#### `filterFuzzy(query: ArrayLike, key?: (x: A) => ArrayLike, eq?: Predicate2): Transducer` - -#### `flatten(): Transducer, T>` - -#### `flattenWith(fn: (x: T) => Iterable): Transducer, T>` - -#### `hexDump(cols?: number, addr?: number): Transducer` - -#### `indexed(): Transducer` - -#### `inspect(prefix?: string): Transducer` - -#### `interleave(sep: B | (() => B)): Transducer` - -#### `interpose(sep: B | (() => B)): Transducer` - -#### `keep(f?: ((x: T) => any)): Transducer` - -#### `labeled(id: L | ((x: T) => L)): Transducer` - -#### `map(fn: (x: A) => B): Transducer` - -#### `mapcat(fn: (x: A) => Iterable): Transducer` - -#### `mapDeep(spec: TransformSpec): Transducer` - -#### `mapIndexed(fn: (i: number, x: A) => B, offset = 0): Transducer` - -#### `mapKeys(keys: IObjectOf<(x: any) => any>, copy?: boolean): Transducer` - -#### `mapNth(n: number, offset?: number, fn: (x: A) => B): Transducer` - -#### `mapVals(fn: (v: A) => B, copy = true): Transducer, IObjectOf>` - -#### `matchFirst(pred: Predicate): Transducer` - -#### `matchLast(pred: Predicate): Transducer` - -#### `movingAverage(n: number): Transducer` - -#### `movingMedian(n: number, key?: ((x: A) => B), cmp?: Comparator): Transducer` - -#### `multiplex(a: Transducer, b: Transducer...): Transducer` - -#### `multiplexObj(xforms: IObjectOf>, rfn?: Reducer): Transducer` - -#### `noop(): Transducer` - -#### `padLast(n: number, fill: T): Transducer` - -#### `page(page: number, pageLen = 10): Transducer` - -#### `partition(size: number, step?: number, all?: boolean): Transducer` - -#### `partitionBy(fn: (x: T) => any): Transducer` - -#### `partitionOf(sizes: number[]): Transducer` - -#### `partitionSort(n: number, key?: ((x: A) => B), cmp?: Comparator): Transducer` - -#### `partitionSync(keys: PropertyKey[] | Set, keyfn: (x: T) => PropertyKey, reset = true, all = true): Transducer>` - -#### `pluck(key: PropertyKey): Transducer` - -#### `rename(kmap: IObjectOf, rfn?: Reducer): Transducer` - -#### `sample(prob: number): Transducer` - -#### `scan(rfn: Reducer, acc?: B): Transducer` - -#### `selectKeys(...keys: PropertyKey[]): Transducer` - -#### `sideEffect(fn: (x: T) => void): Transducer` - -#### `streamShuffle(n: number, maxSwaps?: number): Transducer` - -#### `streamSort(n: number, key?: ((x: A) => B), cmp?: Comparator): Transducer` - -#### `struct(fields: StructField[]): Transducer` - -#### `swizzle(order: PropertyKey[]): Transducer` - -#### `take(n: number): Transducer` - -#### `takeLast(n: number): Transducer` - -#### `takeNth(n: number): Transducer` - -#### `takeWhile(pred: Predicate): Transducer` - -#### `throttle(delay: number): Transducer` - -#### `throttleTime(delay: number): Transducer` - -#### `utf8Decode(): Transducer` - -#### `utf8Encode(): Transducer` - -### Reducers - -#### `add(): Reducer` - -#### `assocMap(): Reducer, [A, B]>` - -#### `assocObj(): Reducer, [PropertyKey, T]>` - -#### `conj(): Reducer, T>` - -#### `count(offset?: number, step?: number): Reducer` - -#### `every(pred?: Predicate): Reducer` - -#### `frequencies(key: (x: A) => B): Reducer, A>` - -#### `groupBinary(bits: number, key: (x: T) => number, branch?: () => IObjectOf, leaf?: Reducer, left?: PropertyKey, right?: PropertyKey): Reducer` - -#### `groupByMap(key: (x: A) => B, rfn?: Reducer): Reducer, A>` - -#### `groupByObj(key: (x: A) => PropertyKey, rfn?: Reducer, init?: () => IObjectOf): Reducer, A>` - -#### `juxtR(...reducers: Reducer): Reducer` - -#### `last(): last(): Reducer` - -#### `max(): Reducer` - -#### `maxCompare(ident: () => T, cmp: Comparator = compare): Reducer` - -#### `mean(): Reducer` - -#### `min(): Reducer` - -#### `minCompare(ident: () => T, cmp: Comparator = compare): Reducer` - -#### `mul(): Reducer` - -#### `push(): Reducer` - -#### `pushCopy(): Reducer` - -#### `reductions(rfn: Reducer): Reducer` - -#### `some(pred?: Predicate): Reducer` - -#### `str(sep = ""): Reducer` +- [base64Decode](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/base64.ts) +- [base64Encode](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/base64.ts) +- [benchmark](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/benchmark.ts) +- [bits](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/bits.ts) +- [cat](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/cat.ts) +- [convolve2d](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/convolve.ts) +- [dedupe](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/dedupe.ts) +- [delayed](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/delayed.ts) +- [distinct](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/distinct.ts) +- [dropNth](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/drop-nth.ts) +- [dropWhile](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/drop-while.ts) +- [drop](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/drop.ts) +- [duplicate](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/duplicate.ts) +- [filterFuzzy](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/filter-fuzzy.ts) +- [filter](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/filter.ts) +- [flattenWith](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/flatten-with.ts) +- [flatten](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/flatten.ts) +- [hexDump](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/hex-dump.ts) +- [indexed](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/indexed.ts) +- [interleave](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/interleave.ts) +- [interpose](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/interpose.ts) +- [keep](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/keep.ts) +- [labeled](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/labeled.ts) +- [mapDeep](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/map-deep.ts) +- [mapIndexed](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/map-indexed.ts) +- [mapKeys](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/map-keys.ts) +- [mapNth](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/map-nth.ts) +- [mapVals](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/map-vals.ts) +- [map](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/map.ts) +- [mapcat](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/mapcat.ts) +- [matchFirst](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/match-first.ts) +- [matchLast](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/match-last.ts) +- [movingAverage](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/moving-average.ts) +- [movingMedian](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/moving-median.ts) +- [multiplexObj](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/multiplex-obj.ts) +- [multiplex](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/multiplex.ts) +- [noop](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/noop.ts) +- [padLast](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/pad-last.ts) +- [page](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/page.ts) +- [partitionBits](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/partition-bits.ts) +- [partitionBy](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/partition-by.ts) +- [partitionOf](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/partition-of.ts) +- [partitionSort](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/partition-sort.ts) +- [partitionSync](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/partition-sync.ts) +- [partition](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/partition.ts) +- [pluck](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/pluck.ts) +- [rename](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/rename.ts) +- [sample](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/sample.ts) +- [scan](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/scan.ts) +- [selectKeys](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/select-keys.ts) +- [sideEffect](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/side-effect.ts) +- [streamShuffle](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/stream-shuffle.ts) +- [streamSort](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/stream-sort.ts) +- [struct](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/struct.ts) +- [swizzle](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/swizzle.ts) +- [takeLast](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/take-last.ts) +- [takeNth](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/take-nth.ts) +- [takeWhile](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/take-while.ts) +- [take](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/take.ts) +- [throttleTime](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/throttle-time.ts) +- [throttle](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/throttle.ts) +- [trace](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/trace.ts) +- [utf8Decode](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/utf8.ts) +- [utf8Encode](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/utf8.ts) +- [wordWrap](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/word-wrap.ts) ### Generators / Iterators -#### `choices(choices: T[], weights?: number[])` - -#### `concat(...xs: Iterable[]): IterableIterator` - -#### `cycle(input: Iterable): IterableIterator` +- [asIterable](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/asIterable.ts) +- [choices](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/choices.ts) +- [concat](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/concat.ts) +- [cycle](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/cycle.ts) +- [iterate](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/iterate.ts) +- [keys](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/keys.ts) +- [normRange](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/normRange.ts) +- [pairs](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/pairs.ts) +- [permutations](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/permutations.ts) +- [permutationsN](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/permutationsN.ts) +- [range](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/range.ts) +- [range2d](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/range2d.ts) +- [range3d](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/range3d.ts) +- [repeat](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/repeat.ts) +- [repeatedly](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/repeatedly.ts) +- [reverse](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/reverse.ts) +- [tuples](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/tuples.ts) +- [vals](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/vals.ts) +- [wrapBoth](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/wrapBoth.ts) +- [wrapLeft](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/wrapLeft.ts) +- [wrapRight](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/wrapRight.ts) +- [wrap](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/wrap.ts) -#### `iterate(fn: (x: T) => T, seed: T): IterableIterator` - -#### `keys(x: any): IterableIterator` - -#### `normRange(n?: number): IterableIterator` - -#### `pairs(x: any): IterableIterator<[string, any]>` - -#### `range(from?: number, to?: number, step?: number): IterableIterator` - -#### `range2d(x1: number, x2: number, y1: number, y2: number, stepx?: number, stepy?: number): IterableIterator` - -#### `range3d(x1: number, x2: number, y1: number, y2: number, z1: number, z2: number, stepx?: number, stepy?: number, stepz?: number): IterableIterator` - -#### `repeat(x: T, n?: number): IterableIterator` - -#### `repeatedly(fn: () => T, n?: number): IterableIterator` - -#### `reverse(input: Iterable): IterableIterator` - -#### `tuples(...src: Iterable[]): IterableIterator` - -#### `vals(x: IObjectOf): IterableIterator` +### Reducers -#### `wrap(src: T[], n = 1, left = true, right = true): IterableIterator` +- [add](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/add) +- [assocMap](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/assoc-map) +- [assocObj](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/assoc-obj) +- [conj](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/conj) +- [count](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/count) +- [every](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/every) +- [frequencies](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/frequencies) +- [groupBinary](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/group-binary) +- [groupByMap](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/group-by-map) +- [groupByObj](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/group-by-obj) +- [last](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/last) +- [maxCompare](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/max-compare) +- [max](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/max) +- [mean](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/mean) +- [minCompare](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/min-compare) +- [min](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/min) +- [mul](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/mul) +- [pushCopy](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/push-copy) +- [push](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/push) +- [reductions](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/reductions) +- [some](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/some) +- [str](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/str) ## Authors From fd8e7614a2984b966183d16ff96e8edb3c9809c0 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 9 Aug 2018 21:15:27 +0100 Subject: [PATCH 42/68] feat(rle-pack): add support for custom input word sizes --- packages/rle-pack/src/index.ts | 56 +++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/packages/rle-pack/src/index.ts b/packages/rle-pack/src/index.ts index 3c6c9b0bb3..edf23741c8 100644 --- a/packages/rle-pack/src/index.ts +++ b/packages/rle-pack/src/index.ts @@ -2,16 +2,24 @@ import { BitInputStream, BitOutputStream } from "@thi.ng/bitstream"; const RLE_SIZES = [3, 4, 8, 16]; -export function encodeBytes(src: Uint8Array) { - const stream = new BitOutputStream().write(src.length, 32); - let num = src.length - 1; - let val = src[0]; +/** + * Compresses input using dynamically sized RLE compression and returns + * result as `Uint8Array`. + * + * @param src + * @param num number of input words + * @param wordSize in bits, MUST be <= 8 + */ +export function encodeBytes(src: Iterable, num: number, wordSize = 8) { + const stream = new BitOutputStream(num * wordSize / 8).write(num, 32); + const n1 = num - 1; + let val; let tail = true; let n = -1; - let x, i, t; + let i = 0, t; const write = () => { stream.write(n > 0 ? 1 : 0, 1); - stream.write(val, 8); + stream.write(val, wordSize); if (n > 0) { t = (n < 0x8) ? 0 : (n < 0x10) ? 1 : (n < 0x100) ? 2 : 3; stream.write(t, 2); @@ -19,36 +27,42 @@ export function encodeBytes(src: Uint8Array) { } n = 0; }; - for (i = 0; i <= num; i++) { - x = src[i]; - if (x !== val) { + for (let x of src) { + if (val === undefined) { + val = x; + } else if (x !== val) { write(); val = x; } else { if (++n === 0x10000) { write(); - tail = (i < num); + tail = (i < n1); } } + i++; + } + if (tail) { + write(); } - if (tail) { write(); } return stream.bytes(); } -export function decodeBytes(src: Uint8Array) { - let num = (src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3]); - let input = new BitInputStream(src, 32); - let out = new Uint8Array(num); - let i = 0; +export function decodeBytes(src: Uint8Array, wordSize = 8) { + const input = new BitInputStream(src); + const ws1 = wordSize + 1; + const num = input.read(32); + const out = new Uint8Array(num); + const flag = 1 << wordSize; + const mask = flag - 1; let x, j; - while (i < num) { - x = input.read(9); - if (x & 0x100) { + for (let i = 0; i < num;) { + x = input.read(ws1); + if (x & flag) { j = i + 1 + input.read(RLE_SIZES[input.read(2)]); - out.fill(x & 0xff, i, j); + out.fill(x & mask, i, j); i = j; } else { - out[i++] = x & 0xff; + out[i++] = x & mask; } } return out; From 9d83255a6be245260da58fdcfcfd95e8fd00cb05 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 22 Aug 2018 23:22:35 +0100 Subject: [PATCH 43/68] perf(transducers): add IReducible, update reduce() - add IReducible interface for custom/optimized iteration and source value provision for reduce() - add array-like check to reduce() and switch to version without forcing array iterator (`for..of..`) --- packages/transducers/src/api.ts | 4 ++++ packages/transducers/src/iterator.ts | 3 ++- packages/transducers/src/reduce.ts | 30 +++++++++++++++++++++------- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/transducers/src/api.ts b/packages/transducers/src/api.ts index 819fa24302..83fed71217 100644 --- a/packages/transducers/src/api.ts +++ b/packages/transducers/src/api.ts @@ -12,6 +12,10 @@ export interface Reducer extends Array { [2]: ReductionFn; }; +export interface IReducible { + $reduce(rfn: ReductionFn, acc: A): A | Reduced; +} + export type TransformFn = (x: any) => any; export type TransformSubSpec = IObjectOf; export interface TransformSpec extends Array { diff --git a/packages/transducers/src/iterator.ts b/packages/transducers/src/iterator.ts index 50b0aaac59..7768f05830 100644 --- a/packages/transducers/src/iterator.ts +++ b/packages/transducers/src/iterator.ts @@ -28,7 +28,8 @@ export function* iterator(xform: Transducer, xs: Iterable): Itera } /** - * Optimized version of `iterator()` for transducers which are guaranteed to: + * Optimized version of `iterator()` for transducers which are + * guaranteed to: * * 1) Only produce none or a single result per input * 2) Do not require a `completion` reduction step diff --git a/packages/transducers/src/reduce.ts b/packages/transducers/src/reduce.ts index a20795bfa3..dc5999beb5 100644 --- a/packages/transducers/src/reduce.ts +++ b/packages/transducers/src/reduce.ts @@ -1,12 +1,16 @@ +import { implementsFunction } from "@thi.ng/checks/implements-function"; +import { isArrayLike } from "@thi.ng/checks/is-arraylike"; import { illegalArity } from "@thi.ng/errors/illegal-arity"; -import { Reducer } from "./api"; +import { Reducer, IReducible } from "./api"; import { isReduced, unreduced, Reduced } from "./reduced"; export function reduce(rfn: Reducer, xs: Iterable): A; export function reduce(rfn: Reducer, acc: A, xs: Iterable): A; +export function reduce(rfn: Reducer, xs: IReducible): A; +export function reduce(rfn: Reducer, acc: A, xs: IReducible): A; export function reduce(...args: any[]): A { - let acc: A, xs: Iterable; + let acc: A, xs: Iterable | IReducible; switch (args.length) { case 3: xs = args[2]; @@ -20,11 +24,23 @@ export function reduce(...args: any[]): A { } const [init, complete, reduce] = args[0]; acc = acc == null ? init() : acc; - for (let x of xs) { - acc = reduce(acc, x); - if (isReduced(acc)) { - acc = (acc).deref(); - break; + if (implementsFunction(xs, "$reduce")) { + acc = (>xs).$reduce(reduce, acc); + } else if (isArrayLike(xs)) { + for (let i = 0, n = xs.length; i < n; i++) { + acc = reduce(acc, xs[i]); + if (isReduced(acc)) { + acc = (acc).deref(); + break; + } + } + } else { + for (let x of >xs) { + acc = reduce(acc, x); + if (isReduced(acc)) { + acc = (acc).deref(); + break; + } } } return unreduced(complete(acc)); From f14f7ce564a0a380f8a1fcfe0391967e814e8573 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 22 Aug 2018 23:24:06 +0100 Subject: [PATCH 44/68] feat(associative): add IReducible impls for SortedMap & SortedSet --- packages/associative/src/sorted-map.ts | 15 ++++++++++++++- packages/associative/src/sorted-set.ts | 8 +++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/associative/src/sorted-map.ts b/packages/associative/src/sorted-map.ts index 12b7058cd2..49b7763a8c 100644 --- a/packages/associative/src/sorted-map.ts +++ b/packages/associative/src/sorted-map.ts @@ -13,6 +13,8 @@ import { isArray } from "@thi.ng/checks/is-array"; import { compare } from "@thi.ng/compare"; import { equiv } from "@thi.ng/equiv"; import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; +import { IReducible, ReductionFn } from "@thi.ng/transducers/api"; +import { isReduced } from "@thi.ng/transducers/reduced"; import { map } from "@thi.ng/transducers/xform/map"; import { SortedMapOpts } from "./api"; @@ -69,7 +71,8 @@ export class SortedMap extends Map implements ICopy>, ICompare>, IEmpty>, - IEquiv { + IEquiv, + IReducible> { static fromObject(obj: IObjectOf): SortedMap { const m = new SortedMap(null, { capacity: Object.keys(obj).length }); @@ -255,6 +258,16 @@ export class SortedMap extends Map implements return this; } + $reduce(rfn: ReductionFn>, acc: any) { + const $this = __private.get(this); + let node = $this.head[NEXT]; + while (node[KEY] !== undefined && !isReduced(acc)) { + acc = rfn(acc, [node[KEY], node[VAL]]); + node = node[NEXT]; + } + return acc; + } + *entries(key?: K, reverse = false): IterableIterator> { const $this = __private.get(this); const step = reverse ? PREV : NEXT; diff --git a/packages/associative/src/sorted-set.ts b/packages/associative/src/sorted-set.ts index 10b6a9dc1d..10f2ba080b 100644 --- a/packages/associative/src/sorted-set.ts +++ b/packages/associative/src/sorted-set.ts @@ -1,5 +1,6 @@ import { ICompare, Pair, } from "@thi.ng/api/api"; import { compare } from "@thi.ng/compare"; +import { IReducible, ReductionFn } from "@thi.ng/transducers/api"; import { map } from "@thi.ng/transducers/xform/map"; import { IEquivSet, SortedSetOpts } from "./api"; @@ -24,7 +25,8 @@ const __private = new WeakMap, SortedMap>(); */ export class SortedSet extends Set implements IEquivSet, - ICompare> { + ICompare>, + IReducible { /** * Creates new instance with optional given values and/or @@ -96,6 +98,10 @@ export class SortedSet extends Set implements return true; } + $reduce(rfn: ReductionFn, acc: any) { + return __private.get(this).$reduce((_acc, x) => rfn(_acc, x[0]), acc); + } + entries(): IterableIterator> { return __private.get(this).entries(); } From 1280cfd51daf9ed174d32f024f12d46febdd27e7 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Wed, 22 Aug 2018 23:27:42 +0100 Subject: [PATCH 45/68] feat(dcons): add IReducible impl, update deps & imports --- packages/dcons/package.json | 5 ++-- packages/dcons/src/index.ts | 46 +++++++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/packages/dcons/package.json b/packages/dcons/package.json index 5042024642..3b226ed38d 100644 --- a/packages/dcons/package.json +++ b/packages/dcons/package.json @@ -32,7 +32,8 @@ "@thi.ng/checks": "^1.5.7", "@thi.ng/compare": "^0.1.6", "@thi.ng/equiv": "^0.1.7", - "@thi.ng/errors": "^0.1.6" + "@thi.ng/errors": "^0.1.6", + "@thi.ng/transducers": "^1.16.0" }, "keywords": [ "datastructure", @@ -48,4 +49,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/packages/dcons/src/index.ts b/packages/dcons/src/index.ts index dbe048b5e4..97686dbd57 100644 --- a/packages/dcons/src/index.ts +++ b/packages/dcons/src/index.ts @@ -1,9 +1,21 @@ -import * as api from "@thi.ng/api/api"; +import { + Comparator, + ICompare, + ICopy, + IEmpty, + IEquiv, + ILength, + IRelease, + IStack, + Predicate +} from "@thi.ng/api/api"; +import { isArrayLike } from "@thi.ng/checks/is-arraylike"; import { compare } from "@thi.ng/compare"; import { equiv } from "@thi.ng/equiv"; import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { illegalState } from "@thi.ng/errors/illegal-state"; -import { isArrayLike } from "@thi.ng/checks/is-arraylike"; +import { IReducible, ReductionFn } from "@thi.ng/transducers/api"; +import { isReduced } from "@thi.ng/transducers/reduced"; export interface ConsCell { value: T; @@ -12,13 +24,14 @@ export interface ConsCell { } export class DCons implements - api.ICompare>, - api.ICopy>, - api.IEmpty>, - api.IEquiv, - api.ILength, - api.IRelease, - api.IStack> { + ICompare>, + ICopy>, + IEmpty>, + IEquiv, + ILength, + IReducible, + IRelease, + IStack> { head: ConsCell; tail: ConsCell; @@ -107,6 +120,15 @@ export class DCons implements } } + $reduce(rfn: ReductionFn, acc: any) { + let cell = this.head; + while (cell && !isReduced(acc)) { + acc = rfn(acc, cell.value); + cell = cell.next; + } + return acc; + } + drop() { const cell = this.head; if (cell) { @@ -185,7 +207,7 @@ export class DCons implements } } - insertSorted(value: T, cmp?: api.Comparator) { + insertSorted(value: T, cmp?: Comparator) { cmp = cmp || compare; let cell = this.head; while (cell) { @@ -207,7 +229,7 @@ export class DCons implements } } - findWith(fn: api.Predicate) { + findWith(fn: Predicate) { let cell = this.head; while (cell) { if (fn(cell.value)) { @@ -423,7 +445,7 @@ export class DCons implements return res; } - filter(pred: api.Predicate) { + filter(pred: Predicate) { const res = new DCons(); let cell = this.head; while (cell) { From c716e4ac317cafd896ddab2ef59d958f4fc37f5b Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 23 Aug 2018 00:04:15 +0100 Subject: [PATCH 46/68] add(transducers): add IReducible support for transduce() & run() --- packages/transducers/src/run.ts | 6 ++++-- packages/transducers/src/transduce.ts | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/transducers/src/run.ts b/packages/transducers/src/run.ts index d1a456e20f..408c159a3a 100644 --- a/packages/transducers/src/run.ts +++ b/packages/transducers/src/run.ts @@ -1,4 +1,4 @@ -import { Transducer } from "./api"; +import { IReducible, Transducer } from "./api"; import { transduce } from "./transduce"; const nop = () => { }; @@ -14,8 +14,10 @@ const nop = () => { }; * @param fx * @param xs */ -export function run(tx: Transducer, xs: Iterable): void; +export function run(tx: Transducer, xs: Iterable): void; +export function run(tx: Transducer, xs: IReducible): void; export function run(tx: Transducer, fx: (x: B) => void, xs: Iterable): void; +export function run(tx: Transducer, fx: (x: B) => void, xs: IReducible): void; export function run(tx: Transducer, ...args: any[]) { if (args.length === 1) { transduce(tx, [nop, nop, nop], args[0]); diff --git a/packages/transducers/src/transduce.ts b/packages/transducers/src/transduce.ts index f84ab37574..028bbf1bf8 100644 --- a/packages/transducers/src/transduce.ts +++ b/packages/transducers/src/transduce.ts @@ -1,12 +1,14 @@ import { illegalArity } from "@thi.ng/errors/illegal-arity"; -import { Reducer, Transducer } from "./api"; +import { IReducible, Reducer, Transducer } from "./api"; import { reduce } from "./reduce"; import { map } from "./xform/map"; export function transduce(tx: Transducer, rfn: Reducer): Transducer, C>; export function transduce(tx: Transducer, rfn: Reducer, xs: Iterable): C; +export function transduce(tx: Transducer, rfn: Reducer, xs: IReducible): C; export function transduce(tx: Transducer, rfn: Reducer, acc: C, xs: Iterable): C; +export function transduce(tx: Transducer, rfn: Reducer, acc: C, xs: IReducible): C; export function transduce(...args: any[]): any { let acc, xs; switch (args.length) { @@ -22,6 +24,5 @@ export function transduce(...args: any[]): any { default: illegalArity(args.length); } - const _rfn: Reducer = args[0](args[1]); - return reduce(_rfn, acc, xs); + return reduce(args[0](args[1]), acc, xs); } From 116ede830d2f3b73c8ee84c2a9c9636be2591c77 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 23 Aug 2018 00:06:29 +0100 Subject: [PATCH 47/68] docs(transducers): update readme --- packages/transducers/README.md | 79 ++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/packages/transducers/README.md b/packages/transducers/README.md index e838b9045f..e460e42165 100644 --- a/packages/transducers/README.md +++ b/packages/transducers/README.md @@ -5,13 +5,37 @@ This project is part of the [@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo. - + - [About](#about) + - [Related packages](#related-packages) - [Installation](#installation) - [Dependencies](#dependencies) - [Usage examples](#usage-examples) + - [Basic usage patterns](#basic-usage-patterns) + - [Fuzzy search](#fuzzy-search) + - [Histogram generation & result grouping](#histogram-generation--result-grouping) + - [Pagination](#pagination) + - [Multiplexing / parallel transducer application](#multiplexing--parallel-transducer-application) + - [Moving average using sliding window](#moving-average-using-sliding-window) + - [Benchmark function execution time](#benchmark-function-execution-time) + - [Apply inspectors to debug transducer pipeline](#apply-inspectors-to-debug-transducer-pipeline) + - [Stream parsing / structuring](#stream-parsing--structuring) + - [CSV parsing](#csv-parsing) + - [Early termination](#early-termination) + - [Scan operator](#scan-operator) + - [Streaming hexdump](#streaming-hexdump) + - [Bitstream](#bitstream) + - [Base64 & UTF-8 en/decoding](#base64--utf-8-endecoding) + - [Weighted random choices](#weighted-random-choices) - [API](#api) + - [Types](#types) + - [IReducible](#ireducible) + - [Transducer](#transducer) + - [Transformations](#transformations) + - [Transducers](#transducers) + - [Generators / Iterators](#generators--iterators) + - [Reducers](#reducers) - [Authors](#authors) - [License](#license) @@ -69,13 +93,20 @@ Almost all functions can be imported selectively, but for development purposes full module re-exports are defined. ```ts -// full import +// full import (not recommended for browser use) import * as tx from "@thi.ng/transducers"; -// selective +// selective / single function imports import { transduce } from "@thi.ng/transducers/transduce"; + +// all transducers are under the /xform import path +import { map } from "@thi.ng/transducers/xform/map"; + +// all reducers are under the /rfn import path import { push } from "@thi.ng/transducers/rfn/push"; -import { map } from "@thi.ng/transducers/xforms/map"; + +// all iterators are under the /iter import path +import { range } from "@thi.ng/transducers/iter/range"; ``` ### Basic usage patterns @@ -83,16 +114,16 @@ import { map } from "@thi.ng/transducers/xforms/map"; ```ts // compose transducer xform = tx.comp( - tx.filter(x => (x & 1) > 0), // odd numbers only + tx.filter((x) => (x & 1) > 0), // odd numbers only tx.distinct(), // distinct numbers only - tx.map(x=> x * 3) // times 3 + tx.map((x) => x * 3) // times 3 ); -// collect as array (tx.push) +// collect into array (tx.push) tx.transduce(xform, tx.push(), [1, 2, 3, 4, 5, 4, 3, 2, 1]); // [ 3, 9, 15 ] -// re-use same xform, but collect as set (tx.conj) +// re-use same xform, but collect into ES6 Set tx.transduce(xform, tx.conj(), [1, 2, 3, 4, 5, 4, 3, 2, 1]); // Set { 3, 9, 15 } @@ -101,6 +132,11 @@ tx.transduce(xform, tx.conj(), [1, 2, 3, 4, 5, 4, 3, 2, 1]); [...tx.iterator(xform, [1, 2, 3, 4, 5])] // [ 3, 9, 15] +// alternatively provide an input iterable and +// use xform as transforming iterator +[...tx.filter((x) => /[A-Z]/.test(x), "Hello World!")].join("") +// "HW" + // single step execution // returns undefined if transducer returned no result for this input // returns array if transducer step produced multiple results @@ -532,6 +568,20 @@ created via `reduced(x)` and handled via these helper functions: #### `unreduced(x: any): any` +### IReducible + +By default `reduce()` consumes inputs via the standard ES6 `Iterable` +interface, i.e. using a `for..of..` loop. Array-like inputs are consumed +via a traditional for-loop and custom optimized iterations can be +provided via implementations of the `IReducible` interface in the source +collection type. Examples can be found here: + +- [DCons](https://github.com/thi-ng/umbrella/tree/master/packages/dcons/src/index.ts#L123) +- [SortedMap](https://github.com/thi-ng/umbrella/tree/master/packages/associative/src/index.ts#L261) + +**Note:** The `IReducible` interface is only used by `reduce()`, +`transduce()` and `run()`. + ### Transducer From Rich Hickey's original definition: @@ -612,6 +662,19 @@ itself. Returns nothing. ### Transducers +All of these functions can be used and composed as transducers. Most also +accept an input iterable and then directly yield a transforming iterator, e.g. + +```ts +// as transducer +tx.transduce(tx.map((x) => x*10), tx.push(), tx.range(4)) +// [ 0, 10, 20, 30 ] + +// as transforming iterator +[...tx.map((x) => x*10, tx.range(4))] +// [ 0, 10, 20, 30 ] +``` + - [base64Decode](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/base64.ts) - [base64Encode](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/base64.ts) - [benchmark](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/xform/benchmark.ts) From ecfcdcd931fd4ee3c727e8f031c51f4d9e99f966 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 23 Aug 2018 00:06:58 +0100 Subject: [PATCH 48/68] build: update yarn.lock --- yarn.lock | 660 ++++++++++++++++++++++++++---------------------------- 1 file changed, 313 insertions(+), 347 deletions(-) diff --git a/yarn.lock b/yarn.lock index 686258ed99..e238940229 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8,27 +8,27 @@ dependencies: "@babel/highlight" "7.0.0-beta.51" -"@babel/code-frame@7.0.0-beta.54": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.54.tgz#0024f96fdf7028a21d68e273afd4e953214a1ead" +"@babel/code-frame@7.0.0-rc.2": + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-rc.2.tgz#12b6daeb408238360744649d16c0e9fa7ab3859e" dependencies: - "@babel/highlight" "7.0.0-beta.54" + "@babel/highlight" "7.0.0-rc.2" "@babel/core@^7.0.0-beta.46": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.0.0-beta.54.tgz#253c54d0095403a5cfa764e7d9b458194692d02b" - dependencies: - "@babel/code-frame" "7.0.0-beta.54" - "@babel/generator" "7.0.0-beta.54" - "@babel/helpers" "7.0.0-beta.54" - "@babel/parser" "7.0.0-beta.54" - "@babel/template" "7.0.0-beta.54" - "@babel/traverse" "7.0.0-beta.54" - "@babel/types" "7.0.0-beta.54" + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.0.0-rc.2.tgz#dcb46b3adb63e35b1e82c35d9130d9c27be58427" + dependencies: + "@babel/code-frame" "7.0.0-rc.2" + "@babel/generator" "7.0.0-rc.2" + "@babel/helpers" "7.0.0-rc.2" + "@babel/parser" "7.0.0-rc.2" + "@babel/template" "7.0.0-rc.2" + "@babel/traverse" "7.0.0-rc.2" + "@babel/types" "7.0.0-rc.2" convert-source-map "^1.1.0" debug "^3.1.0" json5 "^0.5.0" - lodash "^4.17.5" + lodash "^4.17.10" resolve "^1.3.2" semver "^5.4.1" source-map "^0.5.0" @@ -43,13 +43,13 @@ source-map "^0.5.0" trim-right "^1.0.1" -"@babel/generator@7.0.0-beta.54": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.54.tgz#c043c7eebeebfd7e665d95c281a4aafc83d4e1c9" +"@babel/generator@7.0.0-rc.2": + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-rc.2.tgz#7aed8fb4ef1bdcc168225096b5b431744ba76bf8" dependencies: - "@babel/types" "7.0.0-beta.54" + "@babel/types" "7.0.0-rc.2" jsesc "^2.5.1" - lodash "^4.17.5" + lodash "^4.17.10" source-map "^0.5.0" trim-right "^1.0.1" @@ -61,13 +61,13 @@ "@babel/template" "7.0.0-beta.51" "@babel/types" "7.0.0-beta.51" -"@babel/helper-function-name@7.0.0-beta.54": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.54.tgz#307875507a1eda2482a09a9a4df6a25632ffb34b" +"@babel/helper-function-name@7.0.0-rc.2": + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-rc.2.tgz#ad7bb9df383c5f53e4bf38c0fe0c7f93e6a27729" dependencies: - "@babel/helper-get-function-arity" "7.0.0-beta.54" - "@babel/template" "7.0.0-beta.54" - "@babel/types" "7.0.0-beta.54" + "@babel/helper-get-function-arity" "7.0.0-rc.2" + "@babel/template" "7.0.0-rc.2" + "@babel/types" "7.0.0-rc.2" "@babel/helper-get-function-arity@7.0.0-beta.51": version "7.0.0-beta.51" @@ -75,11 +75,11 @@ dependencies: "@babel/types" "7.0.0-beta.51" -"@babel/helper-get-function-arity@7.0.0-beta.54": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.54.tgz#757bd189b077074a004028cfde5f083c306cc6c4" +"@babel/helper-get-function-arity@7.0.0-rc.2": + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-rc.2.tgz#323cb82e2d805b40c0c36be1dfcb8ffcbd0434f3" dependencies: - "@babel/types" "7.0.0-beta.54" + "@babel/types" "7.0.0-rc.2" "@babel/helper-split-export-declaration@7.0.0-beta.51": version "7.0.0-beta.51" @@ -87,19 +87,19 @@ dependencies: "@babel/types" "7.0.0-beta.51" -"@babel/helper-split-export-declaration@7.0.0-beta.54": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.54.tgz#89cd8833c95481a0827ac6a1bfccddb92b75a109" +"@babel/helper-split-export-declaration@7.0.0-rc.2": + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-rc.2.tgz#726b2dec4e46baeab32db67caa6e88b6521464f8" dependencies: - "@babel/types" "7.0.0-beta.54" + "@babel/types" "7.0.0-rc.2" -"@babel/helpers@7.0.0-beta.54": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.0.0-beta.54.tgz#b86a99a80efd81668caef307610b961197446a74" +"@babel/helpers@7.0.0-rc.2": + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.0.0-rc.2.tgz#e21f54451824f55b4f5022c6e9d6fa7df65e8746" dependencies: - "@babel/template" "7.0.0-beta.54" - "@babel/traverse" "7.0.0-beta.54" - "@babel/types" "7.0.0-beta.54" + "@babel/template" "7.0.0-rc.2" + "@babel/traverse" "7.0.0-rc.2" + "@babel/types" "7.0.0-rc.2" "@babel/highlight@7.0.0-beta.51": version "7.0.0-beta.51" @@ -109,21 +109,21 @@ esutils "^2.0.2" js-tokens "^3.0.0" -"@babel/highlight@7.0.0-beta.54": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.54.tgz#155d507358329b8e7068970017c3fd74a9b08584" +"@babel/highlight@7.0.0-rc.2": + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-rc.2.tgz#0af688a69e3709d9cf392e1837cda18c08d34d4f" dependencies: chalk "^2.0.0" esutils "^2.0.2" - js-tokens "^3.0.0" + js-tokens "^4.0.0" "@babel/parser@7.0.0-beta.51": version "7.0.0-beta.51" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.0.0-beta.51.tgz#27cec2df409df60af58270ed8f6aa55409ea86f6" -"@babel/parser@7.0.0-beta.54": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.0.0-beta.54.tgz#c01aa63b57c9c8dce8744796c81d9df121f20db4" +"@babel/parser@7.0.0-rc.2": + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.0.0-rc.2.tgz#a98c01af5834e71d48a5108e3aeeee333cdf26c4" "@babel/template@7.0.0-beta.51": version "7.0.0-beta.51" @@ -134,14 +134,13 @@ "@babel/types" "7.0.0-beta.51" lodash "^4.17.5" -"@babel/template@7.0.0-beta.54": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.54.tgz#d5b0d2d2d55c0e78b048c61a058f36cfd7d91af3" +"@babel/template@7.0.0-rc.2": + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-rc.2.tgz#53f6be6c1336ddc7744625c9bdca9d10be5d5d72" dependencies: - "@babel/code-frame" "7.0.0-beta.54" - "@babel/parser" "7.0.0-beta.54" - "@babel/types" "7.0.0-beta.54" - lodash "^4.17.5" + "@babel/code-frame" "7.0.0-rc.2" + "@babel/parser" "7.0.0-rc.2" + "@babel/types" "7.0.0-rc.2" "@babel/traverse@7.0.0-beta.51": version "7.0.0-beta.51" @@ -158,19 +157,19 @@ invariant "^2.2.0" lodash "^4.17.5" -"@babel/traverse@7.0.0-beta.54": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.54.tgz#2c17f98dcdbf19aa918fde128f0e1a0bc089e05a" +"@babel/traverse@7.0.0-rc.2": + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-rc.2.tgz#6e54ebe82aa1b3b3cf5ec05594bc14d7c59c9766" dependencies: - "@babel/code-frame" "7.0.0-beta.54" - "@babel/generator" "7.0.0-beta.54" - "@babel/helper-function-name" "7.0.0-beta.54" - "@babel/helper-split-export-declaration" "7.0.0-beta.54" - "@babel/parser" "7.0.0-beta.54" - "@babel/types" "7.0.0-beta.54" + "@babel/code-frame" "7.0.0-rc.2" + "@babel/generator" "7.0.0-rc.2" + "@babel/helper-function-name" "7.0.0-rc.2" + "@babel/helper-split-export-declaration" "7.0.0-rc.2" + "@babel/parser" "7.0.0-rc.2" + "@babel/types" "7.0.0-rc.2" debug "^3.1.0" globals "^11.1.0" - lodash "^4.17.5" + lodash "^4.17.10" "@babel/types@7.0.0-beta.51": version "7.0.0-beta.51" @@ -180,12 +179,12 @@ lodash "^4.17.5" to-fast-properties "^2.0.0" -"@babel/types@7.0.0-beta.54": - version "7.0.0-beta.54" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.54.tgz#025ad68492fed542c13f14c579a44c848e531063" +"@babel/types@7.0.0-rc.2": + version "7.0.0-rc.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-rc.2.tgz#8e025b78764cee8751823e308558a3ca144ebd9d" dependencies: esutils "^2.0.2" - lodash "^4.17.5" + lodash "^4.17.10" to-fast-properties "^2.0.0" "@types/events@*": @@ -230,13 +229,9 @@ version "5.2.5" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.5.tgz#8a4accfc403c124a0bafe8a9fc61a05ec1032073" -"@types/node@*": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.0.6.tgz#c0bce8e539bf34c1b850c13ff46bead2fecc2e58" - -"@types/node@^10.5.5": - version "10.5.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.5.tgz#8e84d24e896cd77b0d4f73df274027e3149ec2ba" +"@types/node@*", "@types/node@^10.5.5": + version "10.7.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.7.1.tgz#b704d7c259aa40ee052eec678758a68d07132a2e" "@types/shelljs@0.7.8": version "0.7.8" @@ -386,8 +381,8 @@ long "^3.2.0" JSONStream@^1.0.4: - version "1.3.2" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" + version "1.3.4" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.4.tgz#615bb2adb0cd34c8f4c447b5f6512fa1d8f16a2e" dependencies: jsonparse "^1.2.0" through ">=2.2.7 <3" @@ -409,11 +404,7 @@ acorn-dynamic-import@^3.0.0: dependencies: acorn "^5.0.0" -acorn@^5.0.0: - version "5.5.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" - -acorn@^5.6.2: +acorn@^5.0.0, acorn@^5.6.2: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" @@ -426,13 +417,13 @@ ajv-keywords@^3.1.0: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" ajv@^6.1.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.0.tgz#4c8affdf80887d8f132c9c52ab8a2dc4d0b7b24c" + version "6.5.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9" dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - uri-js "^4.2.1" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" @@ -494,8 +485,8 @@ archy@^1.0.0: resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" dependencies: delegates "^1.0.0" readable-stream "^2.0.6" @@ -585,9 +576,9 @@ async@^1.4.0, async@^1.5.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -atob@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" babel-code-frame@^6.22.0: version "6.26.0" @@ -900,12 +891,13 @@ browserify-cipher@^1.0.0: evp_bytestokey "^1.0.0" browserify-des@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.1.tgz#3343124db6d7ad53e26a8826318712bdc8450f9c" + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" dependencies: cipher-base "^1.0.1" des.js "^1.0.0" inherits "^2.0.1" + safe-buffer "^5.1.2" browserify-rsa@^4.0.0: version "4.0.1" @@ -933,8 +925,8 @@ browserify-zlib@^0.2.0: pako "~1.0.5" buffer-from@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" buffer-indexof@^1.0.0: version "1.1.1" @@ -1073,8 +1065,8 @@ chardet@^0.5.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.5.0.tgz#fe3ac73c00c3d865ffcc02a0682e2c20b6a06029" chokidar@^2.0.0, chokidar@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176" + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" dependencies: anymatch "^2.0.0" async-each "^1.0.0" @@ -1083,12 +1075,13 @@ chokidar@^2.0.0, chokidar@^2.0.2: inherits "^2.0.1" is-binary-path "^1.0.0" is-glob "^4.0.0" + lodash.debounce "^4.0.8" normalize-path "^2.1.1" path-is-absolute "^1.0.0" readdirp "^2.0.0" - upath "^1.0.0" + upath "^1.0.5" optionalDependencies: - fsevents "^1.1.2" + fsevents "^1.2.2" chownr@^1.0.1: version "1.0.1" @@ -1100,9 +1093,9 @@ chrome-trace-event@^1.0.0: dependencies: tslib "^1.9.0" -ci-info@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" +ci-info@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.4.0.tgz#4841d53cad49f11b827b648ebde27a6e189b412f" cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" @@ -1177,14 +1170,14 @@ collection-visit@^1.0.0: object-visit "^1.0.0" color-convert@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + version "1.9.2" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" dependencies: - color-name "^1.1.1" + color-name "1.1.1" -color-name@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" +color-name@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" columnify@^1.5.4: version "1.5.4" @@ -1197,10 +1190,14 @@ command-join@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/command-join/-/command-join-2.0.0.tgz#52e8b984f4872d952ff1bdc8b98397d27c7144cf" -commander@2.15.1, commander@^2.12.1: +commander@2.15.1: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" +commander@^2.12.1: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -1220,22 +1217,22 @@ component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" -compressible@~2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.13.tgz#0d1020ab924b2fdb4d6279875c7d6daba6baa7a9" +compressible@~2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" dependencies: - mime-db ">= 1.33.0 < 2" + mime-db ">= 1.34.0 < 2" compression@^1.5.2: - version "1.7.2" - resolved "http://registry.npmjs.org/compression/-/compression-1.7.2.tgz#aaffbcd6aaf854b44ebb280353d5ad1651f59a69" + version "1.7.3" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" dependencies: - accepts "~1.3.4" + accepts "~1.3.5" bytes "3.0.0" - compressible "~2.0.13" + compressible "~2.0.14" debug "2.6.9" on-headers "~1.0.1" - safe-buffer "5.1.1" + safe-buffer "5.1.2" vary "~1.1.2" concat-map@0.0.1: @@ -1608,9 +1605,9 @@ deep-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" -deep-extend@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.5.1.tgz#b894a9dd90d3023fbf1c55a394fb858eb2066f1f" +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" default-require-extensions@^1.0.0: version "1.0.0" @@ -1625,11 +1622,10 @@ defaults@^1.0.3: clone "^1.0.2" define-properties@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" dependencies: - foreach "^2.0.5" - object-keys "^1.0.8" + object-keys "^1.0.12" define-property@^0.2.5: version "0.2.5" @@ -1757,8 +1753,8 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" elliptic@^6.0.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + version "6.4.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -1782,15 +1778,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enhanced-resolve@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz#e34a6eaa790f62fccd71d93959f56b2b432db10a" - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.4.0" - tapable "^1.0.0" - -enhanced-resolve@^4.1.0: +enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" dependencies: @@ -1805,12 +1793,12 @@ errno@^0.1.3, errno@~0.1.7: prr "~1.0.1" error-ex@^1.2.0, error-ex@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" dependencies: is-arrayish "^0.2.1" -es-abstract@^1.5.1: +es-abstract@^1.5.1, es-abstract@^1.7.0: version "1.12.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" dependencies: @@ -1820,16 +1808,6 @@ es-abstract@^1.5.1: is-callable "^1.1.3" is-regex "^1.0.4" -es-abstract@^1.7.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681" - dependencies: - es-to-primitive "^1.1.1" - function-bind "^1.1.1" - has "^1.0.1" - is-callable "^1.1.3" - is-regex "^1.0.4" - es-to-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" @@ -1839,8 +1817,8 @@ es-to-primitive@^1.1.1: is-symbol "^1.0.1" es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.42" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.42.tgz#8c07dd33af04d5dcd1310b5cef13bea63a89ba8d" + version "0.10.46" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.46.tgz#efd99f67c5a7ec789baa3daa7f79870388f7f572" dependencies: es6-iterator "~2.0.3" es6-symbol "~3.1.1" @@ -1877,8 +1855,8 @@ eslint-scope@^4.0.0: estraverse "^4.1.1" esprima@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" esrecurse@^4.1.0: version "4.2.1" @@ -2012,8 +1990,8 @@ external-editor@^2.0.4: tmp "^0.0.33" external-editor@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.0.tgz#dc35c48c6f98a30ca27a20e9687d7f3c77704bb6" + version "3.0.1" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.1.tgz#fc9638c4d7cde4f0bb82b12307a1a23912c492e3" dependencies: chardet "^0.5.0" iconv-lite "^0.4.22" @@ -2122,8 +2100,8 @@ flush-write-stream@^1.0.0: readable-stream "^2.0.4" follow-redirects@^1.0.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.4.1.tgz#d8120f4518190f55aac65bb6fc7b85fcd666d6aa" + version "1.5.7" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.7.tgz#a39e4804dacb90202bca76a9e2ac10433ca6a69a" dependencies: debug "^3.1.0" @@ -2131,10 +2109,6 @@ for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - foreground-child@^1.5.3, foreground-child@^1.5.6: version "1.5.6" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-1.5.6.tgz#4fd71ad2dfde96789b980a5c0a295937cb2f5ce9" @@ -2202,14 +2176,14 @@ fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fsevents@^1.1.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.3.tgz#08292982e7059f6674c93d8b829c1e8604979ac0" +fsevents@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" dependencies: nan "^2.9.2" - node-pre-gyp "^0.9.0" + node-pre-gyp "^0.10.0" -function-bind@^1.0.2, function-bind@^1.1.1: +function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -2227,8 +2201,8 @@ gauge@~2.7.3: wide-align "^1.1.0" get-caller-file@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" get-pkg-repo@^1.0.0: version "1.4.0" @@ -2305,8 +2279,8 @@ glob@7.1.2, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glo path-is-absolute "^1.0.0" global-modules-path@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/global-modules-path/-/global-modules-path-2.1.0.tgz#923ec524e8726bb0c1a4ed4b8e21e1ff80c88bbb" + version "2.3.0" + resolved "https://registry.yarnpkg.com/global-modules-path/-/global-modules-path-2.3.0.tgz#b0e2bac6beac39745f7db5c59d26a36a0b94f7dc" globals@^11.1.0: version "11.7.0" @@ -2410,10 +2384,10 @@ has-values@^1.0.0: kind-of "^4.0.0" has@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" dependencies: - function-bind "^1.0.2" + function-bind "^1.1.1" hash-base@^3.0.0: version "3.0.4" @@ -2423,11 +2397,11 @@ hash-base@^3.0.0: safe-buffer "^5.0.1" hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + version "1.1.5" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.5.tgz#e38ab4b85dfb1e0c40fe9265c0e9b54854c23812" dependencies: inherits "^2.0.3" - minimalistic-assert "^1.0.0" + minimalistic-assert "^1.0.1" he@1.1.1: version "1.1.1" @@ -2446,8 +2420,8 @@ hmac-drbg@^1.0.0: minimalistic-crypto-utils "^1.0.1" hosted-git-info@^2.1.4, hosted-git-info@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222" + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" hpack.js@^2.1.6: version "2.1.6" @@ -2485,8 +2459,8 @@ http-errors@~1.6.2: statuses ">= 1.4.0 < 2" http-parser-js@>=0.4.0: - version "0.4.12" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.12.tgz#b9cfbf4a2cf26f0fc34b10ca1489a27771e3474f" + version "0.4.13" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" http-proxy-middleware@~0.18.0: version "0.18.0" @@ -2514,19 +2488,15 @@ iconv-lite@0.4.19: resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" iconv-lite@^0.4.17, iconv-lite@^0.4.22, iconv-lite@^0.4.4: - version "0.4.23" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.11: +ieee754@^1.1.11, ieee754@^1.1.4: version "1.1.12" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" -ieee754@^1.1.4: - version "1.1.11" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455" - iferr@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" @@ -2601,8 +2571,8 @@ inquirer@^3.2.2: through "^2.3.6" inquirer@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.0.0.tgz#e8c20303ddc15bbfc2c12a6213710ccd9e1413d8" + version "6.1.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.1.0.tgz#8f65c7b31c498285f4ddf3b742ad8c487892040b" dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" @@ -2642,9 +2612,9 @@ ip@^1.1.0, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" -ipaddr.js@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" is-accessor-descriptor@^0.1.6: version "0.1.6" @@ -2679,14 +2649,14 @@ is-builtin-module@^1.0.0: builtin-modules "^1.0.0" is-callable@^1.1.1, is-callable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" is-ci@^1.0.10: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.0.tgz#3f4a08d6303a09882cef3f0fb97439c5f5ce2d53" dependencies: - ci-info "^1.0.0" + ci-info "^1.3.0" is-data-descriptor@^0.1.4: version "0.1.4" @@ -2768,20 +2738,10 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" -is-odd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" - dependencies: - is-number "^4.0.0" - is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -2929,9 +2889,13 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + js-yaml@^3.7.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -2944,9 +2908,9 @@ json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" json-stringify-safe@^5.0.1: version "5.0.1" @@ -3106,6 +3070,10 @@ lodash._reinterpolate@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" @@ -3127,7 +3095,7 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "~3.0.0" -lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0: +lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -3161,10 +3129,10 @@ longest@^1.0.1: resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" loose-envify@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" dependencies: - js-tokens "^3.0.0" + js-tokens "^3.0.0 || ^4.0.0" loud-rejection@^1.0.0, loud-rejection@^1.6.0: version "1.6.0" @@ -3185,8 +3153,8 @@ lru-cache@^4.0.1, lru-cache@^4.1.1: yallist "^2.1.2" make-dir@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" dependencies: pify "^3.0.0" @@ -3318,15 +3286,19 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.33.0 < 2", mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" +"mime-db@>= 1.34.0 < 2": + version "1.36.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" + +mime-db@~1.35.0: + version "1.35.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" mime-types@~2.1.17, mime-types@~2.1.18: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + version "2.1.19" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" dependencies: - mime-db "~1.33.0" + mime-db "~1.35.0" mime@1.4.1: version "1.4.1" @@ -3340,7 +3312,7 @@ mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" -minimalistic-assert@^1.0.0: +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -3377,11 +3349,11 @@ minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" -minipass@^2.2.1, minipass@^2.2.4: - version "2.3.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.0.tgz#2e11b1c46df7fe7f1afbe9a490280add21ffe384" +minipass@^2.2.1, minipass@^2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957" dependencies: - safe-buffer "^5.1.1" + safe-buffer "^5.1.2" yallist "^3.0.0" minizlib@^1.1.0: @@ -3439,8 +3411,8 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" moment@^2.6.0: - version "2.22.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.1.tgz#529a2e9bf973f259c9643d237fda84de3a26e8ad" + version "2.22.2" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" move-concurrently@^1.0.1: version "1.0.1" @@ -3477,15 +3449,14 @@ nan@^2.9.2: resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" nanomatch@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" define-property "^2.0.2" extend-shallow "^3.0.2" fragment-cache "^0.2.1" - is-odd "^2.0.0" is-windows "^1.0.2" kind-of "^6.0.2" object.pick "^1.3.0" @@ -3493,9 +3464,9 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -needle@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" +needle@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.2.tgz#1120ca4c41f2fcc6976fd28a8968afe239929418" dependencies: debug "^2.1.2" iconv-lite "^0.4.4" @@ -3506,8 +3477,8 @@ negotiator@0.6.1: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" neo-async@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee" + version "2.5.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.2.tgz#489105ce7bc54e709d736b195f82135048c50fcc" next-tick@1: version "1.0.0" @@ -3549,17 +3520,17 @@ node-libs-browser@^2.0.0: util "^0.10.3" vm-browserify "0.0.4" -node-pre-gyp@^0.9.0: - version "0.9.1" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.9.1.tgz#f11c07516dd92f87199dbc7e1838eab7cd56c9e0" +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" dependencies: detect-libc "^1.0.2" mkdirp "^0.5.1" - needle "^2.2.0" + needle "^2.2.1" nopt "^4.0.1" npm-packlist "^1.1.6" npmlog "^4.0.2" - rc "^1.1.7" + rc "^1.2.7" rimraf "^2.6.1" semver "^5.3.0" tar "^4" @@ -3587,12 +3558,12 @@ normalize-path@^2.1.1: remove-trailing-separator "^1.0.1" npm-bundled@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + version "1.0.5" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" npm-packlist@^1.1.6: - version "1.1.10" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" + version "1.1.11" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" dependencies: ignore-walk "^3.0.1" npm-bundled "^1.0.1" @@ -3660,9 +3631,9 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-keys@^1.0.11, object-keys@^1.0.8: - version "1.0.11" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" +object-keys@^1.0.11, object-keys@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" object-visit@^1.0.0: version "1.0.1" @@ -3732,10 +3703,10 @@ optimist@^0.6.1: wordwrap "~0.0.2" original@>=0.0.5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b" + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" dependencies: - url-parse "1.0.x" + url-parse "^1.4.3" os-browserify@^0.3.0: version "0.3.0" @@ -3769,8 +3740,8 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" p-limit@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" dependencies: p-try "^1.0.0" @@ -3891,8 +3862,8 @@ path-key@^2.0.0, path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" path-to-regexp@0.1.7: version "0.1.7" @@ -3967,8 +3938,8 @@ platform@^1.3.3: resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.5.tgz#fb6958c696e07e2918d2eeda0f0bc9448d733444" portfinder@^1.0.9: - version "1.0.13" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + version "1.0.17" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.17.tgz#a8a1691143e46c4735edefcf4fbcccedad26456a" dependencies: async "^1.5.2" debug "^2.2.0" @@ -3999,11 +3970,11 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" proxy-addr@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" dependencies: forwarded "~0.1.2" - ipaddr.js "1.6.0" + ipaddr.js "1.8.0" prr@~1.0.1: version "1.0.1" @@ -4031,8 +4002,8 @@ pump@^2.0.0, pump@^2.0.1: once "^1.3.1" pumpify@^1.3.3: - version "1.5.0" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.0.tgz#30c905a26c88fa0074927af07256672b474b1c15" + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" dependencies: duplexify "^3.6.0" inherits "^2.0.3" @@ -4047,8 +4018,8 @@ punycode@^1.2.4: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" punycode@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" q@^1.4.1, q@^1.5.1: version "1.5.1" @@ -4066,10 +4037,6 @@ querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" -querystringify@0.0.x: - version "0.0.4" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.4.tgz#0cf7f84f9463ff0ae51c4c4b142d95be37724d9c" - querystringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.0.0.tgz#fa3ed6e68eb15159457c89b37bc6472833195755" @@ -4104,11 +4071,11 @@ raw-body@2.3.2: iconv-lite "0.4.19" unpipe "1.0.0" -rc@^1.0.1, rc@^1.1.6, rc@^1.1.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.7.tgz#8a10ca30d588d00464360372b890d06dacd02297" +rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" dependencies: - deep-extend "^0.5.1" + deep-extend "^0.6.0" ini "~1.3.0" minimist "^1.2.0" strip-json-comments "~2.0.1" @@ -4164,7 +4131,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3, readable-stream@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -4230,8 +4197,8 @@ remove-trailing-separator@^1.0.1: resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" @@ -4251,7 +4218,7 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" -requires-port@1.0.x, requires-port@^1.0.0: +requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -4274,8 +4241,8 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" resolve@^1.1.6, resolve@^1.3.2: - version "1.7.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3" + version "1.8.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" dependencies: path-parse "^1.0.5" @@ -4341,7 +4308,7 @@ safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -4360,8 +4327,8 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" schema-utils@^0.4.4, schema-utils@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" + version "0.4.7" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" dependencies: ajv "^6.1.0" ajv-keywords "^3.1.0" @@ -4377,8 +4344,8 @@ selfsigned@^1.9.1: node-forge "0.7.5" "semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + version "5.5.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" send@0.16.2: version "0.16.2" @@ -4554,10 +4521,10 @@ source-list-map@^2.0.0: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" source-map-resolve@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" dependencies: - atob "^2.0.0" + atob "^2.1.1" decode-uri-component "^0.2.0" resolve-url "^0.2.1" source-map-url "^0.4.0" @@ -4688,19 +4655,19 @@ stream-browserify@^2.0.1: readable-stream "^2.0.2" stream-each@^1.1.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.2.tgz#8e8c463f91da8991778765873fe4d960d8f616bd" + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" dependencies: end-of-stream "^1.1.0" stream-shift "^1.0.0" stream-http@^2.7.2: - version "2.8.1" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.1.tgz#d0441be1a457a73a733a8a7b53570bebd9ef66a4" + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" dependencies: builtin-status-codes "^3.0.0" inherits "^2.0.1" - readable-stream "^2.3.3" + readable-stream "^2.3.6" to-arraybuffer "^1.0.0" xtend "^4.0.0" @@ -4708,7 +4675,7 @@ stream-shift@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" -string-width@^1.0.1, string-width@^1.0.2: +string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: @@ -4716,7 +4683,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: @@ -4779,7 +4746,7 @@ strong-log-transformer@^1.0.6: moment "^2.6.0" through "^2.3.4" -supports-color@5.4.0, supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0: +supports-color@5.4.0: version "5.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" dependencies: @@ -4795,17 +4762,23 @@ supports-color@^3.1.2: dependencies: has-flag "^1.0.0" +supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + dependencies: + has-flag "^3.0.0" + tapable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" tar@^4: - version "4.4.2" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.2.tgz#60685211ba46b38847b1ae7ee1a24d744a2cd462" + version "4.4.6" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" dependencies: chownr "^1.0.1" fs-minipass "^1.2.5" - minipass "^2.2.4" + minipass "^2.3.3" minizlib "^1.1.0" mkdirp "^0.5.0" safe-buffer "^5.1.2" @@ -4925,8 +4898,8 @@ trim-right@^1.0.1: resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" ts-loader@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-4.4.2.tgz#778d4464b24436873c78f7f9e914d88194c2a248" + version "4.5.0" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-4.5.0.tgz#a1ce70b2dc799941fb2197605f0d67874097859b" dependencies: chalk "^2.3.0" enhanced-resolve "^4.0.0" @@ -4934,11 +4907,7 @@ ts-loader@^4.4.2: micromatch "^3.1.4" semver "^5.0.1" -tslib@^1.8.0, tslib@^1.8.1: - version "1.9.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" - -tslib@^1.9.0: +tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" @@ -5035,8 +5004,8 @@ uglify-to-browserify@~1.0.0: resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" uglifyjs-webpack-plugin@^1.2.4: - version "1.2.5" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.5.tgz#2ef8387c8f1a903ec5e44fa36f9f3cbdcea67641" + version "1.3.0" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz#75f548160858163a08643e086d5fefe18a5d67de" dependencies: cacache "^10.0.4" find-cache-dir "^1.0.0" @@ -5069,8 +5038,8 @@ unique-slug@^2.0.0: imurmurhash "^0.1.4" universalify@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" @@ -5087,13 +5056,13 @@ unzip-response@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" -upath@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.5.tgz#02cab9ecebe95bbec6d5fc2566325725ab6d1a73" +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" -uri-js@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.1.tgz#4595a80a51f356164e22970df64c7abd6ade9850" +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" dependencies: punycode "^2.1.0" @@ -5111,16 +5080,9 @@ url-parse-lax@^1.0.0: dependencies: prepend-http "^1.0.1" -url-parse@1.0.x: - version "1.0.5" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b" - dependencies: - querystringify "0.0.x" - requires-port "1.0.x" - -url-parse@^1.1.8: - version "1.4.0" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.0.tgz#6bfdaad60098c7fe06f623e42b22de62de0d3d75" +url-parse@^1.1.8, url-parse@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.3.tgz#bfaee455c889023219d757e045fa6a684ec36c15" dependencies: querystringify "^2.0.0" requires-port "^1.0.0" @@ -5133,10 +5095,8 @@ url@^0.11.0: querystring "0.2.0" use@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544" - dependencies: - kind-of "^6.0.2" + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" util-deprecate@~1.0.1: version "1.0.2" @@ -5149,12 +5109,18 @@ util.promisify@^1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" -util@0.10.3, util@^0.10.3: +util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" dependencies: inherits "2.0.1" +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + dependencies: + inherits "2.0.3" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -5164,16 +5130,16 @@ uuid@^2.0.1: resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" uuid@^3.0.1, uuid@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" v8-compile-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.0.tgz#526492e35fc616864284700b7043e01baee09f0a" + version "2.0.2" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c" validate-npm-package-license@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" @@ -5286,8 +5252,8 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0: source-map "~0.6.1" webpack@^4.16.3: - version "4.16.3" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.3.tgz#861be3176d81e7e3d71c66c8acc9bba35588b525" + version "4.17.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.17.1.tgz#0f026e3d823f3fc604f811ed3ea8f0d9b267fb1e" dependencies: "@webassemblyjs/ast" "1.5.13" "@webassemblyjs/helper-module-context" "1.5.13" @@ -5331,16 +5297,16 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" which@^1.2.9, which@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" dependencies: isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" dependencies: - string-width "^1.0.2" + string-width "^1.0.2 || 2" window-size@0.1.0: version "0.1.0" @@ -5399,8 +5365,8 @@ write-json-file@^2.2.0: write-file-atomic "^2.0.0" write-pkg@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-3.1.0.tgz#030a9994cc9993d25b4e75a9f1a1923607291ce9" + version "3.2.0" + resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-3.2.0.tgz#0e178fe97820d389a8928bc79535dbe68c2cff21" dependencies: sort-keys "^2.0.0" write-json-file "^2.2.0" From 519394b3d571a2a231092b37d355e0a30f287bc2 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 23 Aug 2018 03:11:52 +0100 Subject: [PATCH 49/68] feat(api): add NumericArray and TypedArray types --- packages/api/src/api.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/api/src/api.ts b/packages/api/src/api.ts index 32b3bd9749..0bf5d75c77 100644 --- a/packages/api/src/api.ts +++ b/packages/api/src/api.ts @@ -31,6 +31,8 @@ export type FnAny = (...xs: any[]) => T; */ export type Listener = (e: Event) => void; +export type NumericArray = number[] | TypedArray; + /** * Lookup path for nested data structures. */ @@ -61,6 +63,17 @@ export type StatefulPredicate = () => Predicate; */ export type StatefulPredicate2 = () => Predicate2; +export type TypedArray = + Float32Array | + Float64Array | + Int8Array | + Int16Array | + Int32Array | + Uint8Array | + Uint8ClampedArray | + Uint16Array | + Uint32Array; + /** * Observer function for `IWatch` implementations. */ From fb3c04dac0914f392fe883d3f146314fc5e70638 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 23 Aug 2018 03:12:43 +0100 Subject: [PATCH 50/68] refactor(vectors): make Vec & Mat type aliases of NumericArray --- packages/vectors/src/api.ts | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/packages/vectors/src/api.ts b/packages/vectors/src/api.ts index cddbc9d511..81efc2408a 100644 --- a/packages/vectors/src/api.ts +++ b/packages/vectors/src/api.ts @@ -1,18 +1,9 @@ -export type TypedArray = - Float32Array | - Float64Array | - Int8Array | - Int16Array | - Int32Array | - Uint8Array | - Uint8ClampedArray | - Uint16Array | - Uint32Array; +import { NumericArray } from "@thi.ng/api/api"; -export type Vec = number[] | TypedArray; +export type Vec = NumericArray; export type ReadonlyVec = ArrayLike; -export type Mat = number[] | TypedArray; +export type Mat = NumericArray; export type ReadonlyMat = ArrayLike; export type VecOp = (a: Vec, b: ReadonlyVec, ia: number, ib: number, sa: number, sb: number) => Vec; From 0bd860e6257009f4b05c8031661f2240dfafc33e Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 23 Aug 2018 03:15:02 +0100 Subject: [PATCH 51/68] feat(transducers): add fill() & fillN() reducers --- packages/transducers/src/index.ts | 1 + packages/transducers/src/rfn/fill.ts | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 packages/transducers/src/rfn/fill.ts diff --git a/packages/transducers/src/index.ts b/packages/transducers/src/index.ts index d012223abb..a49b11f8b9 100644 --- a/packages/transducers/src/index.ts +++ b/packages/transducers/src/index.ts @@ -12,6 +12,7 @@ export * from "./rfn/assoc-obj"; export * from "./rfn/conj"; export * from "./rfn/count"; export * from "./rfn/every"; +export * from "./rfn/fill"; export * from "./rfn/frequencies"; export * from "./rfn/group-binary"; export * from "./rfn/group-by-map"; diff --git a/packages/transducers/src/rfn/fill.ts b/packages/transducers/src/rfn/fill.ts new file mode 100644 index 0000000000..d52c4e9728 --- /dev/null +++ b/packages/transducers/src/rfn/fill.ts @@ -0,0 +1,23 @@ +import { NumericArray } from "@thi.ng/api/api"; + +import { Reducer } from "../api"; +import { reducer } from "../reduce"; + +/** + * Reducer which starts filling array with results from given `start` + * index (default: 0). + * + * @param start + */ +export function fill(start = 0): Reducer { + return reducer(() => [], (acc, x) => (acc[start++] = x, acc)); +} + +/** + * Like `fill()` reducer, but for numeric arrays (incl. typed arrays). + * + * @param start + */ +export function fillN(start = 0): Reducer { + return fill(start); +} From 8565edb811fcfcf05da12040dd6ca5b77fdb1b73 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 23 Aug 2018 03:20:20 +0100 Subject: [PATCH 52/68] fix(rle-pack): fix initial repeat counts in encodeBytes(), update readme --- packages/rle-pack/README.md | 18 ++++++++++-------- packages/rle-pack/src/index.ts | 11 ++++++----- packages/rle-pack/test/index.ts | 12 +++++++++++- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/packages/rle-pack/README.md b/packages/rle-pack/README.md index c46c7118b2..d4ceac866b 100644 --- a/packages/rle-pack/README.md +++ b/packages/rle-pack/README.md @@ -7,8 +7,8 @@ This project is part of the ## About -Binary run-length encoding packer/unpacker w/ flexible repeat bit -widths. Written in TypeScript, distributed in ES6. +Binary run-length encoding packer/unpacker w/ support for flexible input +word sizes and repeat bit widths. Encoding format: @@ -17,13 +17,15 @@ Encoding format: Then per value: - 1 bit - encoding flag (1 = RLE encoded, 0 = single occurrence) -- 8 bits - value +- n bits - value The following is only used for repeated values: - 2 bits - repeat class - 3/4/8/16 bits - repeat count - 1 (if > 0x10000 then split into chunks...) +Brief overview for 8-bit word size (default): + | Repeats | Original (bits) | RLE (bits) | Saving (bits) | Ratio | |---------|-----------------|------------|---------------|----------| | 1 | 8 | 1+8 | -1 | 1.125 | @@ -61,15 +63,15 @@ let rle = require("@thi.ng/rle-pack"); src = new Uint8Array(1024); src.set([1,1,1,1,1,2,2,2,2,3,3,3,4,4,5,4,4,3,3,3,2,2,2,2,1,1,1,1,1], 512); -// pack data -packed = rle.encodeBytes(src); -// Uint8Array [0,0,4,0,128,96,63,240,18,64,135,3,20,16,32,88,32,96,98,129,14,2,72,6,3,196] +// pack data (word size = 3 bits, i.e. value range 0 - 7) +packed = rle.encodeBytes(src, src.length, 3); +// Uint8Array [0, 0, 4, 0, 140, 7, 254, 73, 67, 177, 96, 87, 3, 98, 161, 201, 35, 1, 226] packed.length -// 26 => 2.5% of original +// 19 => 1.85% of original // unpack -dest = rle.decodeBytes(packed); +unpacked = rle.decodeBytes(packed, 3); ``` ## Authors diff --git a/packages/rle-pack/src/index.ts b/packages/rle-pack/src/index.ts index edf23741c8..4466d5fd56 100644 --- a/packages/rle-pack/src/index.ts +++ b/packages/rle-pack/src/index.ts @@ -11,21 +11,21 @@ const RLE_SIZES = [3, 4, 8, 16]; * @param wordSize in bits, MUST be <= 8 */ export function encodeBytes(src: Iterable, num: number, wordSize = 8) { - const stream = new BitOutputStream(num * wordSize / 8).write(num, 32); + const stream = new BitOutputStream(Math.ceil(num * wordSize / 8)).write(num, 32); const n1 = num - 1; let val; let tail = true; - let n = -1; - let i = 0, t; + let n = 0; + let i = 0; const write = () => { stream.write(n > 0 ? 1 : 0, 1); stream.write(val, wordSize); if (n > 0) { - t = (n < 0x8) ? 0 : (n < 0x10) ? 1 : (n < 0x100) ? 2 : 3; + const t = (n < 0x8) ? 0 : (n < 0x10) ? 1 : (n < 0x100) ? 2 : 3; stream.write(t, 2); stream.write(n, RLE_SIZES[t]); + n = 0; } - n = 0; }; for (let x of src) { if (val === undefined) { @@ -67,3 +67,4 @@ export function decodeBytes(src: Uint8Array, wordSize = 8) { } return out; } + diff --git a/packages/rle-pack/test/index.ts b/packages/rle-pack/test/index.ts index e9cda36d84..a21dabb006 100644 --- a/packages/rle-pack/test/index.ts +++ b/packages/rle-pack/test/index.ts @@ -1,3 +1,13 @@ +import * as assert from "assert"; +import { encodeBytes, decodeBytes } from "../src/index"; + describe("rle-pack", () => { - it("tests pending"); + it("3bit", () => { + const src = new Uint8Array(1024); + src.set([1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1], 512); + const packed = encodeBytes(src, src.length, 3); + assert.deepEqual(packed, [0, 0, 4, 0, 140, 7, 254, 73, 67, 177, 96, 87, 3, 98, 161, 201, 35, 1, 226]); + const dest = decodeBytes(packed, 3); + assert.deepEqual(dest, src); + }); }); From 2c3a1147d9a895e6641990ca187e81a526afd306 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 23 Aug 2018 18:24:23 +0100 Subject: [PATCH 53/68] feat(transducers): add GroupByOpts interface, update groupBy* reducers - add support for direct reduction if optional iterable is provided BREAKING CHANGE: groupByMap() & groupByObj() args now given as options object --- packages/transducers/src/api.ts | 5 +++ packages/transducers/src/rfn/group-binary.ts | 34 +++++++++++--------- packages/transducers/src/rfn/group-by-map.ts | 32 ++++++++++++------ packages/transducers/src/rfn/group-by-obj.ts | 30 ++++++++++++----- 4 files changed, 68 insertions(+), 33 deletions(-) diff --git a/packages/transducers/src/api.ts b/packages/transducers/src/api.ts index 83fed71217..b6265e275a 100644 --- a/packages/transducers/src/api.ts +++ b/packages/transducers/src/api.ts @@ -35,3 +35,8 @@ export interface SortOpts { */ compare: Comparator; } + +export interface GroupByOpts { + key: Fn; + group: Reducer; +} diff --git a/packages/transducers/src/rfn/group-binary.ts b/packages/transducers/src/rfn/group-binary.ts index 12abc55abf..73e90a6bd5 100644 --- a/packages/transducers/src/rfn/group-binary.ts +++ b/packages/transducers/src/rfn/group-binary.ts @@ -11,16 +11,17 @@ function branchPred(key: (x: T) => number, b: number, l: PropertyKey, r: Prop /** * Creates a bottom-up, unbalanced binary tree of desired depth and * choice of data structures. Any value can be indexed, as long as a - * numeric representation (key) can be obtained. This mapping is produced - * by the supplied `key` function. IMPORTANT: the returned values - * MUST be unsigned and less than the provided bit length (i.e. 2^`bits`). + * numeric representation (key) can be obtained. This numeric key is + * produced by the supplied `key` function. IMPORTANT: the returned + * values MUST be unsigned and less than the provided bit length (i.e. + * `0 .. (2^bits) - 1` range). * * By default the tree is constructed using plain objects for branches, * with left branches stored as "l" and right ones as "r". The original - * values are stored at the lowest tree level using a customizable nested - * reducer. By default leaves are collected in arrays (using the `push()` - * reducer), but any suitable reducer can be used (e.g. `conj()` to - * collect values into sets). + * values are stored at the lowest tree level using a customizable + * nested reducer. By default leaves are collected in arrays (using the + * `push()` reducer), but any suitable reducer can be used (e.g. + * `conj()` to collect values into sets). * * Index by lowest 4-bits of ID value: * @@ -72,7 +73,8 @@ function branchPred(key: (x: T) => number, b: number, l: PropertyKey, r: Prop * * @param bits index range (always from 0) * @param key key function - * @param branch function to create a new branch container (object or array) + * @param branch function to create a new branch container (object or + * array) * @param leaf reducer for leaf collection * @param left key for storing left branches (e.g. `0` for arrays) * @param right key for storing right branches (e.g. `1` for arrays) @@ -81,17 +83,17 @@ export function groupBinary( bits: number, key: (x: T) => number, branch?: () => IObjectOf, - leaf: Reducer = push(), + leaf?: Reducer, left: PropertyKey = "l", right: PropertyKey = "r") { - let rfn: Reducer = groupByObj( - branchPred(key, 1, left, right), - leaf, - branch - ); + const init = branch || (() => ({})); + let rfn: Reducer = groupByObj({ + key: branchPred(key, 1, left, right), + group: leaf || push(), + }); for (let i = 2, maxIndex = 1 << bits; i < maxIndex; i <<= 1) { - rfn = groupByObj(branchPred(key, i, left, right), rfn, branch); + rfn = groupByObj({ key: branchPred(key, i, left, right), group: [init, rfn[1], rfn[2]] }); } - return rfn; + return [init, rfn[1], rfn[2]]; } diff --git a/packages/transducers/src/rfn/group-by-map.ts b/packages/transducers/src/rfn/group-by-map.ts index f914ae7e25..279d2b1eb8 100644 --- a/packages/transducers/src/rfn/group-by-map.ts +++ b/packages/transducers/src/rfn/group-by-map.ts @@ -1,18 +1,32 @@ -import { Reducer } from "../api"; - +import { Reducer, GroupByOpts } from "../api"; import { identity } from "../func/identity"; +import { $$reduce, reducer } from "../reduce"; import { push } from "./push"; -import { reducer } from "../reduce"; -export function groupByMap(key: ((x: A) => B) = identity, rfn: Reducer = push()): Reducer, A> { - return reducer( +export function groupByMap(opts?: Partial>): Reducer, SRC>; +export function groupByMap(xs: Iterable): Map; +export function groupByMap(opts: Partial>, xs: Iterable): Map; +export function groupByMap(...args: any[]): any { + const res = $$reduce(groupByMap, args); + if (res !== undefined) { + return res; + } + const opts = >{ + key: identity, + group: push(), + ...args[0] + }; + const [init, _, reduce] = opts.group; _; + return reducer, SRC>( () => new Map(), (acc, x) => { - const k = key(x); - return acc.set(k, + const k = opts.key(x); + return acc.set( + k, acc.has(k) ? - rfn[2](acc.get(k), x) : - rfn[2](rfn[0](), x)); + reduce(acc.get(k), x) : + reduce(init(), x) + ); } ); } diff --git a/packages/transducers/src/rfn/group-by-obj.ts b/packages/transducers/src/rfn/group-by-obj.ts index 5877e3c5a4..4f706a67bd 100644 --- a/packages/transducers/src/rfn/group-by-obj.ts +++ b/packages/transducers/src/rfn/group-by-obj.ts @@ -1,17 +1,31 @@ import { IObjectOf } from "@thi.ng/api/api"; -import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { GroupByOpts, Reducer } from "../api"; +import { identity } from "../func/identity"; +import { reducer, $$reduce } from "../reduce"; import { push } from "./push"; -export function groupByObj(key: (x: A) => PropertyKey, rfn: Reducer = push(), init?: () => IObjectOf): Reducer, A> { +export function groupByObj(opts?: Partial>): Reducer, SRC>; +export function groupByObj(xs: Iterable): IObjectOf; +export function groupByObj(opts: Partial>, xs: Iterable): IObjectOf; +export function groupByObj(...args: any[]): any { + const res = $$reduce(groupByObj, args); + if (res) { + return res; + } + const _opts = >{ + key: identity, + group: push(), + ...args[0] + }; + const [_init, _, _reduce] = _opts.group; _; return reducer( - init || (() => new Object()), - (acc, x) => { - const k = key(x); + () => ({}), + (acc, x: SRC) => { + const k: any = _opts.key(x); acc[k] = acc[k] ? - rfn[2](acc[k], x) : - rfn[2](rfn[0](), x); + _reduce(acc[k], x) : + _reduce(_init(), x); return acc; } ); From 89b4ad5d13637014e1a7385d119b198d6136c985 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 23 Aug 2018 18:43:12 +0100 Subject: [PATCH 54/68] feat(transducers): update all reducers to accept opt iterables - add $$reduce helper - fix str() to use string concatenation (instead of Array.join()) - add opt init vals for add() & mul() - add sub() & div() reducers --- packages/transducers/src/index.ts | 2 ++ packages/transducers/src/reduce.ts | 14 +++++++-- packages/transducers/src/rfn/add.ts | 16 ++++++++--- packages/transducers/src/rfn/assoc-map.ts | 12 ++++++-- packages/transducers/src/rfn/assoc-obj.ts | 16 +++++++---- packages/transducers/src/rfn/conj.ts | 10 +++++-- packages/transducers/src/rfn/count.ts | 14 +++++++-- packages/transducers/src/rfn/div.ts | 14 +++++++++ packages/transducers/src/rfn/every.ts | 12 ++++++-- packages/transducers/src/rfn/fill.ts | 19 +++++++++--- packages/transducers/src/rfn/frequencies.ts | 12 ++++++-- packages/transducers/src/rfn/last.ts | 10 +++++-- packages/transducers/src/rfn/max-compare.ts | 13 +++++++-- packages/transducers/src/rfn/max.ts | 10 +++++-- packages/transducers/src/rfn/mean.ts | 17 +++++++---- packages/transducers/src/rfn/min-compare.ts | 13 +++++++-- packages/transducers/src/rfn/min.ts | 10 +++++-- packages/transducers/src/rfn/mul.ts | 18 ++++++++++-- packages/transducers/src/rfn/push.ts | 8 ++++-- packages/transducers/src/rfn/reductions.ts | 32 ++++++++++++--------- packages/transducers/src/rfn/some.ts | 12 ++++++-- packages/transducers/src/rfn/str.ts | 18 ++++++++---- packages/transducers/src/rfn/sub.ts | 18 ++++++++++++ 23 files changed, 247 insertions(+), 73 deletions(-) create mode 100644 packages/transducers/src/rfn/div.ts create mode 100644 packages/transducers/src/rfn/sub.ts diff --git a/packages/transducers/src/index.ts b/packages/transducers/src/index.ts index a49b11f8b9..fe700680d2 100644 --- a/packages/transducers/src/index.ts +++ b/packages/transducers/src/index.ts @@ -11,6 +11,7 @@ export * from "./rfn/assoc-map"; export * from "./rfn/assoc-obj"; export * from "./rfn/conj"; export * from "./rfn/count"; +export * from "./rfn/div"; export * from "./rfn/every"; export * from "./rfn/fill"; export * from "./rfn/frequencies"; @@ -29,6 +30,7 @@ export * from "./rfn/push"; export * from "./rfn/reductions"; export * from "./rfn/some"; export * from "./rfn/str"; +export * from "./rfn/sub"; export * from "./xform/base64"; export * from "./xform/benchmark"; diff --git a/packages/transducers/src/reduce.ts b/packages/transducers/src/reduce.ts index dc5999beb5..b76200d7da 100644 --- a/packages/transducers/src/reduce.ts +++ b/packages/transducers/src/reduce.ts @@ -1,9 +1,10 @@ import { implementsFunction } from "@thi.ng/checks/implements-function"; import { isArrayLike } from "@thi.ng/checks/is-arraylike"; +import { isIterable } from "@thi.ng/checks/is-iterable"; import { illegalArity } from "@thi.ng/errors/illegal-arity"; -import { Reducer, IReducible } from "./api"; -import { isReduced, unreduced, Reduced } from "./reduced"; +import { IReducible, Reducer } from "./api"; +import { isReduced, Reduced, unreduced } from "./reduced"; export function reduce(rfn: Reducer, xs: Iterable): A; export function reduce(rfn: Reducer, acc: A, xs: Iterable): A; @@ -57,3 +58,12 @@ export function reduce(...args: any[]): A { export function reducer(init: () => A, rfn: (acc: A, x: B) => A | Reduced) { return >[init, (acc) => acc, rfn]; } + +export const $$reduce = (rfn: (...args: any[]) => Reducer, args: any[]) => { + const n = args.length - 1; + return isIterable(args[n]) ? + args.length > 1 ? + reduce(rfn.apply(null, args.slice(0, n)), args[n]) : + reduce(rfn(), args[0]) : + undefined; +}; diff --git a/packages/transducers/src/rfn/add.ts b/packages/transducers/src/rfn/add.ts index 419c9b1e91..17aa67c9ea 100644 --- a/packages/transducers/src/rfn/add.ts +++ b/packages/transducers/src/rfn/add.ts @@ -1,9 +1,17 @@ import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { $$reduce, reducer } from "../reduce"; /** - * Reducer to compute sum of values. + * Reducer to compute sum of values with given `init` value. */ -export function add(): Reducer { - return reducer(() => 0, (acc, x) => acc + x); +export function add(init?: number): Reducer; +export function add(xs: Iterable): number; +export function add(init: number, xs: Iterable): number; +export function add(...args: any[]): any { + const res = $$reduce(add, args); + if (res !== undefined) { + return res; + } + const init = args[0] || 0; + return reducer(() => init, (acc, x: number) => acc + x); } diff --git a/packages/transducers/src/rfn/assoc-map.ts b/packages/transducers/src/rfn/assoc-map.ts index 9d800ec5c2..24acf2f757 100644 --- a/packages/transducers/src/rfn/assoc-map.ts +++ b/packages/transducers/src/rfn/assoc-map.ts @@ -1,10 +1,16 @@ +import { Pair } from "@thi.ng/api/api"; + import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { reducer, reduce } from "../reduce"; /** * Reducer accepting key-value pairs / tuples and transforming / adding * them to an ES6 Map. */ -export function assocMap(): Reducer, [A, B]> { - return reducer(() => new Map(), (acc, [k, v]) => acc.set(k, v)); +export function assocMap(): Reducer, Pair>; +export function assocMap(xs: Iterable>): Map; +export function assocMap(xs?: Iterable>): any { + return xs ? + reduce(assocMap(), xs) : + reducer(() => new Map(), (acc, [k, v]) => acc.set(k, v)); } diff --git a/packages/transducers/src/rfn/assoc-obj.ts b/packages/transducers/src/rfn/assoc-obj.ts index 707813fe93..410f78eeaa 100644 --- a/packages/transducers/src/rfn/assoc-obj.ts +++ b/packages/transducers/src/rfn/assoc-obj.ts @@ -1,12 +1,16 @@ -import { IObjectOf } from "@thi.ng/api/api"; +import { IObjectOf, Pair } from "@thi.ng/api/api"; import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { reduce, reducer } from "../reduce"; /** - * Reducer accepting key-value pairs / tuples and transforming / adding - * them to an object. + * Reducer accepting key-value pairs / tuples and updating / adding them + * to an object. */ -export function assocObj(): Reducer, [PropertyKey, T]> { - return reducer(() => new Object(), (acc, [k, v]) => (acc[k] = v, acc)); +export function assocObj(): Reducer, Pair>; +export function assocObj(xs: Iterable>): IObjectOf; +export function assocObj(xs?: Iterable>): any { + return xs ? + reduce(assocObj(), xs) : + reducer(() => new Object(), (acc, [k, v]) => (acc[k] = v, acc)); } diff --git a/packages/transducers/src/rfn/conj.ts b/packages/transducers/src/rfn/conj.ts index 645e72386e..bf2c9ca72d 100644 --- a/packages/transducers/src/rfn/conj.ts +++ b/packages/transducers/src/rfn/conj.ts @@ -1,9 +1,13 @@ import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { reduce, reducer } from "../reduce"; /** * Reducer. Like `push()`, but for ES6 Sets. */ -export function conj(): Reducer, T> { - return reducer(() => new Set(), (acc, x) => acc.add(x)); +export function conj(): Reducer, T>; +export function conj(xs: Iterable): Set; +export function conj(xs?: Iterable): any { + return xs ? + reduce(conj(), xs) : + reducer(() => new Set(), (acc, x) => acc.add(x)); } diff --git a/packages/transducers/src/rfn/count.ts b/packages/transducers/src/rfn/count.ts index 7724b6c21b..92cbc51996 100644 --- a/packages/transducers/src/rfn/count.ts +++ b/packages/transducers/src/rfn/count.ts @@ -1,5 +1,5 @@ import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { reducer, $$reduce } from "../reduce"; /** * Reducer which ignores incoming values and instead only counts them, @@ -8,6 +8,16 @@ import { reducer } from "../reduce"; * @param offset * @param step */ -export function count(offset = 0, step = 1): Reducer { +export function count(offset?: number, step?: number): Reducer; +export function count(xs: Iterable): number; +export function count(offset: number, xs: Iterable): number; +export function count(offset: number, step: number, xs: Iterable): number; +export function count(...args: any[]): any { + const res = $$reduce(count, args); + if (res !== undefined) { + return res; + } + let offset: number = args[0] || 0; + let step: number = args[1] || 1; return reducer(() => offset, (acc, _) => acc + step); } diff --git a/packages/transducers/src/rfn/div.ts b/packages/transducers/src/rfn/div.ts new file mode 100644 index 0000000000..a83e7be087 --- /dev/null +++ b/packages/transducers/src/rfn/div.ts @@ -0,0 +1,14 @@ +import { Reducer } from "../api"; +import { reduce, reducer } from "../reduce"; + +/** + * Reducer to compute successive division of values using given `init` + * value. + */ +export function div(init: number): Reducer; +export function div(init: number, xs: Iterable): number; +export function div(init: number, xs?: Iterable): any { + return xs ? + reduce(div(init), xs) : + reducer(() => init, (acc, x: number) => acc / x); +} diff --git a/packages/transducers/src/rfn/every.ts b/packages/transducers/src/rfn/every.ts index db9dffad0d..e18a366709 100644 --- a/packages/transducers/src/rfn/every.ts +++ b/packages/transducers/src/rfn/every.ts @@ -1,7 +1,7 @@ import { Predicate } from "@thi.ng/api/api"; import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { $$reduce, reducer } from "../reduce"; import { reduced } from "../reduced"; /** @@ -19,7 +19,15 @@ import { reduced } from "../reduced"; * * @param pred */ -export function every(pred?: Predicate): Reducer { +export function every(pred?: Predicate): Reducer; +export function every(xs: Iterable): boolean; +export function every(pred: Predicate, xs: Iterable): boolean; +export function every(...args: any[]): any { + const res = $$reduce(every, args); + if (res !== undefined) { + return res; + } + const pred = args[0]; return reducer( () => true, pred ? diff --git a/packages/transducers/src/rfn/fill.ts b/packages/transducers/src/rfn/fill.ts index d52c4e9728..bddf6c1564 100644 --- a/packages/transducers/src/rfn/fill.ts +++ b/packages/transducers/src/rfn/fill.ts @@ -1,7 +1,7 @@ import { NumericArray } from "@thi.ng/api/api"; import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { reducer, $$reduce } from "../reduce"; /** * Reducer which starts filling array with results from given `start` @@ -9,7 +9,15 @@ import { reducer } from "../reduce"; * * @param start */ -export function fill(start = 0): Reducer { +export function fill(start?: number): Reducer; +export function fill(xs: Iterable): T[]; +export function fill(start: number, xs: Iterable): T[]; +export function fill(...args: any[]): any { + const res = $$reduce(fill, args); + if (res !== undefined) { + return res; + } + let start = args[0] || 0; return reducer(() => [], (acc, x) => (acc[start++] = x, acc)); } @@ -18,6 +26,9 @@ export function fill(start = 0): Reducer { * * @param start */ -export function fillN(start = 0): Reducer { - return fill(start); +export function fillN(start?: number): Reducer; +export function fillN(xs: Iterable): NumericArray; +export function fillN(start: number, xs: Iterable): NumericArray; +export function fillN(...args: any[]): any { + return fill(...args); } diff --git a/packages/transducers/src/rfn/frequencies.ts b/packages/transducers/src/rfn/frequencies.ts index 73758c0225..3554709c87 100644 --- a/packages/transducers/src/rfn/frequencies.ts +++ b/packages/transducers/src/rfn/frequencies.ts @@ -1,8 +1,16 @@ +import { Fn } from "@thi.ng/api/api"; + import { Reducer } from "../api"; import { identity } from "../func/identity"; +import { $$reduce } from "../reduce"; import { count } from "./count"; import { groupByMap } from "./group-by-map"; -export function frequencies(key: ((x: A) => B) = identity): Reducer, A> { - return groupByMap(key, count()); +export function frequencies(): Reducer, A>; +export function frequencies(xs: Iterable): Map; +export function frequencies(key: Fn): Reducer, A>; +export function frequencies(key: Fn, xs: Iterable): Map; +export function frequencies(...args: any[]): any { + return $$reduce(frequencies, args) || + groupByMap({ key: args[0] || identity, group: count() }); } diff --git a/packages/transducers/src/rfn/last.ts b/packages/transducers/src/rfn/last.ts index aebac4f182..ce0df14438 100644 --- a/packages/transducers/src/rfn/last.ts +++ b/packages/transducers/src/rfn/last.ts @@ -1,6 +1,10 @@ import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { reduce, reducer } from "../reduce"; -export function last(): Reducer { - return reducer(() => undefined, (_, x) => x); +export function last(): Reducer; +export function last(xs: Iterable): T; +export function last(xs?: Iterable): any { + return xs ? + reduce(last(), xs) : + reducer(() => undefined, (_, x) => x); } diff --git a/packages/transducers/src/rfn/max-compare.ts b/packages/transducers/src/rfn/max-compare.ts index 3a46595bc4..f49a78648f 100644 --- a/packages/transducers/src/rfn/max-compare.ts +++ b/packages/transducers/src/rfn/max-compare.ts @@ -2,8 +2,17 @@ import { Comparator } from "@thi.ng/api/api"; import { compare } from "@thi.ng/compare"; import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { $$reduce, reducer } from "../reduce"; -export function maxCompare(init: () => T, cmp: Comparator = compare): Reducer { +export function maxCompare(init: () => T, cmp?: Comparator): Reducer; +export function maxCompare(init: () => T, xs: Iterable): T; +export function maxCompare(init: () => T, cmp: Comparator, xs: Iterable): T; +export function maxCompare(...args: any[]): any { + const res = $$reduce(maxCompare, args); + if (res !== undefined) { + return res; + } + const init = args[0]; + const cmp = args[1] || compare; return reducer(init, (acc, x) => cmp(acc, x) >= 0 ? acc : x); } diff --git a/packages/transducers/src/rfn/max.ts b/packages/transducers/src/rfn/max.ts index b995b5e688..8c5eeadb15 100644 --- a/packages/transducers/src/rfn/max.ts +++ b/packages/transducers/src/rfn/max.ts @@ -1,6 +1,10 @@ import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { reduce, reducer } from "../reduce"; -export function max(): Reducer { - return reducer(() => Number.NEGATIVE_INFINITY, (acc, x) => Math.max(acc, x)); +export function max(): Reducer; +export function max(xs: Iterable): number; +export function max(xs?: Iterable): any { + return xs ? + reduce(max(), xs) : + reducer(() => Number.NEGATIVE_INFINITY, (acc, x: number) => Math.max(acc, x)); } diff --git a/packages/transducers/src/rfn/mean.ts b/packages/transducers/src/rfn/mean.ts index 4baa34cdec..3322298622 100644 --- a/packages/transducers/src/rfn/mean.ts +++ b/packages/transducers/src/rfn/mean.ts @@ -1,10 +1,15 @@ import { Reducer } from "../api"; +import { reduce } from "../reduce"; -export function mean(): Reducer { +export function mean(): Reducer; +export function mean(xs: Iterable): number; +export function mean(xs?: Iterable): any { let n = 0; - return [ - () => 0, - (acc) => acc / n, - (acc, x) => (n++ , acc + x), - ]; + return xs ? + reduce(mean(), xs) : + [ + () => 0, + (acc) => acc / n, + (acc, x) => (n++ , acc + x), + ]; } diff --git a/packages/transducers/src/rfn/min-compare.ts b/packages/transducers/src/rfn/min-compare.ts index d0fd96aeba..381fe86420 100644 --- a/packages/transducers/src/rfn/min-compare.ts +++ b/packages/transducers/src/rfn/min-compare.ts @@ -2,8 +2,17 @@ import { Comparator } from "@thi.ng/api/api"; import { compare } from "@thi.ng/compare"; import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { $$reduce, reducer } from "../reduce"; -export function minCompare(init: () => T, cmp: Comparator = compare): Reducer { +export function minCompare(init: () => T, cmp?: Comparator): Reducer; +export function minCompare(init: () => T, xs: Iterable): T; +export function minCompare(init: () => T, cmp: Comparator, xs: Iterable): T; +export function minCompare(...args: any[]): any { + const res = $$reduce(minCompare, args); + if (res !== undefined) { + return res; + } + const init = args[0]; + const cmp = args[1] || compare; return reducer(init, (acc, x) => cmp(acc, x) <= 0 ? acc : x); } diff --git a/packages/transducers/src/rfn/min.ts b/packages/transducers/src/rfn/min.ts index 49762a984b..b159c97cd1 100644 --- a/packages/transducers/src/rfn/min.ts +++ b/packages/transducers/src/rfn/min.ts @@ -1,6 +1,10 @@ import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { reduce, reducer } from "../reduce"; -export function min(): Reducer { - return reducer(() => Number.POSITIVE_INFINITY, (acc, x) => Math.min(acc, x)); +export function min(): Reducer; +export function min(xs: Iterable): number; +export function min(xs?: Iterable): any { + return xs ? + reduce(min(), xs) : + reducer(() => Number.POSITIVE_INFINITY, (acc, x: number) => Math.min(acc, x)); } diff --git a/packages/transducers/src/rfn/mul.ts b/packages/transducers/src/rfn/mul.ts index 497703507d..f6c98442ef 100644 --- a/packages/transducers/src/rfn/mul.ts +++ b/packages/transducers/src/rfn/mul.ts @@ -1,6 +1,18 @@ import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { $$reduce, reducer } from "../reduce"; -export function mul(): Reducer { - return reducer(() => 1, (acc, x) => acc * x); +/** + * Reducer to compute product of values with optional `init` value + * (default: 1). + */ +export function mul(init?: number): Reducer; +export function mul(xs: Iterable): number; +export function mul(init: number, xs: Iterable): number; +export function mul(...args: any[]): any { + const res = $$reduce(mul, args); + if (res !== undefined) { + return res; + } + const init = args[0] || 1; + return reducer(() => init, (acc, x: number) => acc * x); } diff --git a/packages/transducers/src/rfn/push.ts b/packages/transducers/src/rfn/push.ts index e3b4886f3d..5cddc82511 100644 --- a/packages/transducers/src/rfn/push.ts +++ b/packages/transducers/src/rfn/push.ts @@ -1,6 +1,10 @@ import { Reducer } from "../api"; import { reducer } from "../reduce"; -export function push(): Reducer { - return reducer(() => [], (acc, x) => (acc.push(x), acc)); +export function push(): Reducer, T>; +export function push(xs: Iterable): Set; +export function push(xs?: Iterable): any { + return xs ? + [...xs] : + reducer(() => [], (acc, x) => (acc.push(x), acc)); } diff --git a/packages/transducers/src/rfn/reductions.ts b/packages/transducers/src/rfn/reductions.ts index 77f72a04dd..2387efa599 100644 --- a/packages/transducers/src/rfn/reductions.ts +++ b/packages/transducers/src/rfn/reductions.ts @@ -1,18 +1,24 @@ import { Reducer } from "../api"; +import { reduce } from "../reduce"; import { isReduced, reduced } from "../reduced"; -export function reductions([init, complete, reduce]: Reducer): Reducer { - return [ - () => [init()], - (acc) => (acc[acc.length - 1] = complete(acc[acc.length - 1]), acc), - (acc, x) => { - const res = reduce(acc[acc.length - 1], x); - if (isReduced(res)) { - acc.push(res.deref()); - return reduced(acc); +export function reductions(rfn: Reducer): Reducer; +export function reductions(rfn: Reducer, xs: Iterable): A[]; +export function reductions(rfn: Reducer, xs?: Iterable): any { + const [init, complete, _reduce] = rfn; + return xs ? + reduce(reductions(rfn), xs) : + [ + () => [init()], + (acc) => (acc[acc.length - 1] = complete(acc[acc.length - 1]), acc), + (acc, x) => { + const res = _reduce(acc[acc.length - 1], x); + if (isReduced(res)) { + acc.push(res.deref()); + return reduced(acc); + } + acc.push(res); + return acc; } - acc.push(res); - return acc; - } - ]; + ]; } diff --git a/packages/transducers/src/rfn/some.ts b/packages/transducers/src/rfn/some.ts index 4671cca7d7..266727ceab 100644 --- a/packages/transducers/src/rfn/some.ts +++ b/packages/transducers/src/rfn/some.ts @@ -1,7 +1,7 @@ import { Predicate } from "@thi.ng/api/api"; import { Reducer } from "../api"; -import { reducer } from "../reduce"; +import { $$reduce, reducer } from "../reduce"; import { reduced } from "../reduced"; /** @@ -11,7 +11,15 @@ import { reduced } from "../reduced"; * * @param pred */ -export function some(pred?: Predicate): Reducer { +export function some(pred?: Predicate): Reducer; +export function some(xs: Iterable): boolean; +export function some(pred: Predicate, xs: Iterable): boolean; +export function some(...args: any[]): any { + const res = $$reduce(some, args); + if (res !== undefined) { + return res; + } + const pred = args[0]; return reducer( () => false, pred ? diff --git a/packages/transducers/src/rfn/str.ts b/packages/transducers/src/rfn/str.ts index a0e99608d9..4044de2d3c 100644 --- a/packages/transducers/src/rfn/str.ts +++ b/packages/transducers/src/rfn/str.ts @@ -1,9 +1,15 @@ import { Reducer } from "../api"; +import { reducer } from "../reduce"; -export function str(sep = ""): Reducer { - return [ - () => [], - (acc) => (acc).join(sep), - (acc, x) => ((acc).push(x), acc), - ]; +export function str(sep?: string): Reducer; +export function str(sep: string, xs: Iterable): string; +export function str(sep?: string, xs?: Iterable): any { + sep = sep || ""; + let first = true; + return xs ? + [...xs].join(sep) : + reducer( + () => "", + (acc, x) => (acc = first ? "" + x : acc + sep + x, first = false, acc), + ); } diff --git a/packages/transducers/src/rfn/sub.ts b/packages/transducers/src/rfn/sub.ts new file mode 100644 index 0000000000..80ff9349ef --- /dev/null +++ b/packages/transducers/src/rfn/sub.ts @@ -0,0 +1,18 @@ +import { Reducer } from "../api"; +import { $$reduce, reducer } from "../reduce"; + +/** + * Reducer to successively subtract values from optional `init` value + * (default: 0). + */ +export function sub(init?: number): Reducer; +export function sub(xs: Iterable): number; +export function sub(init: number, xs: Iterable): number; +export function sub(...args: any[]): any { + const res = $$reduce(sub, args); + if (res !== undefined) { + return res; + } + const init = args[0] || 0; + return reducer(() => init, (acc, x: number) => acc - x); +} From 694a25378771b521b8dc205f05b34967722db8ce Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 10:49:06 +0100 Subject: [PATCH 55/68] feat(rle-pack): update data format, custom repeat sizes, rename fns - add support for custom run-length group thresholds - rename => encode() / decode() - decode() returns Uint8/16/32Array based on given word size - add encode() error handling (arg checks) - update tests & readme - add diagram BREAKING CHANGE: new API and encoding format, see readme for details --- assets/dot/rle-layout.dot | 31 ++++++++++++++++ assets/rle-layout.png | Bin 0 -> 29738 bytes packages/rle-pack/README.md | 41 ++++++++++++++------- packages/rle-pack/package.json | 5 +-- packages/rle-pack/src/index.ts | 61 +++++++++++++++++++++----------- packages/rle-pack/test/index.ts | 17 +++++---- 6 files changed, 114 insertions(+), 41 deletions(-) create mode 100644 assets/dot/rle-layout.dot create mode 100644 assets/rle-layout.png diff --git a/assets/dot/rle-layout.dot b/assets/dot/rle-layout.dot new file mode 100644 index 0000000000..cf1fe6f962 --- /dev/null +++ b/assets/dot/rle-layout.dot @@ -0,0 +1,31 @@ +digraph g { + fontname=Inconsolata; + rankdir=LR; + node[shape=square,width=1.5,fontname=Inconsolata]; + + subgraph cluster0 { + label="header"; + style="filled"; + bgcolor="#eeeeee"; + num[label="num values\n(32 bits)"]; + wordsize[label="word size\n(5 bits)"]; + rlesizes[label="RLE sizes\n(4x4 bits)"]; + } + + subgraph cluster1 { + label="each value"; + bgcolor="#cccccc"; + flag[label="RLE flag\n(1 bit)"]; + val[label="value\n(word size)"]; + + subgraph cluster1b { + bgcolor="#aaaaaa"; + label="repeats only"; + repeatid[label="repeat ID\n(2 bits)"]; + repeat[label="repeats\n(varying)"]; + } + } + + num -> wordsize -> rlesizes -> flag -> val -> repeatid -> repeat; + +} \ No newline at end of file diff --git a/assets/rle-layout.png b/assets/rle-layout.png new file mode 100644 index 0000000000000000000000000000000000000000..7f02e4212c3fc0b6df8ef26ddd671a4a1b5cc991 GIT binary patch literal 29738 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 kfitvU&2$9+jLOxH^`^23c~f? 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 EKZG&?JOBUy diff --git a/packages/rle-pack/README.md b/packages/rle-pack/README.md index 9c3db99fe1..d2295b4a6f 100644 --- a/packages/rle-pack/README.md +++ b/packages/rle-pack/README.md @@ -21,35 +21,17 @@ will be encoded using additional RLE chunks... - 32 bits - original number of words - 5 bits - word size -- 16 bits - RLE repeat group bit sizes (default: 3, 4, 8, 16) +- 16 bits - 4x RLE repeat group / chunk sizes (in bits) + +The default group sizes are: 3, 4, 8, 16, i.e. 8, 16, 256, 65536 repetitions Then per value: - 1 bit - encoding flag (1 = RLE encoded, 0 = single occurrence) -- n bits - value - -The following are only used for repeated values: - -- 2 bits - repeat class -- m bits - repeat count - 1 (if greater than max group size then split into chunks...) - -Brief overview for 8-bit word size (default): - -| Repeats | Original (bits) | RLE (bits) | Saving (bits) | Ratio | -|---------|-----------------|------------|---------------|----------| -| 1 | 8 | 1+8 | -1 | 1.125 | -| 2 | 16 | 1+8+2+3 | 2 | 0.875 | -| 3 | 24 | 1+8+2+3 | 10 | 0.583 | -| 4 | 32 | 1+8+2+3 | 18 | 0.438 | -| 8 | 64 | 1+8+2+3 | 50 | 0.219 | -| 9 | 72 | 1+8+2+4 | 57 | 0.208 | -| 16 | 128 | 1+8+2+4 | 113 | 0.117 | -| 17 | 136 | 1+8+2+8 | 117 | 0.14 | -| 256 | 2048 | 1+8+2+8 | 2029 | 0.0093 | -| 257 | 2056 | 1+8+2+16 | 2029 | 0.013 | -| 512 | 4096 | 1+8+2+16 | 4069 | 0.0066 | -| 1024 | 8192 | 1+8+2+16 | 8165 | 0.0033 | -| 65536 | 524288 | 1+8+2+16 | 524261 | 0.000051 | +- 2 bits - repeat or chunk class ID +- m bits - repeat count or chunk size (if greater than max group size + then split into chunks...) +- n bits - value(s) ## Installation @@ -74,18 +56,14 @@ src.set([1,1,1,1,1,2,2,2,2,3,3,3,4,4,5,4,4,3,3,3,2,2,2,2,1,1,1,1,1], 512); // pack data packed = rle.encode(src, src.length); -// Uint8Array [0,0,4,0,65,27,252,3,1,255,128,146,4,56,24,160,129,2,193,3,3,20,8,112,18,64,48,30,32] - packed.length -// 29 => 2.83% of original +// 30 => 2.93% of original // pack with custom word size (3 bits, i.e. our value range is only 0-7) // and use custom repeat group sizes suitable for our data alt = rle.encode(src, src.length, 3, [1, 2, 3, 9]); -// Uint8Array [0,0,4,0,24,9,68,127,249,165,61,182,21,195,109,79,52,143,196] - alt.length -// 19 => 1.85% of original, ~65% of default config +// 20 => 1.95% of original, 66% of default config // unpack unpacked = new Uint8Array(rle.decode(alt)); From 599f2b668571c24e15eaf4c7187c6b11b18881cc Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 13:32:35 +0100 Subject: [PATCH 58/68] feat(transducers): update base64Encode() to return string if input given --- packages/transducers/src/xform/base64.ts | 131 ++++++++++++----------- 1 file changed, 67 insertions(+), 64 deletions(-) diff --git a/packages/transducers/src/xform/base64.ts b/packages/transducers/src/xform/base64.ts index db5e8b5d84..45b696449a 100644 --- a/packages/transducers/src/xform/base64.ts +++ b/packages/transducers/src/xform/base64.ts @@ -58,71 +58,74 @@ export interface Base64EncodeOpts { */ export function base64Encode(): Transducer; export function base64Encode(opts: Partial): Transducer; -export function base64Encode(src: Iterable): IterableIterator; -export function base64Encode(opts: Partial, src: Iterable): IterableIterator; +export function base64Encode(src: Iterable): string; +export function base64Encode(opts: Partial, src: Iterable): string; export function base64Encode(...args: any[]): any { - return $iter(base64Encode, args, iterator) || - (([init, complete, reduce]: Reducer) => { - let state = 0; - let b: number; - const opts = { safe: false, buffer: 1024, ...args[0] }; - const chars = opts.safe ? B64_SAFE : B64_CHARS; - const buf: string[] = []; - return [ - init, - (acc) => { - switch (state) { - case 1: - buf.push( - chars[b >> 18 & 0x3f], - chars[b >> 12 & 0x3f], - "=", - "=" - ); - break; - case 2: - buf.push( - chars[b >> 18 & 0x3f], - chars[b >> 12 & 0x3f], - chars[b >> 6 & 0x3f], - "=" - ); - break; - default: - } - while (buf.length && !isReduced(acc)) { - acc = reduce(acc, buf.shift()); - } - return complete(acc); - }, - (acc, x) => { - switch (state) { - case 0: - state = 1; - b = x << 16; - break; - case 1: - state = 2; - b += x << 8; - break; - default: - state = 0; - b += x; - buf.push( - chars[b >> 18 & 0x3f], - chars[b >> 12 & 0x3f], - chars[b >> 6 & 0x3f], - chars[b & 0x3f] - ); - if (buf.length >= opts.buffer) { - for (let i = 0, n = buf.length; i < n && !isReduced(acc); i++) { - acc = reduce(acc, buf[i]); - } - buf.length = 0; + const iter = $iter(base64Encode, args, iterator); + if (iter) { + return [...iter].join(""); + } + return (([init, complete, reduce]: Reducer) => { + let state = 0; + let b: number; + const opts = { safe: false, buffer: 1024, ...args[0] }; + const chars = opts.safe ? B64_SAFE : B64_CHARS; + const buf: string[] = []; + return [ + init, + (acc) => { + switch (state) { + case 1: + buf.push( + chars[b >> 18 & 0x3f], + chars[b >> 12 & 0x3f], + "=", + "=" + ); + break; + case 2: + buf.push( + chars[b >> 18 & 0x3f], + chars[b >> 12 & 0x3f], + chars[b >> 6 & 0x3f], + "=" + ); + break; + default: + } + while (buf.length && !isReduced(acc)) { + acc = reduce(acc, buf.shift()); + } + return complete(acc); + }, + (acc, x) => { + switch (state) { + case 0: + state = 1; + b = x << 16; + break; + case 1: + state = 2; + b += x << 8; + break; + default: + state = 0; + b += x; + buf.push( + chars[b >> 18 & 0x3f], + chars[b >> 12 & 0x3f], + chars[b >> 6 & 0x3f], + chars[b & 0x3f] + ); + if (buf.length >= opts.buffer) { + for (let i = 0, n = buf.length; i < n && !isReduced(acc); i++) { + acc = reduce(acc, buf[i]); } - } - return acc; + buf.length = 0; + } } - ]; - }); + return acc; + } + ]; + }); } From d861bdd126d54f5d944d4895585b18769368eafc Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 13:34:12 +0100 Subject: [PATCH 59/68] fix(transducers): iterator1() final reduced value handling --- packages/transducers/src/iterator.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/transducers/src/iterator.ts b/packages/transducers/src/iterator.ts index 7768f05830..43f32df6d3 100644 --- a/packages/transducers/src/iterator.ts +++ b/packages/transducers/src/iterator.ts @@ -40,9 +40,12 @@ export function* iterator(xform: Transducer, xs: Iterable): Itera export function* iterator1(xform: Transducer, xs: Iterable): IterableIterator { const reduce = (>xform([null, null, (acc, x) => (acc = x)]))[2]; for (let x of xs) { - const y = reduce(SEMAPHORE, x); + let y = reduce(SEMAPHORE, x); if (isReduced(y)) { - yield unreduced(y.deref()); + y = unreduced(y.deref()); + if (y !== SEMAPHORE) { + yield y; + } return; } if (y !== SEMAPHORE) { From 832e57f1fa6042330eb857b2d1c263b9dd3442a5 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 15:25:07 +0100 Subject: [PATCH 60/68] fix(transducers): copy&paste error (push) --- packages/transducers/src/rfn/push.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/transducers/src/rfn/push.ts b/packages/transducers/src/rfn/push.ts index 5cddc82511..985bbf5826 100644 --- a/packages/transducers/src/rfn/push.ts +++ b/packages/transducers/src/rfn/push.ts @@ -1,8 +1,8 @@ import { Reducer } from "../api"; import { reducer } from "../reduce"; -export function push(): Reducer, T>; -export function push(xs: Iterable): Set; +export function push(): Reducer; +export function push(xs: Iterable): T[]; export function push(xs?: Iterable): any { return xs ? [...xs] : From 024a4e960cd88de8dd52698c83a0626b14eea137 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 15:25:30 +0100 Subject: [PATCH 61/68] docs(transducers): update readme --- packages/transducers/README.md | 55 +++++++++++++++++----------- packages/transducers/src/rfn/fill.ts | 3 +- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/packages/transducers/README.md b/packages/transducers/README.md index e460e42165..08f793b906 100644 --- a/packages/transducers/README.md +++ b/packages/transducers/README.md @@ -53,6 +53,14 @@ though the implementation does heavily differ (also in contrast to some other JS based implementations) and dozens of less common, but generally highly useful operators have been added. See full list below. +Furthermore, since v2.0.0 most transducers & reducers provided here +accept an optional input iterable, which allows them them to be used +directly instead of having to wrap their call in one of the execution +functions (i.e. `transduce()`, `reduce()`, `iterator()`, `run()`). If +executed this way, transducer functions will return a transforming ES6 +iterator (generator) and reducing functions will return a reduced result +of the given input iterable. + ### Related packages #### Extended functionality @@ -768,28 +776,31 @@ tx.transduce(tx.map((x) => x*10), tx.push(), tx.range(4)) ### Reducers -- [add](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/add) -- [assocMap](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/assoc-map) -- [assocObj](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/assoc-obj) -- [conj](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/conj) -- [count](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/count) -- [every](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/every) -- [frequencies](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/frequencies) -- [groupBinary](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/group-binary) -- [groupByMap](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/group-by-map) -- [groupByObj](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/group-by-obj) -- [last](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/last) -- [maxCompare](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/max-compare) -- [max](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/max) -- [mean](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/mean) -- [minCompare](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/min-compare) -- [min](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/min) -- [mul](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/mul) -- [pushCopy](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/push-copy) -- [push](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/push) -- [reductions](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/reductions) -- [some](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/some) -- [str](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/str) +- [add](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/add) +- [assocMap](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/assoc-map) +- [assocObj](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/assoc-obj) +- [conj](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/conj) +- [count](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/count) +- [div](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/div) +- [every](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/every) +- [fill](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/fill) +- [frequencies](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/frequencies) +- [groupBinary](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/group-binary) +- [groupByMap](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/group-by-map) +- [groupByObj](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/group-by-obj) +- [last](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/last) +- [maxCompare](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/max-compare) +- [max](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/max) +- [mean](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/mean) +- [minCompare](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/min-compare) +- [min](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/min) +- [mul](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/mul) +- [pushCopy](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/push-copy) +- [push](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/push) +- [reductions](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/reductions) +- [some](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/some) +- [str](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/str) +- [sub](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/sub) ## Authors diff --git a/packages/transducers/src/rfn/fill.ts b/packages/transducers/src/rfn/fill.ts index bddf6c1564..c68a89370a 100644 --- a/packages/transducers/src/rfn/fill.ts +++ b/packages/transducers/src/rfn/fill.ts @@ -5,7 +5,8 @@ import { reducer, $$reduce } from "../reduce"; /** * Reducer which starts filling array with results from given `start` - * index (default: 0). + * index (default: 0). Use `fillN()` for typed array targets (same impl, + * but provides correct result type). * * @param start */ From 2a443a56cf8546ecbfc00714fedea648fcd62ad1 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 15:25:51 +0100 Subject: [PATCH 62/68] docs(transducers-stats): update readme --- packages/transducers-stats/README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/transducers-stats/README.md b/packages/transducers-stats/README.md index 06228f99e7..f0bd784ef3 100644 --- a/packages/transducers-stats/README.md +++ b/packages/transducers-stats/README.md @@ -25,6 +25,12 @@ for [technical statistical analysis and replaces the older [@thi.ng/indicators](https://github.com/thi-ng/indicators) package. +The transducers provided here accept an optional input iterable, which +allows them them to be used directly instead of having to wrap their +call in one of the transducer execution functions (i.e. `transduce()`, +`iterator()`). If executed this way, the functions will return a +transforming ES6 iterator (generator) instead of a transducer. + ## Supported indicators - [Bollinger Bands](./src/bollinger.ts) @@ -53,12 +59,16 @@ For some realworld use, please see the [crypto chart](https://github.com/thi-ng/umbrella/tree/master/examples/crypto-chart) example. +![screenshot](https://github.com/thi-ng/umbrella/tree/master/assets/crypto-chart.png) + ```ts import * as tx from "@thi.ng/transducers"; import * as stats from "@thi.ng/transducers-stats"; // Simple moving average (SMA) (sliding window size 5) -[...tx.iterator(stats.sma(5), [1,2,3,4,5,10,11,12,13,14,9,8,7,6,5])] +// if an input is given (as is the case here), then returns +// a transforming iterator instead of transducer +[...stats.sma(5, [1,2,3,4,5,10,11,12,13,14,9,8,7,6,5])] // [ 3, 4.8, 6.6, 8.4, 10.2, 12, 11.8, 11.2, 10.2, 8.8, 7 ] // compute multiple stats at once From 2811072682e7bc5f9de49442d388d5910dc257d3 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 15:26:19 +0100 Subject: [PATCH 63/68] assets(examples): update crypto-chart screenshot --- assets/crypto-chart.png | Bin 175337 -> 215948 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/crypto-chart.png b/assets/crypto-chart.png index 5870075e0e64ab689f039d180a12421c3473394c..e9425204ef4ee16e8d54cae5ce20af4c18315edb 100644 GIT binary patch literal 215948 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ℜ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�s z&uLf{5$ahSuxq&}MQb7b*aGhTAnqp)bvMdGIYyBLKS2w+vIYnZTD&hCt0kUc^xsyN82E2~dZy2>-ufB+O4m#*yd@9w$B(nl#M2UK z9k`(B91-|I$cu~3o?$cj7CT~jJaTY~ny<}qrQ5|=9lc)&J|+CTXucjZ9gQj6ZzCc5a4vivTo>sF=YjBT15-JkS3P)I0EOqcfPEHON7groIraW_} z2!kRBNTziHe4E5UaY&~ldxqtmNj;m8kdOeU0T}xj!HEE*4hk&nYhf9=?C5H3A$Su3 zu6}jL!72hmS{Fj{kfTQ4V1qKIAqr^`TrAvWPmLDjPBQrPCT901)9#P+(#>PkQ4`o0 zFmT2lB^A0|r%Wa;uH*4;e|+%?RoiK<6k#pdA&)6YmU~AYKImWWd#}ONY+~v>wqmN* zqV`x5<$a}kdA#*cDE-NxH=qo_T8~-=uF?U@m|pZ$=9FR>yHD7a`c5M z9ZU$0g$zs;-OJbD`&BEYdCdm>|ifV#bR z{W~_qss9RxION=0G8~ex1R8!Kom|D?Bfij4u|gs{^^s2LTtjWU-Aa|;DiZ7YdCnr2 zel-(Ls6wteag0wM6eWV?PO++h@-cs^H7xmjt3=S=bc*V|Y@!CT%~}AoM!?Sxp@ySv z(v%iXMRa13HNUu$h>rRAQ&dfJ&57xA+K3p9@ELIcPXjUbqt`Z zN{SQ06VvIF(WGb72l4QH$rtt;Dq@dwjW_4Ebq8Yy*`{JmNlE1`Oq*56DkDeMCDXp> zy&h&%)pdMs=INcm+BG9D*D5WfaQI7avjNsnZaflqw)R!nH@CUCY}QP**2Gx~^ZLif zi8cQ?iqH+el!Pv zi=L1CwqGja0UM4=xBs%g2kBBL%oR3sw?c!w zMTG_cT$4%c7Io~@^JO!tsu$mWDt~lP#BM?nRI?-q)dcz!2rzL75E4inBC8Do)#y*iW9MG3-!6(s42omMu z5bdo>?3#YF%CF+5qV2^Np3^QV^c@Q5_@37d=eNgT7!pG&(_HzI_tRbVqgW9qCXCPD zUHjts3XGex>t;^PnFCW-_oYg00}gkVBAST_xnG=g=Nkeu^7!VVD83+Vd$11yB{@-& zX9Y<|NzfIUJW258HhgE}wT*?Q-+ZrYi3x#tS|gu(fl6>t22Q1$?JZewOoBo6Cik zYVaY`W$MJ@BzYjbgd>|)W}Jyj4~vMgbw#N;dJsg<_0os@0gAqGYs6o z2R4U5@azjaTwH_ze+6q;T%I7)0`Z}k{uij?4uChOecSK0kb+Dq+Rml~#Qc%bBJeuA zk0J2OU;`0eTH9UFpFmo)bxA_CwY6HUgC>uT_TqB|GAVpziKfQp6JY<2w+ayvI<;)( zke{}p5VRKC3GMH(G>7r@D;Ec&&i?vWh+K=EYE>A|_D+IQ}4HD@ghO{O13>rUO zarX$VNv0-6-N{Zb>Z8Fd&VLxV262?Y7^n_T);nFYe~qnixsV&Dw>Ir?mR z++y_B(gQtMOVJNtCsBT*=AiO(jU7vy>%7Bdkdx~7_1yjJ)Qv-f2fOQ5pG3mYES z3*WNbS}+uLDjMG$GyxP`$nNqeJOd+E>5_;)C}y)F4--d7NojZ{%LLSss4Sn!-C@U& zYOA* zR4U;D0_9v;+DZLDelH>r7l{8P_%x)@-55srt@0ie?5kPKY|{Mv7`~l4`|Pk!L@#gL zbDXb}@fS0UMWE-4XZo=KI|RGz4L|f48k#8mM&|F_f^Ua^e`)3tmy~OzRjSKc3Ez7@ zx5T4&BN(6E7OVou`yyBNZJQEz2C6B%u5kpxeeZJ|Qg^Jl#fzMKgFUm!bX$?=_d#9~Ay^E1NiS{&Qu> z;!rw}Z6=PFxcv)Je%MTx>`!d(qXXQpThSqi(SQ`Y^4{Cf^=pi9Ab+k1$fk~24DDTU z0IYV3g1&%tF1R`TvK;GLfL64H+ktUjtWE2tjr%gSa3lPv{KGdK9%3#>wBx(?vFJ=F z+R4~haZu2eU?NGHI23;wXqN_~Dh6)Y4?+WJv$L5cN>L3eTz(Rd_ zkI@E*~n~hmqyIUh*?5etl>9%zS0k9o@eVu_a8+O z9g|VOJ$l;WK5BMq{vnr9myq~bf2;_e#=E)dZIW`?oxQQkWX?NkoJzSE`UW=)Eumtd z?p6jq*kU~-G zpF{utnTfVIt3QBpK(pX}c@zD^wY7_MT1#V@YT*E^hx3cX<=(^xWti8Rq}{~<&|{;{ zm>Kd7Rams&@c?_BLHg#o$s$!n`HRVV07#_%BK}1;z zglM*^6Ncg{IIqrQ3 z2gI}y?*f7*KX)Ph852V#ijoL(zYvOzKIKpyQ%*7lv~NVZeq-8U zEj<4ILroncx8xLuI~jKKWxrZ7=}oATcH63Jh|wGmH4YB{9o!kiYBvccb68YEfJFT& z+1#epsRUXmyKz9UsF3`5NoZtk(%!*A-6_RnWVe2ZUYq2- zqx`7YDO95kZefEsO(4IJp#D*vx~o9|UekOf)a|JfPGaraKDICOkRrUy^UEUg8I+K> z5jL0eik2&CITYF|QVP8!ad;lP&AOEW;AS96#f_TTatVcQZirfU5#1M?)I8f|)`Wo< zHMERoU3Wy>_l`Swi1}yG^m;LgCpS>58XH}JSi!+Tah5skV#HU>Kj)Axr?PtOqxCvm z*MOL?@%!bm$fq?|J!hEU2#vpvBs#9=Ys-58r=K)aPXifpfyWyE*mDHTGLHf|409+T zS#7QYefjiX&Zkdz+dP7tlE52ljMdUl7npKi(dP`NIKD5HGt}r3~%1Tz3?Z z9ts!7`%k4gh6U4xrebfmSR|(x0J0+Pt}iYsuPEFtQqX@XWV{a3eWsF<3_G1wZkxY9 z21Kz|thismV1w!%op9gqVt*jw`Y~m;1-+zJg&m9@`kK!exx8v;PSrh5N#4bIjaT7` zZ=c5PWVmN09IZS_&Nk)(lWNl7G=BZM6Dy7L_DZKKPR;sW3lHM0U0I1C_%+P}Qi$A> z*ge?z{PkogF+&OR6Imojwx|t@)B|r)N!JWLxj7%a0U;qFK);+T7G2U73K(1hj4}tf z8I12Zu?WKZtq}DC(LOFW{91rybdl{Df+U(44m+LWaX8gXPV&6aKRoYHunq}YK46rE z+$h{0{S@^vw8n<-*UO6ggXF?>oZ7>~Rh3+kT=d$FICcw%{o?O|-|T zO_6p5>P#=;@5?L&#?pyH@*7cbufY?9$*59Xeu}6tjxE_P=x;;j2+g@9E~W4 z%T@ZR`R+{?z#V3KOVYmSwN|F>CaWR5O(kn9LNOf)0%f&CWaH>737mX+hda8UL3dV{ z?cR@|MbB%e`YjYcIKRUgJmOpl_h!ePBDNAyrDEHsJL{`0j!#<*)^{g669Z{sd*X6| z`~kus%vT>yN;p;YE=>}3;mQtYb5(aiO|FKy7KJOIeYn2F)8V2hJ9mTJi%HnAQEnP!w4Ni2f(KVzLArV*g z>{-y!G11|ops8>4M2U=R0TJpWPyU~BeFUr9Z6N|gk8*n;a0D$3=LOvWM z(Z%Q-T?YTf;zFZ_Mh!J(WI6o4y^i~)Qu=rpfCBWO=^Sax z^-m)!+8X>IEuR@e$`A^8S8)Dea0MJUH~CaG%WP?KvMXn1@epvl_E+-nH_46lCPC2u zFd(3}GeF_z03if0|C|Q>Q(>}nhGtXELi$CfDN=ZvzwKh(9s5W}hFP#znCW^>ZgPjJy4YZgEEzFC zK;y2BCVsi`!NX^W-I+U>&?B*GTQ5_z9xY9PDB!9(hIe+nVK#h!^1K*wZZF5f)f^&}N z?Hn8`Lo8QbUsQC83|%34?>kSn*1@b;ks3P4q@=LojxDt!^g`%3A!6s-N`;?UK0xrPprhM9-BhRXRVJ3O_#3P?YmR2@LS{Dy zN3-}%zQt_J+mB*L17sAW$h$7`FNMSIaAOzo1_Y%;WxV=P5$>WCVUoEp)_dFL1z_5v z>1$KpPe4+;D|19R8ZJNPM?ZkPdH+J30zi3i1Sd6oUz%spgDmE{%u)mze1_cd=*ok=bH8(CN@HtBC^x!DmNoywhT!AIQSnIR5+F zYXED*&v)G$pfhaRoh2nKisKulC3TKf6!n0!)Xm3)7wWD`Gj}RUZy*CxKKSed|;DxS|eY>n1?4;@yRBzM>pH|{LH0%8Ccs; z{4Q!s<)+1-7^VZP5c&fDZRJRQ=?HAk9F>_Y-G4JHKypA0IZ4f(+l(*%NlCC1a1|LF zL!1VECdc`XUqJ=-C)qKG{iMxZqdWD0FZvP6=K_)yGWqd@3SBZBlP*LWgiQF;K?0j| z)a{A&cqmTi?|JT(>*8`l$|IhPln)kGe}WVsY;%O=P&rSTJ6qWl0;3S_Xje7rUuZD5 zKHKf9Yb+ExT!_^|UD&3OG>V^DT}|=xtI_5upf4)o@5B5bei|a?*DsxFEMN&+8r<)F zq?UFLE@6gAE3M4dYy1DZLQ89MMcX6gyS*`1J)hINeL|a5*0}j~zMvOTl2GyS=KUI$ zY)OYyw6w()O{Wh|CJtMYR|WjDMe}fFFTr9fz#&`ph+w%!v)Zs#XUP!Xlgl$u<3`Z&s2H@A+S2m`05eJ^1f~*4f2!F>#MW0JUbnGHZR>zLNk=+-%c$l zQZA5Ap^l7pQLpVkEG%b%@ra~>vmC~lvJCCq^#KQzK2=fP3$~ew6 z(WiigG_Z#WX2r+XkfJd}-?Kd+g%6TVV^zFhr!$Qld)PqkY#nn<{Rg`feftRzui0|NJO?|SqHV?;Y z5+tO3o0nGbDc|F9w|%NpHk_dQfsno25Zl}9%TTznL)BHTbz6x3^Bw*IbSbO#s9HMW z{rXOF-se#I2aB=rK0#E{I%s&*|7z>@zkcoMmFV=nUqcfBus*NhpR~c{v36{mx4-Ld z1Ak~UI5WYTL_aQk@u%G!O`8nl8pNmW=1O@svXh@$k8N`P#qt%A6>Nb{v)63;vs1sc zx_J?wT?lh%XEzi*7}&{ynZkP2JV|Wq8H3+Sviu*Llwg>d^=J(AZ_W>ryo=+9(|v}M zLL?_TJdxdk?K(yDSc^-eUh`+8#VgIyZySD1T6%{n zTR;0MxCt=u=;lcf>Nfe)4*6XPpUA=iR2^p6C|R3>+@9`Mh}Su6=vk`NKO_CSqePH5{-CRaBPiA0Iwm5}lmbo< z%M@O{*v8qa;1>p(K!M=Cr6uGtDze$czOxNbki}SF^(c|lRZW4Xg;?g_WgELT_a61N zi%ppvT`ie(buPdTBN3KAY!zy~33TZK|MA{aX&4n|B<`&#zQawb#G+t)+1tPQ;7~~g z{@JrAZ6#K%67`og`iU`hfTSG%p54f$PPp2yO- z&tGuy@T^Q2fjk!G;1yX_RkN<5E+R4i_mdFl>y65f1bW#D|IMcV9&S#^?dtmx#Im8K z9bR0np5po94hHnO_a1SY2=lWj8YL)U{tQq*!bm>3X^`%1touhdQiJg~RR>`)v?E#* zyT7Jem><@7B&qd&T|ktNg4Q{L1IT15N&k6VTk$wUg0LhWRQ#PR>7nNI;wh0%?PA3(~vS>10>=c9z)zG26k zLXKG7=L>_;GPpcN%5Z_NKG&kkdh)FbAq>MIpN|ra23Xx*;0#%+Q@_R;n-q+v-YyMk zJYN}mQK?4T6F>5Kb}NAUy0=1!*L9)93{`z%-sU~Jc)qnXC{;}_j27CcuQHa30z)@j zoW>hqnkAQo5EmxF;eMBzWUNtw@dtEFnfZ&pd;MUamJ5XaqtZh=ldEm6ufD~=IZbsx zR%h@(_U?eGW$m1Mz{6r@gitWlw)>O`@ry(gb|4~2q;aWHeYE3rxeJf-FGA(qiB^w= z^}Hu`xuMi5l1n2nolf?x95mR4OBOtuUr)Xf#;Lt>lT=#ropwD_zSkuY+9`@{i22-l zRx7LbyXfH2DfJirXUGaJwz$2?HeBSZ^qzJadmBBSJ;kKAU+wLjP($ELabzZ-e6}0tbLe1zMv)SpJ_C z69XMwPSZYp_H623A?*C5?HUjwehwo-j#=NUl+%xDz8Sqv@o781Sgn;}2}f>3;-!4C zQ=A%0yJg?~&f=i>sFETu$5HT3vt=^7WAgd7mz0Q?ndA z*5?DT)JpAy^aQff5%lpPIIGfU^4UQ=HfHAY#hF$Y2Eg7;gU}Pia<#Hj=5$=s_?m|j zKh%(8$8PanSRyd}LJ=${>GY`HgfxE=OGv47=p{PdM4u4Od(^@1vU5%Y1y&x=9w`wb zJ>-00&PRX_>gwDa{r1tchW{6bdQL>V-aQQwgS>`1<^DCs#`euBf7kcYYsz9mj-O6x z6Z=T@QWG_Jq-&`Ac0^R;uu{+<|B{ilnP+KuMcrKisw%LSiJ|pTZ{%V zlS0jRuP|cM;ft%SA3=6ccYftg`pu*wBiC0oY~M$h>NFGMUheOA))^PcZwxMA^@N(Vs-;O>mZ-4$c4ekJgApVP&^bNU9IL7uh7v3zHmrOB(OtpCF zf;vXR@D}-uvGQR(Mg2_g)}srq-lV=J9~N4v=+BAuas-8T{eOhrH*kJ)(4TXxk~B*2 zw->eh0|f;$%KaI?ISRSm|82+Q!&yL|!TnoYx^(tijao+5Y{dbm){ibiO9=@yE1)nA z2gKMXHe+?jlSbR6x~b?WxHleJ>4HENCrCqQ4)MyZU>Z!_G zbn|yQW5LLFr*2=2s8e(Y*$QEs7ea`QKM3|$ghL|rUZlszClAhO30a8CC#L_#sonci z+WVIqP4CwdOEz94QXsS(yVJ3XWc5yh!fBJVy=|@24^*;Cl4Cs2Xsb_g) zL>*xcCeJN5=!3j!2s3}G@23&>}Sezlk zuP4sd5Vf_u%Rb)@%AgE*x|cM$z`&CH16o38cMs}YN7Y*)!PPA#A_kA({aWnNwOZS& zDoa-&U}}jBNO#I_FN<03g=CCB%RNfo?0o2%nK`Y>$OTPNqGMvfi4r?PvhfcY%Y2=K zYO7_2u(tv)G-uv&?2?0cUtWCq+2?(}=Dywvw!GK*sAqeGo~PxyO^9*|>@M!VJy6uV zT7rnM&#>`VLGZ@xg@7K?nCQ#ktI!3C}FVfwkQJJq-oI zHR*f^3_c9xCz(ppL*Eh~sF)8Ag1+)7)6u5p`wTE)on5DEMba3^(+Riz zS}kYX4N8g~Iy@b*}H>%_(l&y)E2o!E^U zg6*qHoo%GzFK^t5_@9R6Pd$sd32g3dN2)VZ>TTrg>6@JaGx2|*R1-|(Umd+BViwdOWL-YujTdn$<0jedZbBYgIPYIbkmZCPYE^k8J zE0&107W?0im<>*2kSM29Hb-;xxF*6NnR@P0vd%=kbV<#(TzadtmPf^fnsT&e*Uny3 zJ-x>4>lHZ8Y-luoP|jPA0eBb*#xaIp_4eB8Q=`WII3|quUwrP*&ALuZMYbUtc+2@T z)z6*_j8*Uy2sjaf*p_Y(?spqOx3%EMj{u;l#{>VCF8hm?7aw*JizxUrhopkCvg;)Y z5F6;Pbg?@)zSvGGqlwciG;SYJr~yt^cGg%R{~#$6^)uv5({X#x0q$)5ne?Yb6Z1Gz zt)6CpIIn+^$dx|}icXYVo1Wl}5Brf0Vjl2R1q05~`nDi`){S$_&)lvT{1oYAKtvm< zsJm_}=ta+=x)9>?$K`V(I zq56gbO$`MAS+lZU?0l=YfNH4}$LOup+kbiWSUZQw3;pUkXqoM8MC^C)7HM2!mhp~^ zGEn7rB!KjtY6cPDmpeXs$&05ddB4S)r26tOoyosm@L zxrRLrF~~>qB~ByxVKJ-lyDnnq`E4X8Y%(V1JhU zR6??Oc4Ap4K`j%4H8@Cm(htQf26ks}SpW2`BX$hh%L0)@r;C1usIb@$(0wBtaXMc$ zdxkEzH14na^abBisD|g}NJK!)J zODQzrb;sSup-3Mct}ZD)hs2PIhE(eVt}djY^S)pS8u^Il7%c7URX^iUsV4@TvH);( z97Ep8))BQUK)>{46|q{edf2?BeLul>7>>zNrhVvqu(3Re`7?QGfNUl~@^Slm26OAO z#lXnIs;og`&kkw8;@LIaK*;>=PXDHGaZ#lpgO-Qqd@}o4C^+cvxti$z+Iakv(EP_! zKJs_QAo<1+6F&9e2{V}nV`;sG?_bx=cOxFRRv(y}N)=+YeqUuLDd`aZY*@W^4o-RI zyn!(=mDra_hWQjXFlNNIy?k@snf`)lsIKe;S-OU-^s*a^`eXWhjI8XfZ=kk`4Xr=0 zsg_&tDM){l6Xj@twD5AhYr5}M>TW$91*bp9&GDK1TTemZxp8g>aO(Jlgf_--0VbvB zc;0_+!omAa+V-Fdl?-x@ZEg#T!I0DOrr9}RCO>?Bmd1{UZ_1Kf!b@%d^js+C5C{p< zA6%|Us2W%E^4%N)&?D>(^0%D*35UP0-FzOZS7$o2xkuCR#rR*;RG&%cCZ>0V*-}eW zN@m@?88s#}AAulMm9D~|Yd zyqt^_4RkwvZ7K`pqOgC@r8I&cAncHqHp-*_pU+Z6tS=7Zn+bs`fgRrNX7i98!i4`q zG>?@`n?s7^NTrMZrdt}L)fHPwj4u6_BForn1L+$9H zvuZt~;0+tv&JXXIU;NWypsvM$7@=35vr4Unl~q|BTI?`F)So}fHQ=Tyq!wxh{ujjA zj3Ri-Y}ML*uDtswlK0n_=STz>tBn(4pSMKUFlM1lIe+PXFW4cAHZ{Ykvvg)8R6TqPD@KUO8l z!n40<$VyIwp{qc@ShyBtjG2H`lvg0DCo4xCdGBB83jEue>{MnaSIem4lFZDtc=b#w z7itO#ap6l~V1c*~OpH!=%7lCN2_^ft>pZliLImi&XA7|&*W`M^nJ|axO;;Nzsj z67d}L@Uu13XIB?rOb$#}N@4z``?v*%KfC5q;v3e6tW$u6#K16iCFUU|{6R|7OxL>~GW4Epo(!#FBT~mMK-{7~Gcsmh#;zF%l z&*2+DZe=0*hiZ z_ykON1g6WzN|VD;^K4PO<$Og|6{G#&*=qhPj0&k^_TAE^!_glqHa50@c5xvWpP9-S z@Wc->CT{biMVqQFd~Ob+A8*FlT|3=oE!Gog{+6Q8i6gfq)c44}fV&D++OohSITvDb zY1Th=Ktr?6u^Oy$35dLK$ottz2pK<`&9paq!7PAv!hN_5ZM{}-Whbrtj14o2uW_UKC3QnO7sR!+%uk)w=czG=A`}?q7IIo0-9z(m$nGeusOe zFSd1cb0af&D^3M`Hgl%f^$yA#R%d3=yg_lM)(3u~m5)TPz92WE^mS5TjiLU2<%O-y zNBuDe%8$8&%Jt>Zss4tjVCfAj>u^3l+;+X40v?MI2B9j2iPYm*Rgq8Ua-LfY;&uJ@ zB=&GK7LMz#;hZRk!aN--sL!JIyN*R;1-PkcmY?GR)IhZ9`2y8%C(G$PiR5Tx4tVQ} zKZ6}#npElp#uJ*gNI>oZbU$OtyS-QWA{m$Lpm_rso$ycbtb83!H>7 zo-on`Wj-w}Edz_Y9~S4NPoqN8{F=P5th3V)W0~0I@CsO3?G=cG))^3|%RW2$YFi-r z!oPmO3&-)DSy@#e(_80%C!Nazgog(oxS$t3X5gYJ!`qmZ(SGjX>gsA{M)?ig_2wWJ z%vSyd{?J1gF|-4YMcF(C*37_rZlG1fjZK!YC29Pa?RyblAe8e#-R0z9QnBkG@KbUQDWHmZ0yODIWT7>C??p3tF{Uas46J!_;B> zwq1If+&=~QB*gr@pux`{z>WzgQnr8V6Z6o?1V4{d508z=JnmS$&UaNzk(@AmvgLP2 z$i>Q`px`45RY*eEEZSi=CXppk}VITcR?q}PUCR=kK^ zd4VSi&j+GzfkyWDC-oBg(!PfYK8%;1stg`GOG~(jl0@CUlrm+J%v6gObBF%cCRr_3 zA#@Lc%Vl$wn_YD*Jyp@l&_uJ+2;Ih0+Qgc9ibbNc|Hsu^$3@k3@52LvbO<8SCDNdz zG>C+BHw@B^(mfyw2og$zbazO%BGN70okPO_!_52+-rwhbp7;HS&wPe6Gw1BR*SfBC zt+m&l7d|;%>(LWNx(f;I7i*QFU>#m!YeLvu9FcyjFEKnVqTWtgqR-%3qSPZ<>;oZ1N-xOor(x zsS%T2%a;h(uI2vD<-IvLIM6mo5#n|wzNY-m69gvxH66BB^qI(>g@N}abrJenp?Q;h z{)4^Zo6p61u^AWeCe04=BH%a?JaidGP1kTHCTj^hZW(6Rvnht(U8AhVZe! ze_cPL>AvzTH2K0*k6TEK9i4Za>pqb#d3nI%MJ4SsuM)1NfYRGW8AmU5@5gPLlJBn3 z1e%^^7dd`dY}Qpz9x9*2an!3T@-EEk-bKfZ8K~FlL@$}v+TbhrtmR7A_5Kf>fQq?t}aRu3a6DVxJ!w=>& zI1sG8&)Y(0SY*gqW~~TUVVJ*|xj9WpZEDXJqX5S6#xbsLL&&RPn z@D66ZRIJ3&9LYP@eD9Ui6U`3<-ZbPa&dV8axJv@}pi2-RPsUfEds;ob2k5t5zOKqt5#Y~mN*eZV9ik7HO~ zI-4ILT6o+~R#ILL-_;@}k=JwFPa65=k}eet?5O%Pxf1nw)eV&a^cGSN=BYg3GRg_? zU-v!#P$ju%2^ia7A>lsyKsSZDpaL(|Z}(Bo|4Rd8QKN^tgQ^q{7OjSsx*5D9>NFAI zZ;y#^PGLl+FxGdf-^Ffk5i;{Z_vjhYu&IVzi8R0!k{j#hJ;AJqrIS6J{vkS7l0tHq zpfhY;Cq8-w-w(c>2Js{TQsgglNyFdfJRZo+y?Hef}u?{`Luq4HkoUyV4=YNp1<-dqS(rkkvAe){x$&VZl2n;r`!)~SO7qMTe9v;147 z7qrU=0&2K+32;ElUbqTwAA(*p0pUky@J{^NvtMG89%qPA!n{TKZ^Vf6-GM^2%r>5w z47r3SpB~CeuMeRz%x7j>PB0cYV`wdu-W-jkKAQ?*7FWZ2KmLZft`KH!My=^&o&BF) z0KZS2a|=rjKj9TFcSeQ8BOWIG59JZxXq2C&Rk64h3H@M@Setpy zg&o9eIbMMs&gPEzgYh1%e(y?rjcCYXk&CgP`2483ZlOcJIIY7m%z*|wpnk&|eO2jr zr@8W7KU}8;@{$}RS&x9R2KF*P2$l)^&M+dD_b6<}oXl^3i81hm z@g0A45he+`n}}D1XxGi!@jEY5g>ZvcHT#hDK)cf$vb^h$jdDI%gsl#<>;*FN521za zhj?G_4gtGUjQ^&qKnz(%82Ec2?`Ge_*~dQ#hjDR5)4zQEnq1@TUEOE$r~?rGB1q3H zzK*?5wvT+-)c|H)!st8!d$%QbnL*66Snc6O1l`mn%$>I{WnR)3sJ~5{vXshL>{@mZ z;Ag~)4$qcO#285a-sMH^M_*;{qpK7YHUF;I8y;dclZu_}{VVm^%ll77THbkA&+U8w z?ret~E%JdWK3&_4w0$|O63#n~O8#lNCQm4Ea>`CcT|T9(;*`ZHAYipuYrFjPT0S~x zw%Zx$kD7U$mcqAtcvv8qK)F9(!@NDX3!;pw@s}MRX^CL!E%ym6PiHHDDzA8N&2A3AT;>u@u`oX!F< zrwI23$wtJ_joH~0hbgJrOkigQE}cY~`NO}3!~c%y-3m^Agnr)x)M^Bm~_jn+m&spTnqYa_d!4&u+!->M)YSEjdVR zl0H*R+h1jl^wNuS@@5(=4Jh#$23%z1bALFbop$J+71KOg`y|twqhy2{Sz7Fr)yXHK z?%-=3ddA3(+a45~N(1sM0+xE{Fr)%_s_-CgrnRbnChfUjJ+kTa#3vNfk z6NQ`&dOss#a9+vF4{%-rZdc-w(5i1-=b#^~qp7(F0_h5)`!?C;R~05R?_{?nTA%Rz zc5zh8)K2=h?v|uS{a$8Zf1C4K3|j{$d?h5ydC^zA#Y}y;JrL~AE!2S}E0^I5rdymV zcQ}^cAK^_oS2C5jJ!bNWGGxH!m8r42dYf`81pgVy-Y}P;?GWE5Dv`<^nUKV-zfH4R zD;V+N1I9IaOhkk|lyF0)(+flSY23FZIwy5_YfsGnBf6ss!mamV)=6!sKy_{H+m`)v zx#`=ZPK!a_n3Gu!)2sPzs-D>r@Qx(ku86A`_^qfhx3%P>O|BeR?Pk( znJs{adbL!hM4hn^W%4k8j^;@a4jwX4N)qB;{X?OLi*i}X#RbObK6>S~*)duWD4JvWSz@Z+w5C+^mI>DI=^`w8=``v0cg6mh2^=~XY$fHg zr54!svaw;@bfaHq=^X8adIYzA2c!$FG9to^SSqV(v}Wz%Wr|ba4OHA_!Kvl?Hv#Lo zm*`4bc_ut}&7`(lT-?$?`Q947pTJkyTW+^57F<({<08OO9dJ*To^5vzj#H#$UuQwb z#`qxRQFn1V*3uB@;c1v^cae6l$GCdl949=q;ZN^6IFN095es%e;RCJvLW(3t?t{JB zPZfRoR`8ioNUuHz(`k>n?R2G!^p|Or)e&h@t=z3o%d0bNk7KK^Xg-l0*p;;<_9Lca1)bA@(4q6`R-3b z#H@VeaUCF%)(!5c7hAjq`LFM7?m@Z>Gp&heeosQ=siz)Dt+->hBkI@AMg|xe-#fQ5 z+_=M>0+1zTWeX0Kakt{zBT2ynh8?+KZl06^_A5)`ZRFxSdMJm>qmCU!i>?tW{-pA} z%NPMW{*oo~f71+1cnqHVC@F~6g@uf9#WlFAzI(G<)65LFcM`IDFLoPLu=p@N&FJEa z6u(Fl!q^LXA&-<$GtEZa$f~w-16mR@t3oxaYuE0{&~jp#ciVZC5a;Hmso&hg;klUs6IkuC9UFw-Ap2G7;R#$e?Fk_82m8;uUXvL7+o`h?)C{gFj3ze8N` zHm7cU1&;i?g}Q8!1MQ+!z8i*Qd>cSH8P%UnaRDdPo==U2A|2jf^@KX`bPK{=-e!iz)DP*1DzQuSC+V3~i;UG?r!hivE#eI1L1;wSWj>{> zJeAGhj;iOmEzNb!Oc1}*86y`=4=5#Scz)>_LzVI2(YvETG|_sZE5YyZ!IaZ6O#_45 zpLhlcEQOfUp^2Q$AK_k8G>B`P3(*M7|2P8Rkx`Gb?say=@RZAd(7+@!txX3vul<24*mOW4MN5vnP*6FsnBQ0EA59yx9L$0#Rv_r zjI_=5L=ZL3PI<+!e}U%(4f3Ae=E#sVi(#xB-rrEkFh?T&WE2%guGLyvDiZsXc*ZMG zFbHp4e^%>4a+4c@O(vIc3ilJXDg$7x}qi3ZL5dglN8Ar?I3s;O0YyaOc~tlu#ss zAml#9FtypivZOLD4^Kny6O7Hxz0yOLQrDJJcK3I}(&G3R%zKl5!y(Nd6ACNi^c0Sk z(tA{dx4$mmzX;cr1JitGHkz&S>6Gn?YgcSY9{TFmkiYJ7+_!_EXI9bbJ5phi zU?{`Lq8uK$v0C-()wQ=HbnZQtwGMPH-)Zg6^Sw>z98e;XJbin>oa8P6KR7<>@LI<< zNsNd<=zWI5CX*JOn`EE5E<-L}=m}&CZ1##H$4}^&OD_ij^wDbG16mE#QA-w2LcaZJ z)2kesiNV|f9j}KdO)PK_)6me6le3VbZES5dH#}8@S)ol>Rj2>{ zHAN#xE^+F_F@N$i5)%g}w8iH9#uj0)jr5gI!(web7y9D5D9qN!I*q`>fA%3v2-TbP zBkO3XZ54(2JW(VcdFq~PyM7b;XzLrly-F_rA@VVN3A=~gxBPKIfS7yNc9@N%*g);= zwDjsFz8i1NHU>;bgv~2V=Ro4CliE>iLQ&BQq(efgB(a!A&{^y$M|w|8Oa>yBLD*o5 zL(rMC@dyck(JVtXrei)14i0Z=tuh9{O&(TZ^Dlrgm7i*vo97H-RQbW2?bgR~>rjTC z8;O!Vy-r6$3s-SQMka`}k=YIj)aR((^vdSF&uS9GP3C3ixQ%sk{aOq}mQUtW}gIx)wyW((%ofv=)#@!A$Fk>|Zy8sB$%|(TmC)kwT9e{wQYu1sW*n z=>A1S_}lK4-oPFTi7;x|;Nb2A3s5uJ z0=fEO&_R3JX59X6#=B%PIXRZ&w>ynMN#tjGOWt(%Zq!V5v$)@&AEa!spBHtNd)*mK znman9bWn(AlEW{l{HwmaPxO=n)lz>2^@?sjZo=@JbT<6tb3QhsU^4dJhNI*9w~EdS zF3(BGaD0o3B>Z4T=DQn{TugM}`2!2X)B`KzVT%lGsW8fXqn4QW4mF(~>0jM4?1HX3 zBrkv=NAME7P8+ZriXO*0p178=B&MBk33U67l30YzFHa`K*IM@oZhsLrTU+v%ap6s9 zMc(`{aw+BD5|`EJprN>q1V7${ymvt~Ts@qf`S5?342(#SB+e+>ikf^}J@6WZt=x+2 zp%s5AXH40&+Vy=Y;HZedtg-QO&fdkA`Wf@ZC=(#2Bm-Cbak?!sk6uLb{m#; z4`v;fTBa9LBPE({)bq8@Xh53QuCCs$JnIKWHyc|zVWxWd)S7`_&Ko?HQXN${bI`2sbH9|Na#@_@Q`16@Z4u;2&&Ctw&2sr>t^s z-azTLz4lQ5>R=qYmF9<9XYTXa_{6f|H@VC0wY+F_ zItck~a`J*82>-tn2HV>-h!8ZAro{wMno;)Pck3|!L?qDhPUX~f;mu&hF%1iWt#OBj z+%6j{EBqXiPZy}qo`gI*OKa*`uKqS*7$a#hFWeEOUtia7lC0Y1pM%i{iGdzuljT5$ zvZ%@nUT{O2n73{ukwpZ)>&b_G7fdnYrrx*e(^Ssb9V_TQ7ykB3UphuO0#9T|e!U%& zeV~RccPSpfh8a~tTMyMVi;XcwZ)euKd5V)t_3vnC42~H5KzbL{c)^pg1B#WKBqKxk zpB#UPk%*TFLV_U|XU9q<5Ld*Gj5tc70f02kbmdIbR?AOXgJ2}D{|0uQyyxsGlPX^v z8Zf%Ye8GC9G3_NqLS)r{c^yU;hz5k_J!)6ufMIzKF)-G8lutkUEeL<^th5$dU7dXz zaYQxM;G%DAT-2&}zPn)Tx%r8OP}wKY<$Ic8iuZ#3CysgM6q$!6p0CWK%%OS(gbZAf zpD7sbJryH=VDU%bOfs4-@P+BacjFc~CN1|1^F9BFYz{V}6%K42d>#uA!?8N*SWeA3 z%*eh3^Z2f+Tjl2qT=%V~qx0T$c-@!NMq?!Y(=~dQfR|s5RdMyJA+@zEv=r6u@#~h$ zkOI-Md&GjAQkV+~BFE!*qv?svW#$JkmVO1}^t5F2Vl!#;G7)A-OOyK89%T#ug7*Gk z-^obWwmj33UVH2{j;ri)hU*@>l{>tyZtuK4IjdFPtX(PG8D-E(c};DEiSoYs`b zpxxM%SHm(%QgzS0k2&68za6v1FI@tdVSm^-_V+~jBDMpT zjmTXg`iKxh!@&_M#~3NreyvIQOCv-64&*R+i5%A8l3>|g6z?(<3mE_}yt`KxMo~c5Jg@@9#T287N$acm9d*DlzG^4n{7aDjXMLF3zVft^{0i|flKEHup? zA3wt7Omt`S8gggZ^RNQOFBYxh+(Gml%gUC1JAL{Ic8o8qitnfB(=sCr8NRdOgH0iEC< zen));lt`%rQ&9tBrMfIPQL$dQWidxRb%1lFrc)C$zoOFE5|l3gUgz_+u^X({u$=_U zf#8MKT`yX{{c<^@>u}&#z4fJjw_U>*+IiCkn7c$#JZWEf`7>s zKp@FS;lB66>F(a@oX2Qhx`=F4llN%9#HV=2xO;H4QLh#E8r44@=u%EGlOGuuZPQe& z=$VvcL}kUs5y!xUd)Oige~)+OeAQvSkGo58hUaDlFipXhNxK}`F)!rEt;xOn?=F^$ z$tZvyxQE^oW3+MFpzR(8)ojGF|5H*m_2;1DwB+lw=>%02FJG1NyaT0#u?V<}gfxVa zNsZ(4aU}O%$Av@F4dnK01R`=YUEXoSQ>UC#CNa=`-cg9DYW>e--8m=}@mp7h-;$KC zIf&neNx8eb8ykO9z89O8wjX`UMjA}`aCG+%Lr^VjDvTi{$3Dg5H+?{%nU5Wtmqef~ z;^ymg<{@PA+GGUv;ySovBk)Y6X@j$V%I^BCoP{8dNgS&Viz7zjOva%k`heumO%E=T za;~kx6hXJ#W*x>rU!qpBXj%*~ZzXLxf|^2p!%xj;gl@0A)i(%bi=AsMZFzO||7RL7e6x3&_sH_~H0`fen$o$n!o9y1Rl>Vx_at|Wl@Cpuw@`I|viB3P z;M{A2Oe@t?R1#7^z?LRakw<&-^uz$m#Qv45n)X1dQwig}h02@0z4IzEx(%P#3Q(Nf zd2yRCq9Z#V2G==ypS~W8O2j$xtR(}^e)MB*$5z&$JNQH>O^ti z6m{>i0B?!?u@9G3MDzM^>P!aN@}jMsGiO#qqIF#@({5_ervA{_$GyA>PC%cc2wqs& zn{~@kT#P9NtDZ{&Wr}{x6yUK3M%OF7O zoa@#3kRiv=-rAp?x<+cEK6JjO2qSD$(kH`R*aFRR; z&neq44v0E9nS)1NezW1yrjDMm@%6=YRE;p=1w30~b@irO2^Uy-?x`vN%Tum00bE9U zDcb?E@l{OcD198iby9xG=-%!CKdnqzS?$9u?LM;GQT4V~jyHQ7{Es3p08J#YU(m)X z#p>660}a#WyxCZ}&kOmeVs|%h6j*S&?b&9GIMQ9|2qBb&I*+?9%q+QiRDzmrp=Z54 zsk&hyqb+lNj8`;^Yp5!Ax!e$KX#caaReQN_#+4gjmLPP~C&%67Rz~&l1QaCirqkP6 zSEId~3S8<8J@&LfQArj+0CnN?ZvD^1EoTVLqNjt}HQi8G%vD#MXW^`G&7EZQe>^M; zn7>Y+ASo)$JH|2B$k&2dAGEq~$a@v@7{h}g!K;m}aYE;W^7S>u?Iqb_yt;=my+H=< z{^aYzjvoIiHqQ++HxmYr|URXliue6zL~zi^0Jx5?tzThAjGO1zn$2(s6XP&L1a(12$yHA%0Y zeqE5nFR5q~yV_nd8Bd$l87mflP-tiwn-kde*&$bE&M$aRJE3Zb>y83&I$+r|}FXo5Q* z#*U%X5b)P#HKXhYgrD-v2AC@(f$vl3PR0A{*(AmY;FWQJ*$l>n0zc%Kp19P0Lqs0O&zelr z5Gc8bVFjmFyBNcQ!H~v5C*upfrLsTV(y}r25kRRyJ9h{ zw?8l+@Ez`5baFyyAE9o~L`?#88oI(9w!{;TxNd$0gV5XAh`){&Z*!2(SrF~fK7#cf z)y4>Kw{dWMWEn9yEw{_6zxWxE**y!?giA7B!B6+{?B_@+=3puCXa(O(LFOc!6W zv%l;OA-BrQQv;{knK(Sr{Dh=7hC=UY*pBuZn&JG63D-R zKVlahh>5{=D!8`-r;A2;4L|TfmwFvlrDqBLf<@o#j&u0+p{0qo8?DR-MK_NUM;;S7fB4P(+`<+qLxA=c>ekmY=*y_I7E+{$BPmO}M2W5?pjXN&R z2W~?wgIk1D-&rC8wKO%qj@bgVfSp79Img#!zi}zx89MoZ1dN1$fQ~hK@8ICMa@3#q zAoOVT;er?Lg99RW^H7NXoaY-I;=Czv?nUY*Z}5tR=*DKv8hRGJLsXq>q?d;?W{`-= zt1KOKFvJ9j#A3c5VtOClev(ikVRy@J3-?Dan2{EyQN3ZlaBM(-pj zdI&Ivc6xd@ACL6FL`u6@s54AG;GFLw0QB)YAJ=A`OBjnS^l_eEkH4gCxv;fPn7@Ih z$+@XhO8qBb5?*}lT%B#)*Gp66=A;wx%IXvxYqJzKv%T|*&@ z+v%sTKK|>pgMwJ@CM-|T13+CboX0#7!VlDA5A$LoPWS08ycR$4^r1zFL{@T+qh*yJ zNB{j?&=IabZ1JSdg&ZtgKVOD*vmn6K<3%;jdg^C$xjV(BpL*F%em*5svw9bf{{s+G z^tj&|>&e2)3x}|4Wu$rDb`2}>*FV~Tw26sM$lFRW41)9#?6_|J! zx0=96YWz7z1o!v9w~ie+RYXpFBsJ_8GaH zu{cY9$HB8?fY=u`g$f*Jc%aFKj^yg31|b9d?P!3zBGyMI<$%d2B97%$?92qxrWk?y zbRwB)YdMV)ioCUZ8pJ{y6Su_~uz8#zz9smjiuB({0ih%B9CQbb##{&pJ&-=urF_hE z@7uiy*IvWYfLfvQ!*B!BDSMBWP5r3LvG#<7Xp$mv{aFniEgs-IMg@c6bTcm1tdMr$ z0-KT8`h*p6KLTpo##K}f2Rr9?y5X~oqHv7=h84llWMZi8f0b=7+V9_H*9v&SX9T^#C2Xb|D zySMoM5}qEUS{Ns2cN94Nf^x%nWpU2p^s9eJ$memiSexRMHxjnX<%hNxW0)5*&*Y8c zvL^PUB^o9S_koTUfQYG~p}|WarSZVccb;?$g&PMV!;2tYMS!>WikatMPAA%Kzy`fR$IJ2eDlN=gBbe- zTAOKRYAQP)nx(b%edBezXXvK%oy1b6Z;7$*M3w)0xL`t(*f3Bcmn6U}(-7*8SRYs3 z+h;6PldojB;F#dOOFy1W=>eq7s!~xS?BNd%5XDT}-0?iL_6c#lCzBag% zB>8Lx&F+{B61}@9`iI;oaC64l&aR-%Z-@sG^8CdA1VqC3?^gy<-Kq9bjSr*lzHo&A z-7AG?DgWE!AHS(yGTy&)UZohWt|c4eP3|DEbF)k%d=gs_`x!Y7RX;ir9G(Mm=sB{vJVxEaM2z#Ce#P}KH)6^q=pOdrJo-(QHKfktI`fvW+Tg(r0z7-qQu$2UIu^B3ar|DWRlp=UfW1GK>xT6q8So+%eS44F2R2xu!yx$@z9SiY`r zNh|lcaVpz%yySU;A>^rM_C6tn-3*jN&o0;^efJ2BA^8>q0* z+9=G|=5a?(t$5H?07Cp0E4}SzlZ8Z)fHQ1wTa>Nmm`Og*~Nu zE!DY=2}Habcw+4A{o6(_?-ASH*~P}Wsa${dXxCRASfn;t~Zx6)Ko}g1PS4+kaMM zkQyEkP)~%#tcYr^R5|VTVi(P)NEJSRmu(}fSdnGxku?*0rMhUHQ4ZA>JMy#f!#ejY z)oJ^h(}u;55#{yNtUSKdxn1b+Qeu9s?46^0CkrM!J3B8g?;OR=Ttj4oBU@Y;s9<@? z4atW!Z;%T2M6Ku1YF_PgP@sAOew*r@4yTK@aX&?W*(r-|WwmKSmS5I7D7&eF4}_d% z)%tTN_$TtZFm>W%0l<{}q2Uhzc>ESE_3H}5?=s6an`bA^#&#rrwqRk-K}TYV5fO@ zi@_49-H5RzvSVba|4pudJHe@@=(A}Cr?^hWcOQaEb@BqO(pJU zpyuUYSUna5#-6W4OB_>ba(f?0yQ;VOyt}s?*u-ytuqg(ZdRalcaA+-$T}|f z=xGoce9f_I<#HJ3MRCh=yO!Y*Hq;|T`!$AB71LcLePe7X-TLW0bP1N&*jQpRGG6i^HDKdA+*hYZ)MhWB!f?_R-N5RdRzK<_40_);YYjwwCquOmI*t z;O8O#FSuIeCxt0`V}GlVdi9EBmN`f3*Vx2j+%2|u+y4q-Z4&zEuR4kDXlGZ5VjM9x zb@1+%e|h!yuAKaPD^%q68eWDfU>OXTs8$~AR~~VTK0_Ss7Js4occSR&G0)Lv?J57k zQMup}m&m##s{Jh6zn%q#M=h!gn_0)o%aFw*T>u+7I6QlN4n#ad_By6U8Z&bNyoEX zH~fb_zkNe$Z~xbS{4U|kyfs>&a(R?8^oab?Qhm-|56UN9SZr=6taXd;hlm~yRhlwLW%OC(Jr16_S55&L3hi38u!nZPGh~4B2bS3%!(8c8wE`OFK@w8zjIw=nBWOEc79GcN2o~puGk1V zNR>8_DbzZ0J*dl6O%E>rXB6EVJDnzA0oB*!u*G?s6A~X#4HMQKAeYGnGC0sXbQ(Ys&dyQ6=$rYnt;Ic>E+2nQo3GsbTT3p3eaSJVN4 zNv*07y-TT18FXe{?rNX#RD0rM>tHUU{;5_SYT63O+DT({l-rueBJ&;c-7H6o6aM)p zaJrl36+QqDt_HIi)m=ydrc5j5{npqR3q^6@#QAHT?hfNsk7{fAQMQETw%?`XOsrrv z=^YhU)kDnQ+tC0Yb`6!6mG!ale)Unx@1K&yPoF+P+45!sj@n#0^3>X%ivZ0DXYpwj zlohaBR^Eq?k2j+#oCdxJ(1ypdFL1@i$3L-Y9J6)zl8uiE+Qu|DH{Upqj*7bQpZpUZ z)Pi~L+xBe<$kZQJgr7c;$}$L!-T@_x@dW4vR&$1JCS*3fo6U=Rsg%;dD?VRu!n<)a zWGn#NfcEi?cP!TJ&krhxO;?!A8tD$#kjL@*EIlfI$<^^fQqpf=9#89F-cUb<-wRr? z5NhJ;Rc`XEPD8HHN@OVOiJD1^k6t?$JC4KjR-INHmCjFjzz0(Viw<4i8~DC)A*b>Q zgNqbpPX{g+W~Xx?qT%s>p=E02;JRTk>D4{g0~}%yQ1B5W;;$hEg>jW<6=G zcMOuLk=Lu6M^PY_b9b~u|24Ihb@YskduBUK4tgqd)}w#^^b?%)Sv=Zud45h?qpd>S z?0Gcbbs)5X$q`y~^=0Cb^Cw>XroMWUn!E!111c@>`(`Bs315{9Vy;$ae>=L?<{5?; z1;6|FjSHh+CSN{-%X%iCuJte_nTwhLMh|`(FApC(ugB@_RN`*yI7Le4U_^r-7M1ze z&>{F+CCeiQ0*{$}8=yAHUy6QSvs~6^u!Qh|`!7QWwJ$Mbbkw%CA>8K1{?OocLN)@U ztGo09uzb~U1_NKXj9-X{5*^)!Ipm0Ju-_7(re!*HD=cs6GDTdlAN}k7vScvDZZSH` znCB)@b6-913W++rZ_-5nh}w{KWl@1OUC!ukdM$u|eihFgYW2OUh3i@-l+0sA`I(t^ z4V|uQVa;(LrhVsaaB1l9bVNB$=n9nbx+4&ClaRCf#cO*hnO14clcO%mHw)SI_$o_Z zw--uG5S6`#?maWrUYtW3F!eS0<>t4IiL-Vos(h?&60JHdH<@*TV>6LG+$wr5xQU@7 zGcVLiL;ew!{-JvdT*rm66{q$_Tvk>db5c?x+~G;rpgCQIG}z5#r7{9e1*BYs0zJ!y zK34r#Z2+MMKQ-%MS|laNJRjeATt|BriUn6O$f;QLKe@bGI6qTX^e-_^2S2y_BQ<|n zma+|QGMpMOtQ3^rk`(=&_4t0Yf`+GKQtg?hqt!!4O4nTsfwR7W(WaPm^5UmXVBR-B znbIsb``v1$P`C9@3O+ZhG^wfB)eic3YLW{STkdYkSOe8MD#a;^m%ocm;<;rCRdmLa zM7SpG?lb!=<+)8N4vHocro1pJU*FR{W0`Hp_k8|Mz%?}Im^di;YQc4;{>pd;sKr^@WUA!Bmd{F=5n3IK%roFaYttorA2-$WcGfUo1x(ZKFa^%IMXFs z0=A$^G`x4#$r%&v;DvbQakC82!%=%DN^-Vf#wxe%VJSOyD85)Q`aFp@w4fV}0bpaQ zfcPxMI;wynqS_hfb(r^=?zw`Y{jjOf56_F`sXb_}^$@uEE%KnyG&Y86$rN@GT?XAf zD$zsLS#?02{ktV{)cQM@_7cwDi`(0Dj;_jt35roae?bIuE^U z!^%izmKt#Ki^2a+W?JP@;Cr!Le~{eNr|aUsXPY9{`FC;LW2(FFkGL5O6^Wl65G;1W zi>C7}oS?ux5UmD;x&MHrlsv9-dLmcS%2CEx3s`cVXNmTcY@yaulm-;!oqhrlLsw<~ z&$WP3!?e=J0=oY@S-U|zt$x@bMZ#`JN+#By_vkhF`GTibtG_;CW2iJ!`^+{{xwPeK z%)v2fSn1Ng%=9D)3uNvnbk&33CV)D|58?86vm0(^DO_lMHS~;gRxlo-F?`?18S1pV zCGIBIGti3+=wa)p3?tavyOKuyp~UsH+njb;to?4LyzI@)D_1d;xm`B+*oNXaI6h}e zBklXetC6rA&Slf%^T!nAtkzlDuA0ybY5v>Cf{wtclXj@V!NJer;iH}$930<|T-4$p zj-Q-_oH1x?R7!sc1zHMUP8h$_X*rj+2N$y~Jk0*UkARWn;0bHwI}KHvdIScAc0X^k z6E>`n+ZAbA$!1L#Nx>a(yq7b}3!rBxaqHT0i+Hkb#g(t$C$Q+~i=uUXc{+T#oT^mX;&?tB9sxHWHOM5w2=#(jm%0%j+j!Pt=~y=26`oRK{i zVS)T%*Sxb6n=Z=H0Y7ZC@b%lvrzW7rqQ3HavMrSit^6dn{POfUt3sROs(Up`bbLP0 zuVK5PPziUK5|8l3@zG0Btkxmv$Otb8*|8;-6vCq^p6!hK&|9dtSFF25^LK_v{`!uX z%yvPCIP_ITnHAr@%LrYdb8ESbROrYwP<9&p{MBzTpOAPvY(}I0Ipj&VaV;tjZ_iIr z_1$f)Xp*994fR?4Lt8ak)(c5Pje;{p2PL%ZL`+U7 zxFqTD%zD@PgQ^|kzbWRpyFaFLqI7+kGv{dxh@W1!jYX^EY0j;0Mhk}a!o{383iA`~ zcQ5HT*UxwNqBsY@qKrq;yU^k!*Hn@9;*=HQAi^Cu*lq_k2-|9$99E*2H{KpZ7o;gk`1xH-z3&~4$-)aWX=_v@Oa+()GzLYp-FMdhPn>f&-(+fSxb(V?k0hQN?QPt&SFCx<8eDu@-m+5Tf~Z9Kf5~vS8GXI^Dzj)U@0_%c zWszVbwyeOYJX_Pl$Hynvy(i}KLNMNCdHS6!N6$$hhEr*2zgJnQz(Ik_O>SdT+4gSLNcUvRqRWpbCVb|A6oA-vL)geny|B9 zU*3CQ7&AVT5bw}8A++J4cIJ8O?_0t395UeTm)iW5H*jGze&cndkoCME`L>H`*;ArS zewQC>Is@eW@jouDe)lVvhg-!Zd`z1ZIqj&ms^5OxKBMb~G^ao>I?<$?OiX$z>`c*N z7HL?(#ePTlR`gS4xQ6tgvDs~;-_uqsqgNzZRz78 zQx4>eZl`nM&aGwn0emVpimQFn7bA26{g*^Cbh9D?wMMz_(A?dcnPl?eBV=!7>f#>% ziTW=CO>Zv~K1kGy#RhQ-%N+*cwu$laIW2|UfFnX^^^ki(YmF$uS2;4dCw6own>`j` zg5pKrcGv7yUoN^5+UTJq2fEER4PpORfPyoQMsMS-t*s4@%)!7gW<72y?(i2E3{WA` z>1lV_WK5FZJWrGeN<4MgY^bff*yZi-o(5+)m5ZXXvEa3Vl?B4^z;{jlP@#a2h!P~E zY{EGr(Xc-zJ?R_ulDn5Cx(YoT+w0-Cz(Ml0p%bQFc(($zeiN18*Rzg$JUU^_UQRax z`T6{~oGn^82a|fs-k;UE<`pf#vo~R}TQ2(XgdpKI3yaC(IRl^&5N#I}J7IJKx-B!| z2ROrn<8xW&NoL5zxqHjVp6t=EKCg7!N7ROr!@OQ;$c0Pu^%_~I%W2O!-{YJ7Ua}jq zT@LGl%BrKX@zZCCT{@l71AD>^TRW78sJZK<5cMhi$8P2|ZC*yQRkqomGJRE=9`|D13 zCVq>~%yYyB5fWNSRSCJvk$_2KXM@0|zAreHQ3vlaynY2DuhVrqgw-qcoWG?aPFVJM zu7S+Ue@iLeHlt@8fb^?bmId>jH>7$>&!&y@R5Un3U@>%(Z}nm{U`!@g&iL#5LJDY=IZ;dH{+uPB&CbSk$7E^dF{i!b>! z-(X$Z7aF)N{7Qf=zp}j7P{8cYEUOTU(E1XB?I>}LzC4X>J0gta$UiUi{Z;R>ao3TS z=%CEVZ$S^m9(Cp;5rAi5(cAvhkJXjTQa`Am8&}xgx|teik0ZQWs#l7m z*k9Yd3wEBZc~`F6L+VgpQvBoOOwhrqfD<_PJ+^#U1?4YY|Kg78TlE~Mz$Xj3V=}%w zrc!$M*IK##o^58nbZKr%*(P~{_y5aC=%J2Uz-<)feQSXX3?k&eo6Q3Krz?J-OpImP9I4R%zH|u;iV(weM&>|w>7tO`Y~=U2BrK0A4a#&|L#p1rY&3x&`U(4yB~Kh8P-Q z=9Q)LgS-_KM;rEeu_7it>t8-+;=zd@kRco^UTcLFO#9pR z70-9>X)-o5^gQFetuEQdD7Y7GA#pa&&3M%n`r>z2XtH|inovMt!=9wsBs3#_rmCgk zue|`+H;=woWj{E3lui=1EV8HhmA`ZLt9*y|n(V{oLkzW3)@QLEE6>tXc~m+33~7z; z79SV=$?E7vZ{h)odfmpZ$3RI`jE;(;=SFe*!2@DNm*PTYBmR@85etgB(PWx&dyyBF z{xcINC(szOJWK<+8)%rT~n!GU&JQ+iMaik-G6oxf zdCBp!8hQ-!o@G=IYIZBx#;tvt&%+7GJII|JV*wA3^b3Su39^D+fA(v5TjVbJ-x2|# zY>^`SIu;5x`F3hH*&EciPgYD7-rQPy$q~HvV71-gEPHh{gDC)SghzqydOI1qqGrmQ z#~?+1`Q2;8IDiy|bDMN@1|hyF$DXt^Q`6Gr)9Be1Wp)axneow>CUj&L0@am&X#r>% zmrQp3I^4w$jb-3x%EudDrYnajAq_SC#o01uJ`bo55+%~84V@RFFN4#HJc{cd~W*quq8%zN0G7Ye-KO?pZaxok3aQt%!aYCo2$ z)>k>ywOVKTu2#N~%_x;5{t%U9N-GdV~opaT}VMz(UeHqSOB~)&TeCde}-jO z%`9%@C4ePE0!9>CvC4F5x>TJ%a3NWPieY{VSjPoG;Tz`Hn0#D75%ysA5lVe7PU^j1 z^`Kwa2$r3nr`fXbu0;~f`3lTjF?MQU_%6_ffQi|)QSlF#G0TR;X&=f}Uo%bgl%_Pt z-OV~?nM}3I11n%Ve>H|nu*-9K9-A|IZHAMp293XN*8~RUwkkO44}h@y1~q;yBvkma zw9d0gG3QTL?6-`O&`myYD1= z3|bSo?DqN=>cGGN(DV+_8*FR}8Y@RIp+}8S2kQ5Ou1_P*IDu%@gx(iCS#hE`Ecrp) z8j1M+$#JH=!D!2R_ry!8$%N}6J$-lz}#l`JnwM{4JvR%RJnnoPI13j=gZGHKbkP_Kp(ltoPt7ZV3A*Tm8L?1tX z1pSebjY5w+Nn{k9QSC-#mWnqWx)6dZ8{_ry1CwY=Z=KwQO!pzt z(a-&mTyy})35rISxPw)t0ocgVcbJmiq_nI=Q#=v{TTYXB4TOz9QK>nr?NgFb%aGXi zHrOwP>P9{aY$F$*&M5O?4ez#gc}vX$GnfsOjA8$DssUh)SZt%o3UC2)WH`Y#so&eTZ?m!(V{ZW66hCxd(c+=&(HU{vrA6?F zBhsqDlpvya4RTpQuPk41A}io8M7i!85&uRTA96ppQ#_6rmj_4>uk(Q3gy`rMTX32P z3j1G6gD+4w^KA!#{O}0+UBwgCucZrrDbC+Pw+*rrxTooM=>MGgOHagQusG0_WwO+e ziciplsv#AtRW0U=Vu9ob{;i3>j%M!zZbukhf%lRDsWS7B4FI%$52!(MSlAr>2YxHr zX?3nv+J0GNG#jO1Mo)p-@X)A$N3Q8+=%%hru!Sx=@V!b=Zb8CrR^&CLun(~ogcj+* zPi!@aap;nxO%Pz2p!kDu7Sog_f7{b_p&)TH4Zv8>5Bmo>u4#uJBgf;aQVnQrdApt# zi`4yVWA{BnvJt&2{=p+aV4c&Cm+=WVB#RD1;w0s+-DBGoB?+{B^g#Y>ivG{)4B$L~ zuGxGdoWoB|#SnAPEPCo}>CB<@^z;sS5Fq@$uus^;enSM;sGJ`ZjrmJx0ZqP<_T)Ry z-QWfS7EW3_DC+a)&mBCvQkyRM1fLZ3_~GL$C9-G}(G@P4xCYI^HO4M5+Uo9jo(0P)FR1p5XtPuhM$R0#k6>ujiJPk;_o@-eCp(nXzV2U*~ux?Jha znT!U(HUn^&EXHxM>N`l9ObjUc3LZHMFjKDBuXA$8)wSpJISFqewb&Pi{g$z2^~-cT zpY;m`%b}Jbh1K0?NpSS+9p}T@_x3w&FF8w8OOLc#{m)WM4Nxi5bQ9(stD|2!}Y? ztz4e=yIO}{m}J{rY;JT|-W_46%Jf(@)Rk`x9nrus2Y-(AIqesFD>-Vb7D4zeaq%H_ zaxPmLL&IjDzqNU5nFQGyUTqBRwV zG07E?X8*8&0Q4C2afyEQ1qgC|240;AkQw(HGX`kU0sch7jHRWeGR>R(Xoi7DLT zHt_4S?MQXq#jxQ?ax-cTrH~r}$~yG)(u!N-s@l9`*7|@aB9;Zl@$WMNtKl!j<4Gu8Q^2im!1vc zU9)XrHamr9i(V4!?N)_>$_zI@o!n&0Iqu+0biQ^G!FC-;0^~lEaQ8nQ2Z3EJNC{Mx z7=v^E0w53VjExQyfXIq;^2y1`Q9{J`F0_o2!8;2#26@oqaK>d82Bg=EA!RFhLOQJQ z)At1WMZKyT#`)z?eg*!OE;&(AQc_1Xi^_l;9D@S33R_bQ6eXPXsp_H6BPwL5Nw*n` zSd;R?Y6!Mtd|O}5;me0wsu7|p0BfU#)zd4{{b?+h4?Y=ZuLAT}YbBsIs9g*hCc@X- z39K00OD6MAoIcn#Y%Dmv%!;Dj0!Xpode!0|vhPM-DHX50{6~~tr{;U#w{EYBfaHHY z_g~I%gJ>4p*JY>pHxCnpT0r7fk)v!-!1{UcN)CFopAZ2~(Ge2&e;K)(JP^!;s;GrE zBDXa9i>y<9Im!nm-Ugt3Hda;zGt}`4ux^tvXf^<;Lr8inp}2}l7&Tug{YgX9at#j5 z7M)eRi500%(!W~i^PJ=`ZhvTE!dMH5frlh;$q4bawY0RfwRK8@fU5NdqrX1kw)Ay6 ztB0{y%Uj<@BmrzoCI%o#{>$5l!_hans9)<#JN!B|OM#3c+U#j%3rRjvq}TKD{np95 z*uq-QSt>ZxSIV-EnrkJy0sk|Qn59O3uigGD$u&18Ko+CBR58Gups9FWH3_!MfFLc2 zG*h&Z5NLNX-HBiBCqTakI5Qx=y4ikvl<>+=8InS*2*FQMj4>MWgxFA=hA?go2axE( z54CdcEo4LO)kW8y?tcjk8@(%cV6$1^y!i40NlifvP5Mn?9fw?nT3ao0U$GMWf#W{v zn9MmT4Rk$Lz$@fRF(J8Kzd{y}pD!WM4ySA|IF%qB++r z9E3tma@?W1krqbGckL(rm;k@;=RRdwj*Fg}mIm-Xfp*5JDLt~=GK5%ep8*cFoSfX} zSWpFca#_Ki5Er$8@cI&}r$(DjLvZI8Ir!eqj}?Qm?ALhD05!}1nHE;r3&1DQ^YLk9 zp#13SvbH8)5Acn~`FU^(>?R(IO~cJSBqu?~f_|=p3>!|j2L+CBe>kfiX+FL6``NFK zF4>!?V=f^dE$<_JpFJ|#QB-{QuZymItTF^lj5~LjabO^ z@>tH=0uz-1NoE3k4#UG86cjO{E4@j(F>o7@B8@Uq?7y(=t1zm`nx7R9>(^3;Hveqs znJvjIHpo_ltL0k1!*wYF0}vMif&~jqs@iKY@L!_)b9}S;fR4Mt!|t>FtvbJz=+7hQ z{eD79(C3x(txoo+rJ}lBZhp3SCsj1n<$U?R3UKtz6Hji<9ufE2)UWbMl~S_GuIxam zZf5uJd&Fm1yQI0r^|j3Bj$@mhU`B4&F(`%_#ghG#^bWN#o0&*kT;2JZa`%nlMd`@x zfoP<1VB%9vRoWUF;>2kYT3pfVhlE&J^PML;-uZ@N)6voWAg3ZBSu(aKW<%X1%jzl2 zJ7$Dk94Moqf^P!>bU3?R+Q4|*#l$TXcGCBOfnh^JY;3(j#&kUBP-IV8`3hJ>ieSZ-QUky{bwYiasnmBHoZM#F1B`zS_w$R9H8G> zRs8SsPgKZ7S>}%RQED6hu}(c@+TZ^i-Wa&<-Fv$nq@7^aUm{r7rxhz`tzIYcjo=>l z>(09FtRKT2dvM~!tHR-fz0cY^E?Y(t@`FY0)HZ?ZB45AYd0t%4Uiwi`-{IT9eRZ;l zu1jNzes+!lWX3vBa5)y0rz_xn+&ToCQc30O;rQ7WJv@0HAi5jla?ohfXU<(nCA!f- zqMg2W_+)`9MiWwc-hXgpt%>NN`1&^2+$RdGf%}u6-g{G-H+P=r4Qup*?rwr^c`kxP zJ81Kc&|yfrpjDXc`A=Okys=%ut9oy5K&6!?qI8t~uIJ8p`l_JSfd3P2zTTm=*Z1= zG5@s2Q~Ty6A71c9UqzX%W;y+vdZV+>I;9funK}PHC!_4HFe{T|`eTAmxR1b$9I!bD z#J&8P=2-6aFI65=r4G*75t{5Nw@_M$;}Qsbn1F@{A9pRw2z_8lT)&-n{He)Hq7d5K zpBdmU*k!pH>WMxB6WV8+NlyYvi{>g56qsA}PRA!MG(d<2IYOtkCrsN6z zdM>`D#5t5e9Ej4vE^?ZWM8PZh2Eh{SzdQ0jv9Yi85+k6S^a)e zn(Xl;oUg8a6Hci;IRw)O!x~^N{0*vNi%Rk)F*WIY=F{HscS~OD)OWb>dvE!b-fp$@ z_petx|M-hSvK->yLdnfPu@FO zi6NnY*RdTyssV~Fh3N7LSY-xHR^^?m^Y+<5;%|RbNcrjVLl0t@M z$`Oe|uAO9Vrlt??U>zp|Jb%B08DQzX1Yqg6K+FPI5H~k5&J`kY7PC*4b`)P&P=z48W`6)8I-InY=m>MOt{FY zsPy_1S4X7BA9a&cvZEaxQD(LXbfx6kkE`iZie)A1NPJ@}_c|-FH2)UUup?{o(Fv5W zk|&=T8Pdoom7m6E4i8Mim(p&ipIznTVpHxG&tCir-FRui-0XkLI%4oNR1DbPFIm*P z>>LyCUeT7t6`N$vtG^fJp55%(r!9#F%wwwUzrpFG~tdm3Z;)N z;0?D7WOWpz5}jF-A6(Nvioj*hST9PROHaFdLId@*yUdcRL<}F_`f!-+RPPlEruFkD zTFM-{iRVr-$&DfVTrtY{)pNhYML$(U8j0!S!m^6}ua6@V26awKyNjXAV*ufB^4wqJ zE1Q1J{!t^MKFYo$ocIF&P;x@@v1kH5RL~a<&x?B3`^OOohBk99l0uo7vE?vBwWfKJ z=uoywpEe-SeVCiVUl{~(J+ECj9|or4yy@F^FW*v?%aR267R(mP*@}YM04sBBil;2Y zazE1a)6nyAks0cFm|S1)Vf|$BC)3!?4-rpX{8{w`A2`pS6Tf(88NCE2z7gC2UQ5i4 z?tF3lsG7!>L$X7(hh34IXCgmE{c`KIa!reqWl6T^w?BChK4=_B9)z6pp&(*3(Cj~Slmu8N!>0~zR+Y#Cd+RB?W5b)2xwvqZC+(9qe zLv94dyIzKy1fJ_@Mx`o~Nh)v?K&zo3>?6F7L65Ce+(i)hFz%Ry_9& zqGY&y!JqMwnxE&P``~;q)TyrZB%Vxe?R$?E;YkJgn+++(W-@DH40fs&;pV{lwXwA{ z=N@SS4^L8pQIitTtM0d) zD+~=$j7E+G&GZb4j<=mwX4)Fon++XOGTSs%!D?PR-=UIdyj}eiGU$kMSf_HxyF#vL z0@li9FC8c)xHa%YiA;S>Sx2ILcc|a115Z%v$`kwOE$aiIe)(Iv$#mCEuEBWkQdFo`Y`{8-K)ye@(tZm zQ!)4Nv%&#c^y&NM(`AOaH>NISD;sO|^CdVF_zxu?ewI$m6uD!>rds)r68Aqttl3;t zrlZ0!>GVEWoqR3KXH9PPfQe$|c`m8Vuo*U^A|$&3-)K~JQtOtD6=|1CLTMxYUtswLwQ5YGY1vJs1x68xfs z;#Xwai|*9RRpsId{MKmbswTv-zFL+urtBbrAysWf?nTF53BTe->WC#@Jjt6Uwa**) z%m>o5OI@=lGT8bO_-ihsAdXTJ*vomb^#Ls9fD3Itj;>&d<#?8K$89fThQCndNc&L1 z$6FmQGOiQ`L_|FmwED`~z<4jGI1eh%HDllu1u4@`9x!la+toiq4~P}V`K_} zzvE@9+rayx8vR{tb>?#71_4e*y!7GbrKHYKKCrI}{>O{2mXDdPuHGa7E^Ijca+82!7e46M<5*~P7Z6tTQ-G#FX3VwWTvb&^_Oc9Yc9sYy%e_P9RFh1j0Env z9!e;U$U$V(`V>d~9B{hR>273+NoQ93XrzU`^)%IT_$}Pb+O4(5{NTF($xZ)KAM`BW zfMk$`vLcn3v80!!RJLkFxl>Pu|1hywfMU|)Jf)9%X?+tVFQrZoi7D2tRlol{R*fYd zPbhbC=YGft@KS=Tw4RgyWB*%!_4eee@ZkA1Tyy@g8sd)HwDa?Kp$~u)lt9Ou#Sf5u zqW6FjCsu;7f*dmcr6&5Bf(N1|+Fep!1=+y|g07lfg@A|x2q$!zQ|-`&*;9sA2L}i9 zG~ht0CTu9gOFL`xtJDp=5af`Agje|H&&@|n)P62NdfspI6lWXr7u;C|P;)ywWg!;$ z;B6tlLnjcB;{!=P>FwK#OG_t|H*euM{mSvJinV|ZWstqK4}bz76%}gMgScmjzt!X4 zN9ajF;_c_!ZOQpx*_Sv73utEnVaC$`XC8!}ByKm$8%z3N_AWBpA{~p6V#0EZ{j;WR z`h*Y z7CcFhh$jiQ75rji?jWgG#@^gssnWCR$W5FTw}yv@)l6Rj?xacq7!5p|Qq<@ZlmI#oC-uGws{TKo8 zK*Vi(wyLU1{IxLn&=nvRFl4&w=)^VhM;u~gi9db%N5ULXEJK0%#3B2)j`NW4rI#N? zuyisQ#qU9XDu4rhOqc-@57uQPpuvs#uRQi(f|Ni2wE zO`Pd{Lw7$M-$Q_3*`M79igHSbcc^^Dz zCVRkOhOYCV2uR%M8Gbcn*U1{K^d=gR;D4i;eF`x0=f9&e;Q$SVSK?R|33&4iRT-$o zpl+uOnf$*D%MW3@exFvTpKuf(3h>zR-J{COP(`8+e(Ys8H?MNw?Pxk^gC)HyS`_AT-1swPqipJ7PZPk(vgAmV;k?WRpz@1wv6J{BNr4 zC2<`MjLo!>l|0vFPyUDs!Aj8^b_B2btn^#F6yxO?4}k*@M}t7W1NzZuEFJit zBPYNjF#^#N>0bM|nA}u!&dl{tnuZ@e#5jR~tB^0AKL2z&Jv(lk`DqVnh zFP89DqeF(k?JKLIQS&oTa;G24YLTFUp+he;8zSR&X+MQE!3!IE@w-2Meg9S*fn|p& zj;IR1?mn;G6lr-YFMLsa_d1o9|MmB4ANNCnIk;Gm&AIlse;I9pCdv&^FSA(eN@>&a z&O%|`Zs+sQ^h=Hp8HG?+G5l|mr!I>aw|(4?*A5a-!qxLwO}Cm`XbbMz^H4^1^c(eK z%O{KKGi--Fkin~oQ=5B21H2?EWm&|2zU7IsW{$v5bbma`oMnAgRj!{_ith-2+yd_B zuppoeq}2Zg^pSJy|~e}vlTb+Nzliv7{FwZA?OWW2T3P^kK11UB*7zg(uC&nxb0eRr$cBC@iZ6qq z=S0E4six0m_{1r6TxF+;*?j$OX%gc17l22$!vSnUAXKP)6U{H}G8dnS78~6`X%^@x zP!c^c*^CS#y5G-_+ILpi@H|MJ;0LGQco%2n&!uR?-eL!pd+4Xqv$5t$tMPB2VfalE zTO1iyYqH6{6{p4m_K$_1H?5<|gp1SYq9mbw%D;E^pD`58r)J=37Pr5BvA8}>|MXcV z%uOKi3WxP;?XCax)4t+(fPsH%#tcYZs<u^ z(xVM>NJVX?suI|lFeFpPP{YCqH@E?-G}!9E!&-dPw7)v!jGFmwrMWouV?8M&Bct+O zl7RiI!Xpz*bO(dKZB)=u73Y0Z)9u;&O=x>ns?7hR30=cr%w$1Z?(aq`xBJ%jDY|@Ywx7Lms3NXye{HGSuGc4f#EP)%4qt07Hk< z`PA~T$_&==_o@6On~6tJn3n<@8XDJst;vXZ7SH#aOG`F#>z9Ad`kx=0QV5JdM#}fh z9{ndffnyx-KzCltB%J>K?VBckYM4GkpK@iUuNz1TKWeiFacmXPcg)1$bAAjMDW!i2SJUmB_o|H;Fy*HP2H@CNOV3|4yyrr(m7`@6ml?KwU8g8L22Vf3xs%h)X*q1AEjJ&|>6P znK?>W^N`=a3-+q27!FoeAK4!M_C|@9R}g_m^%^`?H`w;bKz%5SWqy@9R9csU+CcMl zr899>Rqo|%*dm(@-Y86;{QaFcGYj;>tP-E2Z&`+qNZ_-Zr=6+d^eq3!fRa(ubKw^S z-rPdoy9f*8lG^&ROCyK$v!iFmD>UCyYj~I#cQ2vn9pS9{4BFjz4I@iLGs_ciMC{*1g(7IjnRJngemqyW}$3 z)V5y*#KpyLG@|t=twYHSHzI*fwUEFfHEl1aR^oil{9yT5n4M;4FuIQkqA_(%sfYDr zfFf1R$`Jp|@#-z`j!4~i_hcPSQhbw7W^NfHp*}fwTEh7fLYvh)PzrvYvQ{$Mp&Y8h zKuov)!#g*kk{t1#j(wG>WGRkhoUx~CV5?#9x$xQWK|n87T&naB4*E`oDD(J-j)#Ru z?;46$wbIYsklnJ{Hl}v1Ig@i0UMci^bio#g9$Gm%j_v-z>RdR49~=UUB|r*}J=SP= zb+eFW-3uPz}NRcN#K-h9?q zM4nTm#KZafT$CDc(I>TlH{WkQ^>cK`6t_P)7?QkaJ?%5(AvZ1Tx&*xiA1yfTtWVN3 z5O~zkkXG&wOlba6RN@CA$h*FTCq_%$>Rc^ zUNW>1dug?zhI;;ExpCmZImHd=QNF+@Jx`<7g65rC5RTk3(@;N;!~-`qnKO4c&&FEX z*nr9$8%^QRm+#WMB$AblT>sk$e8r_vFY|cFTZPY_so|bqUPS4iXM<@pCrSKTD z-iq(EF<8o+5kA_@*DuMAS>GZF;Inl2L!P;%ew z==?Ct++pjK$CAR1F9Wj;&k;>0CmjsQJd>#K4ZOT|21p-1d)@XQc(5+^MtRRD@k=Th z$74oF)0g`C=`wIb^0uHUv<>7qd-gmexl$o_0pa(^jtvt;G`35|USMC~7J9p{e&hJt zJOw+VsQwkKykJs|y9W_GRM7`B;49_W`ONUj13@ClRbw}&f9oBwO+xMCFzNO2xd^-i zQp6Kfn;OOOM$;y^h0tQ&-eW-5K^DHW)qFfX{a7=r#7ypPUGmd+-Z*b&}=u|dd?24m!H|! zIUwBZ4VLOU&mxYPR#1A;5-3ttd#32b_jBgLsE`_DT2Bw$8_!bsB z+o?QR$k(S0ryp}TE_avJ)@tfj1(wWM%=)5j;cEIG&RW^|q=@uW>7hX1 zG-Y}Pi1DA)@Ge!=-aQ_ovcN9@ZG0P0v4 zZYtZ8l$BfajQ#BAXhn|#^9rd)*!MxH8EnW?#5lI+oR38!4(%l?h;n+12wRSu=jk^r zu~4nNOd-M=_SNt2aBE@XL!>>n+pX+A#hG_r|K>jYVD_8C7yjvenWSr5e}JgotEhV< z@a}hA{fCNQv2pvdMF*pXAyz_H0EnTBV%pRLaj}$tBpeimW2NtsV{KzQ;iDp~x{#GI^kJh&Iy{_~R zxcv8E*XTm8VQD1ImMx!*OwOUXOT8rD(YQ=9&X?-5ZbRgJPu^NKxJC z?fOKHvfjbG_IlhkY(4~u-$0GKROvYzkfH9OVN)UaA?BxF>yrJh@oajlw=q@i75aB{ zC+q0Aqc~pc@3bY9e&@thKU0H->w4Zy?G^4v-0?dn6Nq*Ny|xNG)m#friu(yaIw3XS z9zjqf*TMF3;`m@1KMg;^DvUQGtfMl7yT{3Kds#{6&;;P%1r$aY``_G@1ik&E# zj0Pvhs&^-v+F-q>2Q{$*6@p=gWx)vKFkc+^`etySX3cbD6hn^?r)UrR2ZNb#D{j35WWN1P6zX#jCvKojhz^xW%0J ze9BH)ueR1B&M-?KR;Q_pe3V&At#Y`X7t0qr1Lx`RWBpsLa%(wc$IV0muB_7;Bz4!7 z>+fpG)nolI_M5M{Fsn#fXb+W6lX+dmB$}z@KuF?x<}mR)A0U-?qYuhcLie>LtrzW@6bUr0saqdzG5DMcD0% zC*Q`i7pH`R3Tsxsp_zpzJ!@&i__7e2*j1oob%b^GFg`m|eYRU1tz4}k&g*)WuXm*5 zuW!rsZ*4i1Z%Vdl>{IQc`?74xAHl->sIaDCyQPD8rdWcaVncR)wCGjmI0-pj@oMwd zc@6+gIo)|M!Gk)4iYdKni(xvjZ^02H?p1mx&eo*^ zTDNwXJ30WxaFL=_c7}y$jEq5~((;8i4aq-#bGXD(pDIsZtv1;cy(?0c*^t9hzAqJd zP>U~pv7F!LZs+Q4s$zv+TV^6x*ScpqO9>=0~n$Nc;`qo=rX6#|N&?{r-yZhmhZP zAH1L1qoQ~E!ep;RaLD7!$>H7+aUb&x(U!5`On0S@pgvqYK zLGw=WhXOPZZ)o``T2uS^d^_&D1l-*)9T zN{wLFR?HmVi3F#%`T%co9T+`iU2OyXIpNFl6b8r%uY26|roL#7!4ARiSmeD`2*(+l zJ|bqX` z`@Kp}pu`5So4woB5G|&cszyZ@O*ivxEiXzfXLf>*Ts>9vRl^&r89#knaURDP(apE< zDapos=;~u+rfjH7UFeXuYK(n|<=jSd1#a3Ipg-EQC(a3XdsecvuF$J>9r5@sUM*2MBXI| z@k9G1^h8(6L!2Ew`Y@OL9!N_$o^ieO*3K!L)`XFd8l_lLMHkCE-*>ZsgRV;fX0t;CN+O4Oc5i`ZDF722%K%HB1W#^;q z@JF2=m^ZWJcw*BOrYmiM8HS1kMvWJ78Wcqy@zbsC4wF_ISvF5c^PLn7#5*|#$G>)J z+~87-r(m#On3E1Y>rn&w%dew##dCi32;;NT~Z zAX&p?A_=8g?LN zbtY*a4gtX@+46PxkMX07NI2JgF>%JjQKxSVk%Vs*47S@Z>FeqcuWXH4A^2M4m1a$u zDMDko>l+3$@IWSj`StMU7K+RrC^T5tTu63(OM4bpLwx787>5L0x8|`urye}%wDXv( z!Z|pwuW&SO(?)0$FZy6bpXSY#ePs|$BLMq)JapKH-+gm!(p{eP#GC2z;CZ&l(?k`l zt3pl!wV%$O^+`45rtMM-2@d9h$kz_JfCO6xDc%f*GE2wZxOW)5!Db&K7x6zu40-Ra z$SimtmVBMRfvA*Cc`))23+W*u-t8}V5JJFH^q zmg&#lt?1g++?c8(!U%GiN&Fmc_UcRKAT*g;f#S2Rfxbcbou>CU{PzbR_SPg2W${#g zEfZbF)5zyp$i<`{#Ing299nb9EeLk(3O5N_4N!aa6ML$nW+nlUVEhE8h9ac|&QQJh zPwYA#cgHV7)5+^`m1yZA5V0M=Bbj|d3T>2Mkwi6dlXoKA8nxr{cIJV{%x;Sa%0brw zhHx5jm6@BI53pP9pR(%Xk4MVtmRR!&l=G{w2-eLC>XHAnqQ!l@YW9_Fm^*6|WEF<{I z?zj70W#_AqPQ0t2b^_Pj0LJMBr-vk6!*GLbtDnh7G-emd5X&z`CI;t3YR)tUhL6Ec z!a6eWFL)4zPDp#WT=AjF54ZsM%_`d5iCJVG7jwPOXw1tU`AHq<;38$A_H3jciNEqsDdoYe7p{iX9n@MCO0Fv?Bgg!UY4woe5|5rNcSFd@$|Pf zsLy7d`9$05nA>e|VJ~}A%rDbDh)&aathX5+KY$sP&5Kx(o>5c;frPD}OFmI=Knm8# zY5r}+h0A1VBN%4xN(gJu8Kzr=PW35E=jYM@e)sk%eW>0+8gJ{G-ebxj1Zd@5lMxXBqi|4e2p7OdtD}|f2)V3Bz#n^x z@!k`epeA`Q70>U!G?dZO7+psF+QqsWPTm;WL4E(dE!Z|R@%1E7OOD8mqHpM~DyDF$ zI1%H|m@X@DsrI-dHzuOT@988g?Fkp$wQSzvGS_En0!AjHfCpb^fB<{zM$V|g}Q+E zIt!UXDz}EfXQM&~6XR2x5bGU?pQk|()HTn&-M=_Ga$SC?p`PLJA!R%DyWb zoo9U-ukGWoaaJMN@%Y=#-D&9h3Q4R^!$L#OtHP??%~PeGeckziW)a?&BspuH^Hr_R z@i9NOK-Oh<2SF|#ETi1|f3ANp9;S!F;R4xsq!yPeCoPXqS*8xj@4d}Wdg z8%FzYv&~FBVaY_zO0$5`UHO10i6X=WksA@sDFh z4|0NT^d{|eq$CxcbOI)6N4ye5AAf)C{dox&)s6Yt<`k6)Z+%~0QGec6q&R>c6%?o!rj#-G&jS#7n2A5p= zFi*F@>UW|Io66H4dgIr@bf_ov1jlt$zG56|q0dqpF57ZymP$$9mkSHH9?bYJN~UF> z6~ArrB>^xz6i*9GmsTs+%HE?|nR;aT_64Tp88+nHMc%I(OSB8B32}=O%lK3S>~k*| zn9QFIUyvhTnmjX6rc`je=FBy%>{<`gT{qnK)%v#6?rc(V#> z+rwQC5pK1P7kM+Pjd^>n&#VksmZHT?o5Lc_jy2Gtu<%>Dag46OF!&SFmZk+ zKAuRntR3br#SiIbc^~PBs;@N52`MT6QRQTOLQW> zvT-kWxVXl0&nDN2kEmP5uON9W_Pigr&~mGqhR%g{H%YVBXZSWAdUA)Vb zCV7&rio$fs#7=|n5ancJiTqF<%Sq=OpPaCXuF(;;?Lm49gKf0j&FMKM1o!Li1XK9F zSB7)fa>B^0j9XNT00XKNGez2ES$v#ojpfi1wLW~sipri4E)eTY{#`N9vaf88`kwYf z_%N-vck`ZeI8BTas-@B_A%a}0xb)a({#~Nwkhd5U9x^(dUI?pbutEQh_B>@jgtbOt z)QgmVjP-1LdO0cTQp}I+#YPdV{z7~qt-RI1qT#-wXWf2>3ster+9dfmIf%b2EkQSf z-?u|FZm_oy{&>NXT=bNK@kDtSmGCU$_>QJt4}P~|(m8JWMI9dE3z@;dCvGs*@Q=9@ ze{Zqp@p-!AWd|b!?;!!+uUBBv$Bp7T=giMW&OURk=EdW^M86T^+t%oI|C1Q%Y0gD+ zj^*Vr!r*M?VRT=)665X}B5_q&J~4c3j{$M0KJ;$vY>ccOFWy1I&$wp9naBo*WWtes3X z`vfexjEC%EU{8}5vF;_C6}+aC(7S1HCsvo29SPYpd6u8mHkp|A&1@{>zs7XK zSX`EMFLzWM*=Z^+wlY}`SCR%7zv$}L{k({qeW>c?Ed@0ZVK?c$Z(4e|Otf|BpFRK zyqDZ2V}sWGQin1tN^_VQ#-Gi2b92sf@A{DLTHCjPTPVUw@Iwe?6ZE52g6}=9p2qaP z769Qa#A0?O%pi^zEYIa+aD%$_2C>rxFX;q}E#%lennU?&y*~qiFZ)1ip>UGrs=(-s zOI6Rgwb*FIQLKLK@+7#VhZS@3F%(>~u@Mj-KO{`U>NeHm=6uGz$&FF3P)qCy<-&9| z7Iejsh2ztEB9!jwI3^CA6;`;8LlT_nLBrqT8rrhOM;AFlHzPYXe))AiG$bcnTF27BkBz*_#yc^Uk35d zOZoWav*(U&Cx>j>jlv=$V@w?1P-vAe?9@t*8ja6ZR$LA*bA483(PtdAVA9Zyv8}_9 z3N+7n?%vAULXlIeNP2C=`vY}Dv8SQt$0!c{m@2$CCh@zI*5EIu^~bi|B&I2u#IpG5 zlBWSjA?#(izwe&7gI~Yx;p&>9a3;sG;8lz83Ey7A02 zYi6}-cSunH99=Y}6tc0gTXmgkX>~+dR#30_YSjjCJ2X7Lr<<|jM$eg!kXa}NaV(dd zSkdR{3z7`P523_?vB(xFiG@tdisVISg(O$+6<&ljS>y?S(1iSgU!-H>pku?!4nFpV z3c81_A4!QG>|v$_?tB^^etG^;m2U8aBx|zK)aA)}RjZC`Z+)ly>k;kL zWtli3Q6bNdWUZ=o!+6A2^0Rp8e_|L{4sHV zO9Ve#`zI6UMJylD?zb@05`(^jgVR|w=9V`-D;g;)#K(ss;1}r_JG$6p?(ux|vV7(l zClj#~EjBOBp=B_o4-Z}1fcZJFh{d33eJ?q)Im(YZt z$5czZU2bT~h<7rJbp~BXSJJ>Q-z;wE6kNQSywv1nq1hcVyfYbmHefd2RXA8r5 z26G1L`{*|knu<^~A3WmWz!()Vh^#uRbY98uAMYF)IZQfL8(8LrR~AfE6w3B-QEF(F z)>fRvrS}-vZ){p23JS&xY-i%JI}6ajxS3WJ$@6jT*182RaFQxhGFD4>+FLwl0-Ig9 zNFfuKWLI_N{aWnTR-$^`U@JN<@0ZQqtfrN1nDmb}a|$2rVS*IP_I5^sbwdi+>T91= zj-I}=o-FcNITy<55}G`k%QuAnKka>aIF$YSww)9zp=|AxLRrh+g3wq(V`(heXBf#c z7;B|Owk*kHm)+P6GYq9tG9kk-3?kbw2xDh{x99ivJkR(2E`Pnpd%W*){N^8rZRWo3 z&;7aX>pHLVJg=@GyIyo_^0K5Z_mnwF+RdgB-{7wYp|dbJH-12VwG}?a*U?~Go7bC8 z=Tpo~2Z?x};B8nip%qjON_;MEn5pH8&rPF$U?HqlFIw|RAD6NgSr95L45gYnpV7xu z=NT#a(82{ni869711aBQl#5CyN@hzYH*LGE{Lox08c*_do-AK99*%#rQQ*;*pI*7q zTcUdWVDNfNAJ1Ug@qu0?Yrez`x#nNH#U-BI`^t)c!FIhRj4&Qewcd@zTY-)N`Uh0Q zm0bW7tlZNAPXQ-MH%J0_8{>Ol-9$C_GwsQ8w^At9YU)e-mWa^i)OOv|vez{WWidc; zhq|#$kQ!LroE*NKb8}#SQdvpHROrBBWBM%S(_~qxP1gqd+knBeGR|+LeQF9Lmj{Aq z`^r7nk7*!1R@J6h9@99TU4z%uad0b>4=Av3fsn2c{I*+mNV zj;YC7>r=kdd;lElJ+t>euZE3Ntg^?Rx;~z7b04hCaSxb^1Vcqr{^%QhtJE667K*cy zDYLG*4P|(EsN7w%@|$zhyJVjTY0s6@3d2*w3AWhr21jw--0ss~&cq%!iV?gmdvWAq zBCW&uTA6K9p?DE_L#o6LB)IC|h_9Q+IVNUCOe%cDD2IVXHeyz8uQdRu+9m(Hx< z+aeN{@~ggE{d|mVXKr0lNq{OS|6Q;MTjKt&m`Rg@vr+?&;@vMY1ybs2dX)x}lpSCo zlZvp5Q}tRi)TfTQx7L)sqRn1BKPkC5oarWCQjX3x?E8K- z6tNth{3*=*>go9IefLO5Bt>eMX{X4k=-`6AA{qgpn3%OM&Sth#(|P5w{NZ+n`-y59 zYNltcE4DD_e@SD7Bo~)(BID<8im0}Qvv+ODmz4{?^c1v3UY|w%IHpm+Clyis$C^mc zrMb6TZsW(}l+2fThU(sIb2+XCh^^k}EQ66V-7Vj^jk`Ua7-WnXnQ`HB>Yu$@%sM!F zjOp>%rK!-f4(gyWZ)(y2cD)z{WR6CHhq^D=%*49*$>5-FSSlt{&Qui%e~+8AsdL<7 z4y~fwCwxAq`5YkB%)WvI!;HXcPbN@KRp}o!{N77D-4AY!I)A*WU?a8ptj&nOn}Z~; z$NI{X7ii9f+v&!W!c+R+mJWafK+ew1H1U&| zPfrdVb!EB1VHHu>nI&}2#`vmB6=Lk?w8d94hzF2lC4(Wh{$qK{WSA`uUw}4IrY{Cn z>-P~(dGt@teq4q3eVilcs#rF|N zaS!G`OnVIvit*?|1BlM1>?H1bAVelr3A;vE0XQm zS)(*Cza-}W%-@)FOR^>)LUQHyXn(f5X8B$dYzk#w^?1|b&V~ZZ)GV8Lny1|La{Ovu z(TNg{YOUizHZF97OKKyfFL~6H-bPEgG=t;=KaqtMw`4|IZoFGkzYc_xMQ-Ok@c-3< zU`O9^D*V$aIv&A-7!H^c0N=~LpLx|g zAB~1@t`-l&LB6p89+J3DsWUIXdTe#D0z@qJQ=H=;h?Kk>qJwdrnRO8#fYNva>i#} zjhCm{bB}TzPzwJw-WIwwIFfPIdlI00-=+ZLEa@Hcok8OwBVC*C^1WncaUnaK*6@ap zKi9XHJ8k_2oTlUuOMkPl{&P2cb_-X=|B7j5>@4`Q2lJI@?##LL6c}}4g{jBfU0v6I z#f3J8GIkm3aSY>FOG$x#uZ7{Jx_-uzEaPy$%A%le(E=V2*Uk;>si{JiQ6r-M0(m+C zQhR(jSGI2aG1hPj4l(7{w3O5T9y2N}EgfLu%>Azv7Y}0D0LR_A{>y`*M963@$p$wb zt6FuT$98wZ7K%t*x=`NuP|0CmILm=LW+n&~#@FTDsV>xIcPM=MRMzWy_v$&BmZMq> zF<}m-&CZmh-z1mt?1O*m7#`o;6S&x}zZaV9%*@mdR*Z|svJ+y3nfzzozN)(Q1afBd zd(-yP*VGdahS?P!`44(v8a{SyK@y+N_+^r8Ln-J`#?}Y}97+fKCH$r>?!9}!NkIH! zBP#Ldi8USUy1f~gnrD+{&3MOooS3}j=MuwQYSToPNo#q^BeJ^|%2*>c@6tWD!QS4> zukb5pMRe02r!jAPXKuY&RlJ}ZE4r}(Sb%m4tarF*IOLx1@>YR&%)d{25Cllq7&{}3 zGJ|nI^}(J@MdRkH5|VdAcc(%%Hm7sr)K^n+Hiz)QlqNE0Z{1uGdLkB;_dgniZkn1} z?l6`!8TSNgE}M^p?vO%z6?7$X<3hK`{SsM5wuaX_B%IciLzk7UavQoqeNmc#PRuA| zDKYKG6fh#9tgP&1X>oBCE_9Ujc-I@vYM0JB*zi&cW(c{^G_u);Vab&X%y~?O8x#_E ze;nU^H!r|-F2Z(uOh~Cp4!E&2MIs#p<@Nk}i_PyYJr#i)-^o8iqtUS78|KD$o}Lqq zkuoh~{NM{Mj2aYGZ0n8-Svl=?E?qX{S9DaP(^o+PH0M!~wPlPc%-vDMqS3!{GF8q^ z%2I4cS3JOxN-R=(#FAo#O3D>KRu*+(5;$yr3=@<|CNc^*&m9t6CHqH)btDdVr|(DI zf*4_Vw}q9j{?HLTz0aDbXqSXDlD?-chnxOPe*AX4P{|=S7wTBZsz>h`QzYG!hYwvr zt>55NR|r`88L&J#W6yMadz8~Qm~LLJSCFK2qjz&5Xi8P3v~I(<7tl&RwTcW-_86+~ zp3Dgg*2T4{B<9Z5Y4vdR`eRcFKYf*G*W%6uZ2xMD6IX{y6@JQ3d_36i?rTN>%x-q6 z;AXkYwn4wNdsVu^JRF;3S7ME!D&0jtRr=K9*r{f@E^jRy6-CyLcqE?vXZa1+iA$H* ziDHw6%tuo7Y$^3rNL5dut6GbOE4Znt(xLvLvWPq$4%l#j6v-IK+H-8oNKIy!v&)Q>3-pPY!T{H1nu(#%BxLyt--R;f;Nk*kLNUJGIA{KkE_qk|4 zRIs;5Y}$yJV4i75{v7!8al5lYMnDx@fT&ld-!L;f?fPUK(4frgN7U+wWkE`cc8xJk zX-#M99{jj&t(3exQ;^Af##JyG*LC~$EAmfQM5XtgqBN>m?JOmXBgQ>eoh`}0b$=yp zfn58Q@c!vr`{UEapXa?uJI5hY0}L_=pFi$|05}fnv-@!F`{WO7Z)7qWq?4C+qMO(E zBid+#m=aa%3Y9c?0`Y=}NNCogFty@*z2re;UQMrhRy%R%(J0z14Q^1q1r`08q7=Wt z7qZBTDra#S5I6G@xELQH=o`|-Rfy`|SsNLle|Vcp-kG&!U`6CTSbOk{Wle^IJhvLF zR_Fdo)KFLsyCD}`=gIGA_4g+uM{Jl%@({eQg(-|`X>AQd#u6pp?tfEzhcbX28%8e( z8ygko6e(BW=IdNCgO!$jj>yx#iZK}<`#$*=$x>5}PQpZ(y|Q$3E7CKDtiqcc(P$7V z;V#syHNQ(S>oSwKho`A&BBeNi<5wD+;x~H|iiPbbtxu~(^w8S5yqGLWX`FgS_!X;~ zvt|Kivl)Du;&Sd$loChQXSuLrSZjxBZx{ImnJSf7n!_0)fecY7dsY2Z)GPr_tn*&w z3tfMFXMb6~YKns+b~n?0e|PNsEj`jwNxy)AfW*#iEo^?4qL`SNo2=4;)m-&Ge*d@< z!rFtj=U)sEpYnoB$WhbbKP2*1v03Brtx^hW@r|ObGe<@sZZEk-ozzQO(3JrV%oKCG zCH1eXiwlh11$b3>1u{t4b6B)r*n-$3mVawgGjZ*eDpM9RnWd;9T9`jM74+usLHoBB z4v;x=t)%$^SI#z7M!im5SK>XQc?*Km35KS9xe2M9*Lt*R-fLYD>kM%guP1^biF+*W z4qyDS{2sAjlKAE1ADHHyGHDb`K4vElh`1EkvM;4Z&lJoy_&HzpiiZtc;UlSxPZ<1Q zL8?n1LM#uaq_&d{rE|m`Q3=Pkxjv)Hux7UEbftV2ojd8p*S*`MYV?wO+iPJYsS&Nr zTn^Tx@h^#zl)Slj!DG)Qhv@pcovyy8XH(OT4I-1>M<1L!L`gWorYsv_Ue{8)dKV81 z#ps_!Yc-b@MOx)sJNv4`r~&jcTmq=0hA7O^?PX?9G-mBJI|c33?@Ad`PjVT!&Jx#Q zUOh)naaV?e4^k>l$yi_FH$Ii)cLDvt4!T?OQDZAvg*#BUKsqkJwtFxeChKjNcQZOB zCT2c9jN5Z_g~H6VtaFLokFPLh4qY=*soRj3chl5xfX+RgaZ~7*0{eyp^0=ao)n~Ti74LB;CK(=?KTj&Hk=8w33y)2M>Vd3GA2wW| zbVpQs?#ugE(JnrkCEP}SP}luyn$n|50yyqvpmT4)T5@^N$D4jz)kK<;q!BnSmF8qB zghJXsEdO4qUB!%Pv%Ff2A-aFB8HH=Unn^>bHqV`%q9SWA)AUhzp2G4j9aDk1Bt^Ip zcBT(Z8``y8e!_GNn;tiLeVnNjn@STsPvxr}IB&N#bJK%_s}?wKin(x)Q~P?tFUqF5FtT_AFwt zb%>BfKCehP`!+ZC`2r|8IdU_->?PK;Rzj;RKPLcu`|?Vt-HCTlSmGxK_dCL+RX86W z$KmTkeuW#gFJ2xdo=YPboK;}GBold;dTl7`*p<@nmoPVPeZhAh8Cc0iNJBHr59Lb- zkizt<9NKtMMG_3JwkJT_Q>t;$utWMLyd2@l$&^%%OzJ&}R;=^)8@sqM7$k5lR{{uY z3d!*V?R~pI($Q3e6PL6jq0T>Fi5I}>TqfMgIK`<(m@!y39{9{11Y}3bUpP(;GBY7g zT;pf948{1b?l@r%|5X@raUIxyvHH)sy9W-3Gf1JY+f$O0-TIaQ2@3uPk7pOXPRPbT z+p=7n-+yp$*x7PLVKiD6-!HQ&C58i&!zOVRuhc^49FF&l2lOVm+)q2nsSfcY*SI+o z21j=N%80!q3xOn@JJj!eFzyo@F<8yH<0$S<+*NZ#wI$JKn3@EhqC_4#orJ$jCHp1c z6?4zrn`OkaG3$Ss z7 z$RJMY`qy5;$6hPK zQqrQLvb#;ist}FiVoLe&(F(quKGyGwOTYRs_+EF#Ddx4BqQn=$vRn+K-JeEgs;DFu zsM@?Gcwu@k#}&j;r}3vHZl`7q+Rmkhqgd?!V%MMU+Q{91==b+_75k<)#|Ax{Ax)4v zYv~hNvq1!5$eVfickTB1`;#;ENM9b5!BavYU7i}{J{SSreDA}Ko+&aDrRPHc`7}1) ze`UJcS%|*#`ho{8zf`f#$dVaJsOp=&@9pc#;n!^@;>V;V=1sl7)%8rnaciizXUZlX zwrXBQji{L^dmr zEEH(#HFdD5aWx@}y?y1^Wck{DzX_u}*w$6ZS9wsOH;i`cdDJi6&=p<3#C_8ehfAjX z#;ILw_cOLWevB4k^l0uRs^AoF=N#fyePM5q!~c<$Pc3Wk+R$YIUq>84hXpvf1Wi7EOLIVU0J z1X^+AWEx)1SOe}bJMLNDlOmSP6w!l6nYso#l;pMJiz9py#0n7U^n}idzYKOR9bx%% z@mls53iYqPEU9V+Dw&mL86@fU`9w*hdGwm*jTF4T?m&_JR|0YM2<+{QYEOL2yT_a$ zQGqS&EZWqwJ|-XLOTph#F4DTP0<>H!!0HXovc9)xrF=0LMuyHEyk#1l#?c0uSsiJZ zMT+p!ToybYNrbpog|{YX%hW}W%#{pYWO-gF4*}l^U2i@9t#NH6?_eMs>#^6`m`-&M zHk=%8g*H!Nf7n=l7xOV_@$qpp-R3Mfc18lyUEc6~2ES!S0nJdV( zlPBbRAl7de$t4yWa1~I1jZ) z_sT+A%pD`F^CfUw3HoInghBn-GeO0=LX7e*%E~S@n0}#6si1tYRJP6WA++*fXW_FC zWIYFTtLR!PjX+bVzHHe%b@wFG z1l~mv79*xDkE<`>RZh70{#aeW+n^NM$>r?xYw9IIlxj;mQEh9AbGi0f3cIvl@XTw# zRsUpHo&d-@%jpVrKoQjUH#i_nm5Jj^cz)V{r-BDgF(Xutm?PKbDR5h=XUMV$;X@9Z zs@yaK;?NdzOzXShrN9$CnZ`%Ut4=p2@3?=T3B2WVwOL~D@+{rX2t@T5pQeWJ;}`H- z?gh=K1~m|%oGPGh6={AJ7U=2gTOE_-hBJ4fyHh6&*RqF=$}V@C9o^z$2EFL<-964v zFr=1gtDmc_sOXwJEc{@g*SB!sCru^|_0jJ_iL7c@blKK$QlAwyra@oy-8?UewWx=X5cEER;;~I#%}o>UMEyQXn8eOr9dGbbmL3m% zAH1{h4VU9KrU?GNH1QQTd6<0Ny_M^O*;Bs^#K%fRi4WmaL7%I0nR&_G852xkFOkRw zqO92fhOE!s{ANWxPn=8_l|E8@`dgFKv!_8Hn`IAzaW(BM)-(&TUm_4sm6j zO&Js+uo1j~%(N_8d3z`_OB-y>Di2TW%l+D$M}LU&Asw;!Q#1PKS^{P7K{ld&0bZ#` z`Ypqkj?IWDdA0eJC=Dl}T1fa+#a>Ikx?a&E&M}*j1c4qv`D>z_7*kG98yaD9d!j`e z9R%s$^Zo_9`(`-5Cm9KVTuPSgIo*ZWYH+zt+1F3Bz~rCbR2OQtIQ%YmV`q~vNH=sS zDvPD~(a_ye3t(P>J?Vmzh-Maa{HPXx8BA0?#x!^>D)(z9O-8DjmPEV}NDHKkqpdN9 zI|cf>`=F0bU2E2*BQ<;KY(E{!8scNbM>f~)2vp5_8L)rj9bbrDkC|3nQWx^t z+CcxXec6%7hhRUMNcAAAkqc1MxsXlUn6|Q5nGNL|`ofT&h$%sRuazs@$=8|&g(ItQ zt{=Pxs+|oBH1)kTv9?=OZPBSKkh_N9js3I4i?&$)cCbe;7*)< z#YXW&N2aFj%u2C3o1LQQeSR}7-Lje*GiiOXdA}xd>O&LAz2i+0^nBynF?Iu~QFh|I z+r8x>y}(Cc*j*9o?G}%#<^u;tH#Lc+0KWB7md9H|5Y*l&_rv;c%CVY zCPEdi0N1-zMbnZ^(|z|f(x|mxid9Q7Gd>gExN9Em;bDR8NeLA2W9D!!sbbaZb`DtP z7<1RvjF#B>99ls&vH{$KN~MM>G+`wSC3;D*RKXfI4i#olRenhmtZ8WMeCgp~zd;X) zqMDidU%kv8n?1sGDZm#6zB7KcUZ#Oj>%r?A@o24Jq_SK%dzI z;f~^neUW^9Qu?O)DBP$9)XrnkG<2M)>q?@^FUtE1L-ZYVu5()m7O%*H8=Nfopm@mG z4rbS#KZnnr)9)E2FtAJN6`pn`l4tp=!L)aT>-GXS;$Xaaq835Z+0Qy`uvpEC^A)bD zE85xDqFegV(MlmCj-u8xf{0f@yhDY*|0^~B`_}4WBSPNFJj8&{d03Ddaf&400k>QL zDRQf#5XdHpi~S%8JC))?oO{d~kPnt$AT`_=Zbi z@kWGf&^w)PYL;sc`tLOGba)8Nf27p4l4uLONh2~)D=AYYw4&F6Yv$v#-ymI;oNX})^_XI|JAFB-Rjvkxe**7+l|)*0 zS^Ekvw5K1G=rYQKUnJnizP<98Eswp5km7@!U^FcRcdnKf<+j^gE`uaRZ+cJ+FAs_g zm-x8POJoH^-40KtxM(aN1EJnJHzbT?1pyX6tA4~FNUHg zKqB5>^NSpYUYj2v1JH6U&(V zf@I<~qJKk1Of1adC&Qioj5OizB(lEUhv3zr#6nJS|5119FnGrGj;Ako2@WLIR>!Ae ze2Fj!m)!t&?3E*YvOFJV>`fq;_UoP5y?AQ0a-7z*ur1#dG10+8D1$>2jipMJRbH;u zGdeD&>Q~x#uE;2uY8t3hnIQuc2bJ1vwJ2`+wRMGIHRu-3kRK&-g*PfxITK@@-CsSO zaRC<;Ba4tHa&69v^eeY&^DupWck}KD_Udh@h^K$6$j!WrV2BJw@qBjE4$TwH7GvYn zB#;Z+&LDC9+_Mc5^)-Us->f+SWtBn&LYlWHWDy|gR>2&xUe6GUFKNc2q}k#$4`L)3 zK_V`>#-yQnQzoz6;lpKoFBSd+X`dvZkcE#vajXcg(>y~ zGU1S}o{zqFO>)08YHMr5T~6T6msp3cFa8kTxbk3Bi|;H3=Qw;Hp9y zA-;9Rq)t3h*KKQh3m8OHV=0sYyY~Tr>EWtedF4U0kBwBi>MIhAQ~#xE^t>3;yrV>e z>2>{o7(((`*RFrGNJ{Zf|BNMw-Ed<7fQKU~R)w}U>fb1k#Mw_k@@&vB)tOmtkW7In z(4WoAKOp^X|NRDfKYN8|U$xPQ`pW{&j-5#HY~^?S=MW)uEI;?P zqr$TgvYvs?i=*}qHV@vhE2+7%ruBd5+j+lVw#NP+oz7YsgaAsux2Iw3@4Hqjg(Z#O zwmJk>g(Rf!^knXuRbvWhNu6@OE||S04Uqo#Fg?!j*cw01@ZVUPaPySw(x(Vs3RrTa z6<=dfpCRfw#B=!G_yqJH6*;lg@(luK5lipiy}W*(*59JrzlwPO^Rxe92mGJ8Rl(dE`hV%cy7np11L>6<{4|R8E z{(szY|Il3cncLEJ=(G;xirULK?ShWqd+;Cr=D$;{uJo2J`_^Z+SMEC^P?rCG3?dWD z#<@#A(_QvLF~VXE(=i(sf$e`mC;yC%yRpmokEa>{#)E&3z%%+w{uvuq`sCUteq(A48eMW|3Y?ZtKa8l^rgKIF@EYKhC z0V3O8b0?$+HJleUv-Ja@7!)LX0>p~iC27w9gKg`&sV2bm$7%zx-@6yGF=3j2`|<_G z;xkQAHUGr{pbZC<<(7b#s=LJ)s^R6%7o!k4=Z@5|v9U*wSV&*z3KezZ#693}xTohH zfkOi@gaq!9R9C4mKaxZ;6-f0KM1~hR%D@RpquN4{JT^(gH?H>q%&j?yT2x>YOz&N5 zoKj!#Z&R%q-)oCYW(EP%Ofmol$pug%1^AMjpubgzX#zb@rBE1zSp6T6g}_%(j|)q{ z142Pj(GB60txy|1R@mO|^!~{{@I9}OfQ@g>5}jl#^yq%9xVn{7pG29vo12M(c6^ z_P=&q0VoD){2e44Bz-*8;=z@9*wxfYKz5GKk12z!ei<%HycT zB`bLO*|PwtC8TMA7~e5?)2l{DAnE7XSNHDcoJWYsn&0!(nScu~E`+S9zAd_2ur>}j z$9g<^Eh=}`A7H06eI-83H%y1NgaTxj>FIMjz?DfOuJ28bo#tmw*QDDQcgm)J*gSLX z@U<*k_LY<91@I`bB8|eDA#l~9k7_|10O=z;tWn4v{29+NVcl6 z7nv4r6FiZ4MX8F%RW^8}B04;*j{5aEp1tAutU+u}jIg5A!Gd*h8bps z70vtKkntSofIXXnb|*R>1=FUamt8Jt{Wmj(LdnH!mam!7ua KP4soUNB;$Il`Gx= literal 175337 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 z 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 From 3057237f9f2b70fbec6cbd7523abf8ae3178e0a5 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 16:08:38 +0100 Subject: [PATCH 64/68] refactor(iges): transducer imports & usage --- packages/iges/src/index.ts | 51 ++++++++++++++------------------------ 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/packages/iges/src/index.ts b/packages/iges/src/index.ts index 96155b3d12..ad47f45b24 100644 --- a/packages/iges/src/index.ts +++ b/packages/iges/src/index.ts @@ -2,19 +2,15 @@ import { defmulti } from "@thi.ng/defmulti"; import { float } from "@thi.ng/strings/float"; import { padLeft } from "@thi.ng/strings/pad-left"; import { padRight } from "@thi.ng/strings/pad-right"; -import { - comp, - iterator, - map, - mapcat, - mapIndexed, - partition, - push, - str, - transduce, - wordWrap, - wrap -} from "@thi.ng/transducers"; +import { comp } from "@thi.ng/transducers/func/comp"; +import { wrap } from "@thi.ng/transducers/iter/wrap"; +import { push } from "@thi.ng/transducers/rfn/push"; +import { transduce } from "@thi.ng/transducers/transduce"; +import { map } from "@thi.ng/transducers/xform/map"; +import { mapIndexed } from "@thi.ng/transducers/xform/map-indexed"; +import { mapcat } from "@thi.ng/transducers/xform/mapcat"; +import { partition } from "@thi.ng/transducers/xform/partition"; +import { wordWrap } from "@thi.ng/transducers/xform/word-wrap"; import { DEFAULT_GLOBALS, DictEntry, @@ -86,11 +82,7 @@ const formatLine = (body: string, type: string, i: number) => `${$BODY(body)}${type}${$SEQ(i + 1)}`; const formatStart = (doc: IGESDocument) => { - const res = transduce( - mapIndexed((i, x: string) => formatLine(x, "S", i)), - push(), - doc.start - ); + const res = [...mapIndexed((i, x: string) => formatLine(x, "S", i), doc.start)]; doc.offsets.S += res.length; return res; }; @@ -140,15 +132,12 @@ const formatTerminate = (doc: IGESDocument) => ); const formatStatus = (s: EntityStatus) => - transduce( - map($Z2), - str(""), - [ - s.blank || 0, - s.subord || 0, - s.usage || 0, - s.hierarchy || 0 - ]); + [ + s.blank || 0, + s.subord || 0, + s.usage || 0, + s.hierarchy || 0 + ].map($Z2).join(""); const formatDictEntry = (e: DictEntry) => transduce( @@ -222,12 +211,10 @@ export const addPolyline2d = (doc: IGESDocument, pts: ArrayLike[], form [1, Type.INT], [pts.length + (form === PolylineMode.CLOSED ? 1 : 0), Type.INT], [0, Type.FLOAT], - ...iterator( - mapcat( - ([x, y]) => [[x, Type.FLOAT], [y, Type.FLOAT]] - ), + ...mapcat( + ([x, y]) => [[x, Type.FLOAT], [y, Type.FLOAT]], form === PolylineMode.CLOSED ? - wrap(pts, 1, false, true) : + wrap(pts, 1, false, true) : pts ) ], From 389aff82f5ddcb43cc334f2d113953a508746fd1 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 17:30:20 +0100 Subject: [PATCH 65/68] build: update yarn.lock --- yarn.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/yarn.lock b/yarn.lock index e238940229..37ca9107df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -230,8 +230,8 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.5.tgz#8a4accfc403c124a0bafe8a9fc61a05ec1032073" "@types/node@*", "@types/node@^10.5.5": - version "10.7.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.7.1.tgz#b704d7c259aa40ee052eec678758a68d07132a2e" + version "10.9.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.9.1.tgz#06f002136fbcf51e730995149050bb3c45ee54e6" "@types/shelljs@0.7.8": version "0.7.8" @@ -405,8 +405,8 @@ acorn-dynamic-import@^3.0.0: acorn "^5.0.0" acorn@^5.0.0, acorn@^5.6.2: - version "5.7.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + version "5.7.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.2.tgz#91fa871883485d06708800318404e72bfb26dcc5" add-stream@^1.0.0: version "1.0.0" @@ -2571,8 +2571,8 @@ inquirer@^3.2.2: through "^2.3.6" inquirer@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.1.0.tgz#8f65c7b31c498285f4ddf3b742ad8c487892040b" + version "6.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" @@ -2580,7 +2580,7 @@ inquirer@^6.0.0: cli-width "^2.0.0" external-editor "^3.0.0" figures "^2.0.0" - lodash "^4.3.0" + lodash "^4.17.10" mute-stream "0.0.7" run-async "^2.2.0" rxjs "^6.1.0" From 7a5be2132e8afa5ad27c8d43efc05c37ed46faef Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 18:31:33 +0100 Subject: [PATCH 66/68] fix(transducers): arg handling in rename() --- packages/transducers/src/xform/rename.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/transducers/src/xform/rename.ts b/packages/transducers/src/xform/rename.ts index c5adfbb8ab..af52156a98 100644 --- a/packages/transducers/src/xform/rename.ts +++ b/packages/transducers/src/xform/rename.ts @@ -10,16 +10,15 @@ import { filter } from "./filter"; import { map } from "./map"; export function rename(kmap: IObjectOf | Array, rfn?: Reducer): Transducer; -export function rename(kmap: IObjectOf | Array, src: Iterable): IterableIterator; export function rename(kmap: IObjectOf | Array, rfn: Reducer, src: Iterable): IterableIterator; export function rename(...args: any[]): any { - const iter = $iter(rename, args); + const iter = args.length > 2 && $iter(rename, args); if (iter) { return iter; } - let kmap; - if (isArray(args[0])) { - kmap = args[0].reduce((acc, k, i) => (acc[k] = i, acc), {}); + let kmap = args[0]; + if (isArray(kmap)) { + kmap = kmap.reduce((acc, k, i) => (acc[k] = i, acc), {}); } if (args[1]) { const ks = Object.keys(kmap); From cff9d18a7b595fe06631f484782ab883cad93ec9 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 18:31:53 +0100 Subject: [PATCH 67/68] docs(transducers): update readme examples --- packages/transducers/README.md | 100 ++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/packages/transducers/README.md b/packages/transducers/README.md index 08f793b906..d82510fc60 100644 --- a/packages/transducers/README.md +++ b/packages/transducers/README.md @@ -123,8 +123,8 @@ import { range } from "@thi.ng/transducers/iter/range"; // compose transducer xform = tx.comp( tx.filter((x) => (x & 1) > 0), // odd numbers only - tx.distinct(), // distinct numbers only - tx.map((x) => x * 3) // times 3 + tx.distinct(), // distinct numbers only + tx.map((x) => x * 3) // times 3 ); // collect into array (tx.push) @@ -142,8 +142,8 @@ tx.transduce(xform, tx.conj(), [1, 2, 3, 4, 5, 4, 3, 2, 1]); // alternatively provide an input iterable and // use xform as transforming iterator -[...tx.filter((x) => /[A-Z]/.test(x), "Hello World!")].join("") -// "HW" +[...tx.filter((x) => /[A-Z]/.test(x), "Hello World!")] +// ["H", "W"] // single step execution // returns undefined if transducer returned no result for this input @@ -160,24 +160,23 @@ f = tx.step(take) ### Fuzzy search ```ts -[...tx.iterator(tx.filterFuzzy("ho"), ["hello", "hallo", "hey", "heyoka"])] +[...tx.filterFuzzy("ho", ["hello", "hallo", "hey", "heyoka"])] // ["hello", "hallo", "heyoka"] -[...tx.iterator(tx.filterFuzzy("hlo"), ["hello", "hallo", "hey", "heyoka"])] +[...tx.filterFuzzy("hlo", ["hello", "hallo", "hey", "heyoka"])] // ["hello", "hallo"] // works with any array-like values & supports custom key extractors -[...tx.iterator( - tx.filterFuzzy([1, 3], (x) => x.tags), +[...tx.filterFuzzy( + [1, 3], + { key: (x) => x.tags }, [ { tags: [1, 2, 3] }, - { tags: [1, 3, 4] }, + { tags: [2, 3, 4] }, { tags: [4, 5, 6] }, { tags: [1, 3, 6] } ] )] -// [ { tags: [ 1, 2, 3 ] }, -// { tags: [ 1, 3, 4 ] }, -// { tags: [ 1, 3, 6 ] } ] +// [ { tags: [ 1, 2, 3 ] }, { tags: [ 1, 3, 6 ] } ] ``` ### Histogram generation & result grouping @@ -192,16 +191,20 @@ tx.transduce(tx.map(x => x.toUpperCase()), tx.frequencies(), "hello world") tx.reduce(tx.frequencies(), [1, 1, 1, 2, 3, 4, 4]) // Map { 1 => 3, 2 => 1, 3 => 1, 4 => 2 } +// direct reduction if input is given +tx.frequencies([1, 1, 1, 2, 3, 4, 4]) +// Map { 1 => 3, 2 => 1, 3 => 1, 4 => 2 } + // with optional key function, here to bin by word length -tx.reduce( - tx.frequencies(x => x.length), +tx.frequencies( + x => x.length, "my camel is collapsing and needs some water".split(" ") ) // Map { 2 => 2, 5 => 3, 10 => 1, 3 => 1, 4 => 1 } -// actual grouping -tx.reduce( - tx.groupByMap(x => x.length), +// actual grouping (here: by word length) +tx.groupByMap( + { key: x => x.length }, "my camel is collapsing and needs some water".split(" ") ) // Map { @@ -217,7 +220,7 @@ tx.reduce( ```ts // extract only items for given page id & page length -[...tx.iterator(tx.page(0, 5), tx.range(12))] +[...tx.page(0, 5, tx.range(12))] // [ 0, 1, 2, 3, 4 ] // when composing with other transducers @@ -230,7 +233,8 @@ tx.reduce( [...tx.iterator(tx.comp(tx.page(2, 5), tx.padLast(5, "n/a")), tx.range(12))] // [ 10, 11, 'n/a', 'n/a', 'n/a' ] -[...tx.iterator(tx.page(3, 5), rtx.ange(12))] +// no values produced for invalid pages +[...tx.page(3, 5, tx.range(12))] // [] ``` @@ -277,15 +281,12 @@ tx.transduce( ), tx.push(), [1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10] -); +) // [ 2.6, 3.4, 4, 4.6, 5.4, 6.2, 6.8, 7.6, 8.4 ] // this combined transducer is also directly // available as: `tx.movingAverage(n)` -tx.transduce( - tx.movingAverage(5), - [1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10] -); +[...tx.movingAverage(5, [1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 8, 9, 10])] // [ 2.6, 3.4, 4, 4.6, 5.4, 6.2, 6.8, 7.6, 8.4 ] ``` @@ -293,13 +294,13 @@ tx.transduce( ```ts // function to test -fn = () => { for(i=0; i<1e6; i++) let x =Math.cos(i); return x; }; +fn = () => { let x; for(i=0; i<1e6; i++) { x = Math.cos(i); } return x; }; // compute the mean of 100 runs tx.transduce( - tx.comp(tx.benchmark(), tx.take(100)), + tx.benchmark(), tx.mean(), - tx.repeatedly(fn) + tx.repeatedly(fn, 100) ); // 1.93 (milliseconds) ``` @@ -310,15 +311,14 @@ tx.transduce( // alternatively, use tx.sideEffect() for any side fx tx.transduce( tx.comp( - tx.inspect("orig"), + tx.trace("orig"), tx.map(x => x + 1), - tx.inspect("mapped"), + tx.trace("mapped"), tx.filter(x => (x & 1) > 0) ), tx.push(), [1, 2, 3, 4] ); - // orig 1 // mapped 2 // orig 2 @@ -342,9 +342,10 @@ here](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/src/xf // 2 or 3 items: `[name, size, transform?]`. If `transform` is given, it will // be used to produce the final value for this field. In the example below, // it is used to unwrap the ID field values, e.g. from `[0] => 0` -[...tx.iterator( - tx.struct([["id", 1, (id) => id[0]], ["pos", 2], ["vel", 2], ["color", 4]]), - [0, 100, 200, -1, 0, 1, 0.5, 0, 1, 1, 0, 0, 5, 4, 0, 0, 1, 1]) ] +[...tx.struct( + [["id", 1, (id) => id[0]], ["pos", 2], ["vel", 2], ["color", 4]], + [0, 100, 200, -1, 0, 1, 0.5, 0, 1, 1, 0, 0, 5, 4, 0, 0, 1, 1] +)] // [ { color: [ 1, 0.5, 0, 1 ], // vel: [ -1, 0 ], // pos: [ 100, 200 ], @@ -401,16 +402,16 @@ xform = tx.comp( tx.scan(tx.count()), tx.map(x => [...tx.repeat(x,x)]), tx.scan(tx.pushCopy()) -); +) -tx.transduce(xform, tx.push(), [1, 1, 1, 1]); +[...tx.iterator(xform, [1, 1, 1, 1])] // [ [ [ 1 ] ], // [ [ 1 ], [ 2, 2 ] ], // [ [ 1 ], [ 2, 2 ], [ 3, 3, 3 ] ], // [ [ 1 ], [ 2, 2 ], [ 3, 3, 3 ], [ 4, 4, 4, 4 ] ] ] // more simple & similar to previous, but without the 2nd xform step -tx.transduce(tx.comp(tx.scan(tx.count), tx.scan(tx.pushCopy)), tx.push(), [1,1,1,1]) +tx.transduce(tx.comp(tx.scan(tx.count()), tx.scan(tx.pushCopy())), tx.push(), [1,1,1,1]) // [ [ 1 ], [ 1, 2 ], [ 1, 2, 3 ], [ 1, 2, 3, 4 ] ] ``` @@ -423,7 +424,7 @@ here](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/src/xf ```ts src = [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 33, 48, 49, 50, 51, 126, 122, 121, 120] -[...iterator(hexDump(8, 0x400), src)] +[...tx.iterator(tx.hexDump({ cols: 8, address: 0x400 }), src)] // [ '00000400 | 41 42 43 44 45 46 47 48 | ABCDEFGH', // '00000408 | 49 4a 21 30 31 32 33 7e | IJ!0123~', // '00000410 | 7a 79 78 00 00 00 00 00 | zyx.....' ] @@ -432,7 +433,7 @@ src = [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 33, 48, 49, 50, 51, 126, 122, 121 ### Bitstream ```ts -[...tx.iterator(tx.bits(8), [ 0xf0, 0xaa ])] +[...tx.bits(8, [0xf0, 0xaa])] // [ 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0 ] [...tx.iterator( @@ -455,9 +456,12 @@ src = [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 33, 48, 49, 50, 51, 126, 122, 121 ### Base64 & UTF-8 en/decoding +Unlike JS default `btoa()` / `atob()` functions which operate on +strings, these transducers convert byte values to base64 and back. + ```ts -// add offset (0x80) to allow negative values to be encoded -// (URL safe result can be produced via opt arg to `base64Encode`) +// here we first add an offset (0x80) to allow negative values to be encoded +// (URL safe results can be produced via opt arg to `base64Encode`) enc = tx.transduce( tx.comp( tx.map(x => x + 0x80), @@ -481,18 +485,18 @@ enc = tx.transduce( buf = tx.transduce( tx.comp(tx.utf8Encode(), tx.base64Encode()), tx.str(), - "beer (🍺) or hot beverage (☕︎)" + "beer (🍺) or hot beverage (☕️)" ); // "YmVlciAo8J+Nuikgb3IgaG90IGJldmVyYWdlICjimJXvuI4p" tx.transduce(tx.comp(tx.base64Decode(), tx.utf8Decode()), tx.str(), buf) -// "beer (🍺) or hot beverage (☕︎)" +// "beer (🍺) or hot beverage (☕️)" ``` ### Weighted random choices ```ts -tx.transduce(tx.take(10), tx.push(), tx.choices("abcd", [1, 0.5, 0.25, 0.125])) +[...tx.take(10, tx.choices("abcd", [1, 0.5, 0.25, 0.125]))] // [ 'a', 'a', 'b', 'a', 'a', 'b', 'a', 'c', 'd', 'b' ] tx.transduce(tx.take(1000), tx.frequencies(), tx.choices("abcd", [1, 0.5, 0.25, 0.125])) @@ -670,8 +674,9 @@ itself. Returns nothing. ### Transducers -All of these functions can be used and composed as transducers. Most also -accept an input iterable and then directly yield a transforming iterator, e.g. +All of the following functions can be used and composed as transducers. +With a few exceptions, most also accept an input iterable and then +directly yield a transforming iterator, e.g. ```ts // as transducer @@ -751,7 +756,6 @@ tx.transduce(tx.map((x) => x*10), tx.push(), tx.range(4)) ### Generators / Iterators -- [asIterable](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/asIterable.ts) - [choices](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/choices.ts) - [concat](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/concat.ts) - [cycle](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/iter/cycle.ts) @@ -776,6 +780,10 @@ tx.transduce(tx.map((x) => x*10), tx.push(), tx.range(4)) ### Reducers +As with transducer functions, reducer functions can also given an +optional input iterable. If done so, the function will consume the input +and return a reduced result (as if it would be called via `reduce()`). + - [add](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/add) - [assocMap](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/assoc-map) - [assocObj](https://github.com/thi-ng/umbrella/tree/master/packages/transducers/rfn/assoc-obj) From 1c92f223201e78da589653771c40017aed582142 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 18:38:06 +0100 Subject: [PATCH 68/68] Publish - @thi.ng/api@4.1.0 - @thi.ng/associative@0.6.0 - @thi.ng/atom@1.4.7 - @thi.ng/cache@0.2.16 - @thi.ng/compose@0.1.0 - @thi.ng/csp@0.3.56 - @thi.ng/dcons@1.1.0 - @thi.ng/defmulti@0.3.8 - @thi.ng/dgraph@0.2.12 - @thi.ng/diff@1.0.22 - @thi.ng/dot@0.1.11 - @thi.ng/hdom-components@2.1.12 - @thi.ng/hdom@3.0.33 - @thi.ng/heaps@0.2.16 - @thi.ng/hiccup-css@0.2.15 - @thi.ng/hiccup-svg@1.0.10 - @thi.ng/hiccup@2.0.10 - @thi.ng/iges@0.2.5 - @thi.ng/interceptors@1.8.10 - @thi.ng/iterators@4.1.21 - @thi.ng/memoize@0.1.1 - @thi.ng/pointfree-lang@0.2.18 - @thi.ng/pointfree@0.8.7 - @thi.ng/range-coder@0.1.5 - @thi.ng/resolve-map@3.0.8 - @thi.ng/rle-pack@1.0.0 - @thi.ng/router@0.1.21 - @thi.ng/rstream-csp@0.1.97 - @thi.ng/rstream-dot@0.2.36 - @thi.ng/rstream-gestures@0.4.17 - @thi.ng/rstream-graph@2.1.21 - @thi.ng/rstream-log@1.0.48 - @thi.ng/rstream-query@0.3.35 - @thi.ng/rstream@1.11.3 - @thi.ng/sax@0.3.14 - @thi.ng/strings@0.3.0 - @thi.ng/transducers-fsm@0.2.13 - @thi.ng/transducers-hdom@0.1.3 - @thi.ng/transducers-stats@0.4.0 - @thi.ng/transducers@2.0.0 - @thi.ng/vectors@0.2.1 --- packages/api/CHANGELOG.md | 12 ++++++ packages/api/package.json | 2 +- packages/associative/CHANGELOG.md | 11 ++++++ packages/associative/package.json | 10 ++--- packages/atom/CHANGELOG.md | 8 ++++ packages/atom/package.json | 4 +- packages/cache/CHANGELOG.md | 8 ++++ packages/cache/package.json | 10 ++--- packages/compose/CHANGELOG.md | 12 ++++++ packages/compose/package.json | 6 +-- packages/csp/CHANGELOG.md | 8 ++++ packages/csp/package.json | 8 ++-- packages/dcons/CHANGELOG.md | 11 ++++++ packages/dcons/package.json | 8 ++-- packages/defmulti/CHANGELOG.md | 8 ++++ packages/defmulti/package.json | 4 +- packages/dgraph/CHANGELOG.md | 8 ++++ packages/dgraph/package.json | 10 ++--- packages/diff/CHANGELOG.md | 8 ++++ packages/diff/package.json | 4 +- packages/dot/CHANGELOG.md | 8 ++++ packages/dot/package.json | 4 +- packages/hdom-components/CHANGELOG.md | 8 ++++ packages/hdom-components/package.json | 8 ++-- packages/hdom/CHANGELOG.md | 8 ++++ packages/hdom/package.json | 12 +++--- packages/heaps/CHANGELOG.md | 8 ++++ packages/heaps/package.json | 4 +- packages/hiccup-css/CHANGELOG.md | 8 ++++ packages/hiccup-css/package.json | 6 +-- packages/hiccup-svg/CHANGELOG.md | 8 ++++ packages/hiccup-svg/package.json | 4 +- packages/hiccup/CHANGELOG.md | 8 ++++ packages/hiccup/package.json | 4 +- packages/iges/CHANGELOG.md | 11 ++++++ packages/iges/package.json | 10 ++--- packages/interceptors/CHANGELOG.md | 8 ++++ packages/interceptors/package.json | 6 +-- packages/iterators/CHANGELOG.md | 8 ++++ packages/iterators/package.json | 6 +-- packages/memoize/CHANGELOG.md | 8 ++++ packages/memoize/package.json | 6 +-- packages/pointfree-lang/CHANGELOG.md | 8 ++++ packages/pointfree-lang/package.json | 6 +-- packages/pointfree/CHANGELOG.md | 8 ++++ packages/pointfree/package.json | 4 +- packages/range-coder/CHANGELOG.md | 8 ++++ packages/range-coder/package.json | 4 +- packages/resolve-map/CHANGELOG.md | 12 +++++- packages/resolve-map/package.json | 2 +- packages/rle-pack/CHANGELOG.md | 24 ++++++++++++ packages/rle-pack/package.json | 4 +- packages/router/CHANGELOG.md | 8 ++++ packages/router/package.json | 4 +- packages/rstream-csp/CHANGELOG.md | 8 ++++ packages/rstream-csp/package.json | 6 +-- packages/rstream-dot/CHANGELOG.md | 8 ++++ packages/rstream-dot/package.json | 4 +- packages/rstream-gestures/CHANGELOG.md | 8 ++++ packages/rstream-gestures/package.json | 8 ++-- packages/rstream-graph/CHANGELOG.md | 8 ++++ packages/rstream-graph/package.json | 10 ++--- packages/rstream-log/CHANGELOG.md | 8 ++++ packages/rstream-log/package.json | 8 ++-- packages/rstream-query/CHANGELOG.md | 8 ++++ packages/rstream-query/package.json | 12 +++--- packages/rstream/CHANGELOG.md | 8 ++++ packages/rstream/package.json | 10 ++--- packages/sax/CHANGELOG.md | 8 ++++ packages/sax/package.json | 8 ++-- packages/strings/CHANGELOG.md | 17 +++++++++ packages/strings/package.json | 4 +- packages/transducers-fsm/CHANGELOG.md | 8 ++++ packages/transducers-fsm/package.json | 6 +-- packages/transducers-hdom/CHANGELOG.md | 8 ++++ packages/transducers-hdom/package.json | 6 +-- packages/transducers-stats/CHANGELOG.md | 11 ++++++ packages/transducers-stats/package.json | 6 +-- packages/transducers/CHANGELOG.md | 51 +++++++++++++++++++++++++ packages/transducers/package.json | 8 ++-- packages/vectors/CHANGELOG.md | 8 ++++ packages/vectors/package.json | 4 +- 82 files changed, 548 insertions(+), 132 deletions(-) create mode 100644 packages/compose/CHANGELOG.md diff --git a/packages/api/CHANGELOG.md b/packages/api/CHANGELOG.md index ead88af2e7..0ef3c1bc37 100644 --- a/packages/api/CHANGELOG.md +++ b/packages/api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [4.1.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/api@4.0.6...@thi.ng/api@4.1.0) (2018-08-24) + + +### Features + +* **api:** add new/move type aliases into api.ts ([cf30ba2](https://github.com/thi-ng/umbrella/commit/cf30ba2)) +* **api:** add NumericArray and TypedArray types ([519394b](https://github.com/thi-ng/umbrella/commit/519394b)) + + + + ## [4.0.6](https://github.com/thi-ng/umbrella/compare/@thi.ng/api@4.0.5...@thi.ng/api@4.0.6) (2018-08-01) diff --git a/packages/api/package.json b/packages/api/package.json index 024abcf8d6..88b79e7925 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/api", - "version": "4.0.6", + "version": "4.1.0", "description": "Common, generic types & interfaces for thi.ng projects", "main": "./index.js", "typings": "./index.d.ts", diff --git a/packages/associative/CHANGELOG.md b/packages/associative/CHANGELOG.md index 6e45252bf5..926a15260d 100644 --- a/packages/associative/CHANGELOG.md +++ b/packages/associative/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [0.6.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/associative@0.5.11...@thi.ng/associative@0.6.0) (2018-08-24) + + +### Features + +* **associative:** add IReducible impls for SortedMap & SortedSet ([f14f7ce](https://github.com/thi-ng/umbrella/commit/f14f7ce)) + + + + ## [0.5.11](https://github.com/thi-ng/umbrella/compare/@thi.ng/associative@0.5.10...@thi.ng/associative@0.5.11) (2018-08-01) diff --git a/packages/associative/package.json b/packages/associative/package.json index ac851d44f0..cad40e2e6f 100644 --- a/packages/associative/package.json +++ b/packages/associative/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/associative", - "version": "0.5.11", + "version": "0.6.0", "description": "Alternative Set & Map data type implementations with customizable equality semantics & supporting operations", "main": "./index.js", "typings": "./index.d.ts", @@ -28,13 +28,13 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", "@thi.ng/compare": "^0.1.6", - "@thi.ng/dcons": "^1.0.7", + "@thi.ng/dcons": "^1.1.0", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "data structures", @@ -54,4 +54,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/packages/atom/CHANGELOG.md b/packages/atom/CHANGELOG.md index 7b8702dfd4..5f933d0779 100644 --- a/packages/atom/CHANGELOG.md +++ b/packages/atom/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.4.7](https://github.com/thi-ng/umbrella/compare/@thi.ng/atom@1.4.6...@thi.ng/atom@1.4.7) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/atom + ## [1.4.6](https://github.com/thi-ng/umbrella/compare/@thi.ng/atom@1.4.5...@thi.ng/atom@1.4.6) (2018-08-01) diff --git a/packages/atom/package.json b/packages/atom/package.json index fbaf257937..38788878d4 100644 --- a/packages/atom/package.json +++ b/packages/atom/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/atom", - "version": "1.4.6", + "version": "1.4.7", "description": "Mutable wrapper for immutable values", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", diff --git a/packages/cache/CHANGELOG.md b/packages/cache/CHANGELOG.md index 6731e904cf..c6f5008399 100644 --- a/packages/cache/CHANGELOG.md +++ b/packages/cache/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.16](https://github.com/thi-ng/umbrella/compare/@thi.ng/cache@0.2.15...@thi.ng/cache@0.2.16) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/cache + ## [0.2.15](https://github.com/thi-ng/umbrella/compare/@thi.ng/cache@0.2.14...@thi.ng/cache@0.2.15) (2018-08-01) diff --git a/packages/cache/package.json b/packages/cache/package.json index 16f30f4c54..1c44a077f0 100644 --- a/packages/cache/package.json +++ b/packages/cache/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/cache", - "version": "0.2.15", + "version": "0.2.16", "description": "In-memory cache implementations with ES6 Map-like API and different eviction strategies", "main": "./index.js", "typings": "./index.d.ts", @@ -28,9 +28,9 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", - "@thi.ng/dcons": "^1.0.7", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/api": "^4.1.0", + "@thi.ng/dcons": "^1.1.0", + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "cache", @@ -46,4 +46,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/packages/compose/CHANGELOG.md b/packages/compose/CHANGELOG.md new file mode 100644 index 0000000000..f99a8b6b78 --- /dev/null +++ b/packages/compose/CHANGELOG.md @@ -0,0 +1,12 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + + +# 0.1.0 (2018-08-24) + + +### Features + +* **compose:** extract comp() & juxt() to new [@thi](https://github.com/thi).ng/compose package ([ca0a04e](https://github.com/thi-ng/umbrella/commit/ca0a04e)) diff --git a/packages/compose/package.json b/packages/compose/package.json index 34ac7e97e2..abaa8daa6f 100644 --- a/packages/compose/package.json +++ b/packages/compose/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/compose", - "version": "0.0.1", + "version": "0.1.0", "description": "TODO", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/errors": "^0.1.6" }, "keywords": [ @@ -40,4 +40,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/packages/csp/CHANGELOG.md b/packages/csp/CHANGELOG.md index 174cf47b51..ca122ed170 100644 --- a/packages/csp/CHANGELOG.md +++ b/packages/csp/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.3.56](https://github.com/thi-ng/umbrella/compare/@thi.ng/csp@0.3.55...@thi.ng/csp@0.3.56) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/csp + ## [0.3.55](https://github.com/thi-ng/umbrella/compare/@thi.ng/csp@0.3.54...@thi.ng/csp@0.3.55) (2018-08-08) diff --git a/packages/csp/package.json b/packages/csp/package.json index 0c5ca6b148..8424e473ec 100644 --- a/packages/csp/package.json +++ b/packages/csp/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/csp", - "version": "0.3.55", + "version": "0.3.56", "description": "ES6 promise based CSP implementation", "main": "./index.js", "typings": "./index.d.ts", @@ -32,11 +32,11 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", - "@thi.ng/dcons": "^1.0.7", + "@thi.ng/dcons": "^1.1.0", "@thi.ng/errors": "^0.1.6", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "async", diff --git a/packages/dcons/CHANGELOG.md b/packages/dcons/CHANGELOG.md index 8e18faf440..ba6a2db6b2 100644 --- a/packages/dcons/CHANGELOG.md +++ b/packages/dcons/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [1.1.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/dcons@1.0.7...@thi.ng/dcons@1.1.0) (2018-08-24) + + +### Features + +* **dcons:** add IReducible impl, update deps & imports ([1280cfd](https://github.com/thi-ng/umbrella/commit/1280cfd)) + + + + ## [1.0.7](https://github.com/thi-ng/umbrella/compare/@thi.ng/dcons@1.0.6...@thi.ng/dcons@1.0.7) (2018-08-01) diff --git a/packages/dcons/package.json b/packages/dcons/package.json index 3b226ed38d..8164a3bee9 100644 --- a/packages/dcons/package.json +++ b/packages/dcons/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/dcons", - "version": "1.0.7", + "version": "1.1.0", "description": "Comprehensive doubly linked list structure w/ iterator support", "main": "./index.js", "typings": "./index.d.ts", @@ -28,12 +28,12 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", "@thi.ng/compare": "^0.1.6", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "datastructure", @@ -49,4 +49,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/packages/defmulti/CHANGELOG.md b/packages/defmulti/CHANGELOG.md index 46a627d3e5..68066adba4 100644 --- a/packages/defmulti/CHANGELOG.md +++ b/packages/defmulti/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.3.8](https://github.com/thi-ng/umbrella/compare/@thi.ng/defmulti@0.3.7...@thi.ng/defmulti@0.3.8) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/defmulti + ## [0.3.7](https://github.com/thi-ng/umbrella/compare/@thi.ng/defmulti@0.3.6...@thi.ng/defmulti@0.3.7) (2018-08-01) diff --git a/packages/defmulti/package.json b/packages/defmulti/package.json index b94ba10092..14a128b053 100644 --- a/packages/defmulti/package.json +++ b/packages/defmulti/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/defmulti", - "version": "0.3.7", + "version": "0.3.8", "description": "Dynamically extensible multiple dispatch via user supplied dispatch function.", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/errors": "^0.1.6" }, "keywords": [ diff --git a/packages/dgraph/CHANGELOG.md b/packages/dgraph/CHANGELOG.md index 659af61fec..cc7140eaae 100644 --- a/packages/dgraph/CHANGELOG.md +++ b/packages/dgraph/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.12](https://github.com/thi-ng/umbrella/compare/@thi.ng/dgraph@0.2.11...@thi.ng/dgraph@0.2.12) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/dgraph + ## [0.2.11](https://github.com/thi-ng/umbrella/compare/@thi.ng/dgraph@0.2.10...@thi.ng/dgraph@0.2.11) (2018-08-01) diff --git a/packages/dgraph/package.json b/packages/dgraph/package.json index e5cf2eb535..33ee783dd8 100644 --- a/packages/dgraph/package.json +++ b/packages/dgraph/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/dgraph", - "version": "0.2.11", + "version": "0.2.12", "description": "Type-agnostic directed acyclic graph (DAG) & graph operations", "main": "./index.js", "typings": "./index.d.ts", @@ -28,11 +28,11 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", - "@thi.ng/associative": "^0.5.11", + "@thi.ng/api": "^4.1.0", + "@thi.ng/associative": "^0.6.0", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "data structure", @@ -45,4 +45,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/packages/diff/CHANGELOG.md b/packages/diff/CHANGELOG.md index 30f7d88f22..aabd51d074 100644 --- a/packages/diff/CHANGELOG.md +++ b/packages/diff/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.0.22](https://github.com/thi-ng/umbrella/compare/@thi.ng/diff@1.0.21...@thi.ng/diff@1.0.22) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/diff + ## [1.0.21](https://github.com/thi-ng/umbrella/compare/@thi.ng/diff@1.0.20...@thi.ng/diff@1.0.21) (2018-08-01) diff --git a/packages/diff/package.json b/packages/diff/package.json index 1661e2bcc3..c682e9cc24 100644 --- a/packages/diff/package.json +++ b/packages/diff/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/diff", - "version": "1.0.21", + "version": "1.0.22", "description": "Array & object Diff", "main": "./index.js", "typings": "./index.d.ts", @@ -26,7 +26,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/equiv": "^0.1.7" }, "keywords": [ diff --git a/packages/dot/CHANGELOG.md b/packages/dot/CHANGELOG.md index d8d35c6599..25ae448527 100644 --- a/packages/dot/CHANGELOG.md +++ b/packages/dot/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.11](https://github.com/thi-ng/umbrella/compare/@thi.ng/dot@0.1.10...@thi.ng/dot@0.1.11) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/dot + ## [0.1.10](https://github.com/thi-ng/umbrella/compare/@thi.ng/dot@0.1.9...@thi.ng/dot@0.1.10) (2018-08-01) diff --git a/packages/dot/package.json b/packages/dot/package.json index 790c4e0a68..1e957174df 100644 --- a/packages/dot/package.json +++ b/packages/dot/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/dot", - "version": "0.1.10", + "version": "0.1.11", "description": "Graphviz DOM abstraction as vanilla JS objects & serialization to DOT format", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7" }, "keywords": [ diff --git a/packages/hdom-components/CHANGELOG.md b/packages/hdom-components/CHANGELOG.md index e2f773110d..85010d8eb1 100644 --- a/packages/hdom-components/CHANGELOG.md +++ b/packages/hdom-components/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [2.1.12](https://github.com/thi-ng/umbrella/compare/@thi.ng/hdom-components@2.1.11...@thi.ng/hdom-components@2.1.12) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/hdom-components + ## [2.1.11](https://github.com/thi-ng/umbrella/compare/@thi.ng/hdom-components@2.1.10...@thi.ng/hdom-components@2.1.11) (2018-08-01) diff --git a/packages/hdom-components/package.json b/packages/hdom-components/package.json index 56d2f53d5a..6953e85b2e 100644 --- a/packages/hdom-components/package.json +++ b/packages/hdom-components/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/hdom-components", - "version": "2.1.11", + "version": "2.1.12", "description": "Raw, skinnable UI & SVG components for @thi.ng/hdom", "main": "./index.js", "typings": "./index.d.ts", @@ -28,9 +28,9 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", - "@thi.ng/transducers": "^1.16.0", + "@thi.ng/transducers": "^2.0.0", "@types/webgl2": "^0.0.4" }, "keywords": [ @@ -40,4 +40,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/packages/hdom/CHANGELOG.md b/packages/hdom/CHANGELOG.md index cf5d2f1f86..08059f31a0 100644 --- a/packages/hdom/CHANGELOG.md +++ b/packages/hdom/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [3.0.33](https://github.com/thi-ng/umbrella/compare/@thi.ng/hdom@3.0.32...@thi.ng/hdom@3.0.33) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/hdom + ## [3.0.32](https://github.com/thi-ng/umbrella/compare/@thi.ng/hdom@3.0.31...@thi.ng/hdom@3.0.32) (2018-08-01) diff --git a/packages/hdom/package.json b/packages/hdom/package.json index 5a08034708..816558234d 100644 --- a/packages/hdom/package.json +++ b/packages/hdom/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/hdom", - "version": "3.0.32", + "version": "3.0.33", "description": "Lightweight vanilla ES6 UI component & virtual DOM system", "main": "./index.js", "typings": "./index.d.ts", @@ -20,7 +20,7 @@ "test": "rm -rf build && tsc -p test && nyc mocha build/test/*.js" }, "devDependencies": { - "@thi.ng/atom": "^1.4.6", + "@thi.ng/atom": "^1.4.7", "@types/mocha": "^5.2.5", "@types/node": "^10.5.5", "mocha": "^5.2.0", @@ -29,11 +29,11 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", - "@thi.ng/diff": "^1.0.21", + "@thi.ng/diff": "^1.0.22", "@thi.ng/equiv": "^0.1.7", - "@thi.ng/hiccup": "^2.0.9" + "@thi.ng/hiccup": "^2.0.10" }, "keywords": [ "browser", @@ -48,4 +48,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/packages/heaps/CHANGELOG.md b/packages/heaps/CHANGELOG.md index 3130dc8802..1c9c413f57 100644 --- a/packages/heaps/CHANGELOG.md +++ b/packages/heaps/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.16](https://github.com/thi-ng/umbrella/compare/@thi.ng/heaps@0.2.15...@thi.ng/heaps@0.2.16) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/heaps + ## [0.2.15](https://github.com/thi-ng/umbrella/compare/@thi.ng/heaps@0.2.14...@thi.ng/heaps@0.2.15) (2018-08-01) diff --git a/packages/heaps/package.json b/packages/heaps/package.json index 3ba0cc8e94..8425d4c4da 100644 --- a/packages/heaps/package.json +++ b/packages/heaps/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/heaps", - "version": "0.2.15", + "version": "0.2.16", "description": "Generic binary heap & d-ary heap implementations with customizable ordering", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/compare": "^0.1.6" }, "keywords": [ diff --git a/packages/hiccup-css/CHANGELOG.md b/packages/hiccup-css/CHANGELOG.md index 572573b5f1..c00428584d 100644 --- a/packages/hiccup-css/CHANGELOG.md +++ b/packages/hiccup-css/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.15](https://github.com/thi-ng/umbrella/compare/@thi.ng/hiccup-css@0.2.14...@thi.ng/hiccup-css@0.2.15) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/hiccup-css + ## [0.2.14](https://github.com/thi-ng/umbrella/compare/@thi.ng/hiccup-css@0.2.13...@thi.ng/hiccup-css@0.2.14) (2018-08-08) diff --git a/packages/hiccup-css/package.json b/packages/hiccup-css/package.json index 0d38b59268..0521fd800c 100644 --- a/packages/hiccup-css/package.json +++ b/packages/hiccup-css/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/hiccup-css", - "version": "0.2.14", + "version": "0.2.15", "description": "CSS from nested JS data structures", "main": "./index.js", "typings": "./index.d.ts", @@ -28,10 +28,10 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "clojure", diff --git a/packages/hiccup-svg/CHANGELOG.md b/packages/hiccup-svg/CHANGELOG.md index dcfa3ad58b..6395ebf2d5 100644 --- a/packages/hiccup-svg/CHANGELOG.md +++ b/packages/hiccup-svg/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.0.10](https://github.com/thi-ng/umbrella/compare/@thi.ng/hiccup-svg@1.0.9...@thi.ng/hiccup-svg@1.0.10) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/hiccup-svg + ## [1.0.9](https://github.com/thi-ng/umbrella/compare/@thi.ng/hiccup-svg@1.0.8...@thi.ng/hiccup-svg@1.0.9) (2018-08-01) diff --git a/packages/hiccup-svg/package.json b/packages/hiccup-svg/package.json index fa4452163c..e7b8d23648 100644 --- a/packages/hiccup-svg/package.json +++ b/packages/hiccup-svg/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/hiccup-svg", - "version": "1.0.9", + "version": "1.0.10", "description": "SVG element functions for @thi.ng/hiccup & @thi.ng/hdom", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/hiccup": "^2.0.9" + "@thi.ng/hiccup": "^2.0.10" }, "keywords": [ "components", diff --git a/packages/hiccup/CHANGELOG.md b/packages/hiccup/CHANGELOG.md index 383ce77c95..72b40acabe 100644 --- a/packages/hiccup/CHANGELOG.md +++ b/packages/hiccup/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [2.0.10](https://github.com/thi-ng/umbrella/compare/@thi.ng/hiccup@2.0.9...@thi.ng/hiccup@2.0.10) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/hiccup + ## [2.0.9](https://github.com/thi-ng/umbrella/compare/@thi.ng/hiccup@2.0.8...@thi.ng/hiccup@2.0.9) (2018-08-01) diff --git a/packages/hiccup/package.json b/packages/hiccup/package.json index e4481bcd3d..38636e955e 100644 --- a/packages/hiccup/package.json +++ b/packages/hiccup/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/hiccup", - "version": "2.0.9", + "version": "2.0.10", "description": "HTML/SVG/XML serialization of nested data structures, iterables & closures", "main": "./index.js", "typings": "./index.d.ts", @@ -20,7 +20,7 @@ "test": "rm -rf build && tsc -p test && nyc mocha build/test/*.js" }, "devDependencies": { - "@thi.ng/atom": "^1.4.6", + "@thi.ng/atom": "^1.4.7", "@types/mocha": "^5.2.5", "@types/node": "^10.5.5", "mocha": "^5.2.0", diff --git a/packages/iges/CHANGELOG.md b/packages/iges/CHANGELOG.md index 814ea35ad3..1a9f9a3462 100644 --- a/packages/iges/CHANGELOG.md +++ b/packages/iges/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.5](https://github.com/thi-ng/umbrella/compare/@thi.ng/iges@0.2.4...@thi.ng/iges@0.2.5) (2018-08-24) + + +### Bug Fixes + +* **iges:** regression to due transducers update ([78d0a84](https://github.com/thi-ng/umbrella/commit/78d0a84)) + + + + ## [0.2.4](https://github.com/thi-ng/umbrella/compare/@thi.ng/iges@0.2.3...@thi.ng/iges@0.2.4) (2018-08-08) diff --git a/packages/iges/package.json b/packages/iges/package.json index f415d313c1..31617e6a04 100644 --- a/packages/iges/package.json +++ b/packages/iges/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/iges", - "version": "0.2.4", + "version": "0.2.5", "description": "IGES 5.3 serializer for (currently only) polygonal geometry, both open & closed", "main": "./index.js", "typings": "./index.d.ts", @@ -28,10 +28,10 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", - "@thi.ng/defmulti": "^0.3.7", - "@thi.ng/strings": "^0.2.0", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/api": "^4.1.0", + "@thi.ng/defmulti": "^0.3.8", + "@thi.ng/strings": "^0.3.0", + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "CAD", diff --git a/packages/interceptors/CHANGELOG.md b/packages/interceptors/CHANGELOG.md index 9b0710c674..634c7cb218 100644 --- a/packages/interceptors/CHANGELOG.md +++ b/packages/interceptors/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.8.10](https://github.com/thi-ng/umbrella/compare/@thi.ng/interceptors@1.8.9...@thi.ng/interceptors@1.8.10) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/interceptors + ## [1.8.9](https://github.com/thi-ng/umbrella/compare/@thi.ng/interceptors@1.8.8...@thi.ng/interceptors@1.8.9) (2018-08-01) diff --git a/packages/interceptors/package.json b/packages/interceptors/package.json index 15fc5bffc4..f7494db1b6 100644 --- a/packages/interceptors/package.json +++ b/packages/interceptors/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/interceptors", - "version": "1.8.9", + "version": "1.8.10", "description": "Interceptor based event bus, side effect & immutable state handling", "main": "./index.js", "typings": "./index.d.ts", @@ -28,8 +28,8 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", - "@thi.ng/atom": "^1.4.6", + "@thi.ng/api": "^4.1.0", + "@thi.ng/atom": "^1.4.7", "@thi.ng/checks": "^1.5.7", "@thi.ng/errors": "^0.1.6", "@thi.ng/paths": "^1.5.2" diff --git a/packages/iterators/CHANGELOG.md b/packages/iterators/CHANGELOG.md index 5ff9e384ab..2317d54fe0 100644 --- a/packages/iterators/CHANGELOG.md +++ b/packages/iterators/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [4.1.21](https://github.com/thi-ng/umbrella/compare/@thi.ng/iterators@4.1.20...@thi.ng/iterators@4.1.21) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/iterators + ## [4.1.20](https://github.com/thi-ng/umbrella/compare/@thi.ng/iterators@4.1.19...@thi.ng/iterators@4.1.20) (2018-08-01) diff --git a/packages/iterators/package.json b/packages/iterators/package.json index 846b311707..19b86bc3a0 100644 --- a/packages/iterators/package.json +++ b/packages/iterators/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/iterators", - "version": "4.1.20", + "version": "4.1.21", "description": "clojure.core inspired, composable ES6 iterators & generators", "main": "./index.js", "typings": "./index.d.ts", @@ -28,8 +28,8 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", - "@thi.ng/dcons": "^1.0.7", + "@thi.ng/api": "^4.1.0", + "@thi.ng/dcons": "^1.1.0", "@thi.ng/errors": "^0.1.6" }, "keywords": [ diff --git a/packages/memoize/CHANGELOG.md b/packages/memoize/CHANGELOG.md index cc3cdbf2c9..82c0488b65 100644 --- a/packages/memoize/CHANGELOG.md +++ b/packages/memoize/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/memoize@0.1.0...@thi.ng/memoize@0.1.1) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/memoize + # 0.1.0 (2018-08-08) diff --git a/packages/memoize/package.json b/packages/memoize/package.json index d3aa5ad67d..5c6af0065d 100644 --- a/packages/memoize/package.json +++ b/packages/memoize/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/memoize", - "version": "0.1.0", + "version": "0.1.1", "description": "Function memoization with configurable caches", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6" + "@thi.ng/api": "^4.1.0" }, "keywords": [ "cache", @@ -40,4 +40,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/packages/pointfree-lang/CHANGELOG.md b/packages/pointfree-lang/CHANGELOG.md index 9cb0492627..e49b8a5192 100644 --- a/packages/pointfree-lang/CHANGELOG.md +++ b/packages/pointfree-lang/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.18](https://github.com/thi-ng/umbrella/compare/@thi.ng/pointfree-lang@0.2.17...@thi.ng/pointfree-lang@0.2.18) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/pointfree-lang + ## [0.2.17](https://github.com/thi-ng/umbrella/compare/@thi.ng/pointfree-lang@0.2.16...@thi.ng/pointfree-lang@0.2.17) (2018-08-01) diff --git a/packages/pointfree-lang/package.json b/packages/pointfree-lang/package.json index d8d144cb76..79a0b9a10d 100644 --- a/packages/pointfree-lang/package.json +++ b/packages/pointfree-lang/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/pointfree-lang", - "version": "0.2.17", + "version": "0.2.18", "description": "Forth style syntax layer/compiler for the @thi.ng/pointfree DSL", "main": "./index.js", "typings": "./index.d.ts", @@ -30,9 +30,9 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/errors": "^0.1.6", - "@thi.ng/pointfree": "^0.8.6" + "@thi.ng/pointfree": "^0.8.7" }, "keywords": [ "concatenative", diff --git a/packages/pointfree/CHANGELOG.md b/packages/pointfree/CHANGELOG.md index ce3137f1c6..b63af8e259 100644 --- a/packages/pointfree/CHANGELOG.md +++ b/packages/pointfree/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.8.7](https://github.com/thi-ng/umbrella/compare/@thi.ng/pointfree@0.8.6...@thi.ng/pointfree@0.8.7) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/pointfree + ## [0.8.6](https://github.com/thi-ng/umbrella/compare/@thi.ng/pointfree@0.8.5...@thi.ng/pointfree@0.8.6) (2018-08-01) diff --git a/packages/pointfree/package.json b/packages/pointfree/package.json index 408aab3f7a..cca7cb5f51 100644 --- a/packages/pointfree/package.json +++ b/packages/pointfree/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/pointfree", - "version": "0.8.6", + "version": "0.8.7", "description": "Pointfree functional composition / Forth style stack execution engine", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6" diff --git a/packages/range-coder/CHANGELOG.md b/packages/range-coder/CHANGELOG.md index 9f011827df..880d6d27a2 100644 --- a/packages/range-coder/CHANGELOG.md +++ b/packages/range-coder/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.5](https://github.com/thi-ng/umbrella/compare/@thi.ng/range-coder@0.1.4...@thi.ng/range-coder@0.1.5) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/range-coder + ## [0.1.4](https://github.com/thi-ng/umbrella/compare/@thi.ng/range-coder@0.1.3...@thi.ng/range-coder@0.1.4) (2018-08-08) diff --git a/packages/range-coder/package.json b/packages/range-coder/package.json index 1479fd5a5e..5562826539 100644 --- a/packages/range-coder/package.json +++ b/packages/range-coder/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/range-coder", - "version": "0.1.4", + "version": "0.1.5", "description": "Binary data range encoder / decoder", "main": "./index.js", "typings": "./index.d.ts", @@ -20,7 +20,7 @@ "test": "rm -rf build && tsc -p test && nyc mocha build/test/*.js" }, "devDependencies": { - "@thi.ng/transducers": "^1.16.0", + "@thi.ng/transducers": "^2.0.0", "@types/mocha": "^5.2.5", "@types/node": "^10.5.5", "mocha": "^5.2.0", diff --git a/packages/resolve-map/CHANGELOG.md b/packages/resolve-map/CHANGELOG.md index 2c428dc468..c9961caf93 100644 --- a/packages/resolve-map/CHANGELOG.md +++ b/packages/resolve-map/CHANGELOG.md @@ -3,7 +3,15 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - + +## [3.0.8](https://github.com/thi-ng/umbrella/compare/@thi.ng/resolve-map@3.0.7...@thi.ng/resolve-map@3.0.8) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/resolve-map + + ## [3.0.7](https://github.com/thi-ng/umbrella/compare/@thi.ng/resolve-map@3.0.6...@thi.ng/resolve-map@3.0.7) (2018-08-01) @@ -11,7 +19,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline **Note:** Version bump only for package @thi.ng/resolve-map - + ## [3.0.6](https://github.com/thi-ng/umbrella/compare/@thi.ng/resolve-map@3.0.5...@thi.ng/resolve-map@3.0.6) (2018-07-20) diff --git a/packages/resolve-map/package.json b/packages/resolve-map/package.json index 8a780a9a91..e9328786a9 100644 --- a/packages/resolve-map/package.json +++ b/packages/resolve-map/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/resolve-map", - "version": "3.0.7", + "version": "3.0.8", "description": "DAG resolution of vanilla objects & arrays with internally linked values", "main": "./index.js", "typings": "./index.d.ts", diff --git a/packages/rle-pack/CHANGELOG.md b/packages/rle-pack/CHANGELOG.md index febe8136f4..03bf012bd5 100644 --- a/packages/rle-pack/CHANGELOG.md +++ b/packages/rle-pack/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [1.0.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/rle-pack@0.2.24...@thi.ng/rle-pack@1.0.0) (2018-08-24) + + +### Bug Fixes + +* **rle-pack:** fix initial repeat counts in encodeBytes(), update readme ([8565edb](https://github.com/thi-ng/umbrella/commit/8565edb)) + + +### Features + +* **rle-pack:** add support for custom input word sizes ([fd8e761](https://github.com/thi-ng/umbrella/commit/fd8e761)) +* **rle-pack:** further update data format (non-repeats) ([4041521](https://github.com/thi-ng/umbrella/commit/4041521)) +* **rle-pack:** update data format, custom repeat sizes, rename fns ([694a253](https://github.com/thi-ng/umbrella/commit/694a253)) + + +### BREAKING CHANGES + +* **rle-pack:** new API and encoding format, see readme +for details + + + + ## [0.2.24](https://github.com/thi-ng/umbrella/compare/@thi.ng/rle-pack@0.2.23...@thi.ng/rle-pack@0.2.24) (2018-08-01) diff --git a/packages/rle-pack/package.json b/packages/rle-pack/package.json index cede746688..2e774dca28 100644 --- a/packages/rle-pack/package.json +++ b/packages/rle-pack/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rle-pack", - "version": "0.2.24", + "version": "1.0.0", "description": "Binary run-length encoding packer w/ flexible repeat bit widths", "main": "./index.js", "typings": "./index.d.ts", @@ -43,4 +43,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/packages/router/CHANGELOG.md b/packages/router/CHANGELOG.md index 35c982107c..f86c98d1f4 100644 --- a/packages/router/CHANGELOG.md +++ b/packages/router/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.21](https://github.com/thi-ng/umbrella/compare/@thi.ng/router@0.1.20...@thi.ng/router@0.1.21) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/router + ## [0.1.20](https://github.com/thi-ng/umbrella/compare/@thi.ng/router@0.1.19...@thi.ng/router@0.1.20) (2018-08-01) diff --git a/packages/router/package.json b/packages/router/package.json index 1583677f89..69145ff74f 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/router", - "version": "0.1.20", + "version": "0.1.21", "description": "Generic router for browser & non-browser based applications", "main": "./index.js", "typings": "./index.d.ts", @@ -27,7 +27,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6" diff --git a/packages/rstream-csp/CHANGELOG.md b/packages/rstream-csp/CHANGELOG.md index a594a2b9f1..f6fde73b09 100644 --- a/packages/rstream-csp/CHANGELOG.md +++ b/packages/rstream-csp/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.97](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-csp@0.1.96...@thi.ng/rstream-csp@0.1.97) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/rstream-csp + ## [0.1.96](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-csp@0.1.95...@thi.ng/rstream-csp@0.1.96) (2018-08-08) diff --git a/packages/rstream-csp/package.json b/packages/rstream-csp/package.json index 998b0b0356..866e69e408 100644 --- a/packages/rstream-csp/package.json +++ b/packages/rstream-csp/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-csp", - "version": "0.1.96", + "version": "0.1.97", "description": "@thi.ng/csp bridge module for @thi.ng/rstream", "main": "./index.js", "typings": "./index.d.ts", @@ -28,8 +28,8 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/csp": "^0.3.55", - "@thi.ng/rstream": "^1.11.2" + "@thi.ng/csp": "^0.3.56", + "@thi.ng/rstream": "^1.11.3" }, "keywords": [ "bridge", diff --git a/packages/rstream-dot/CHANGELOG.md b/packages/rstream-dot/CHANGELOG.md index 07b5a21a8e..f1e83827ff 100644 --- a/packages/rstream-dot/CHANGELOG.md +++ b/packages/rstream-dot/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.36](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-dot@0.2.35...@thi.ng/rstream-dot@0.2.36) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/rstream-dot + ## [0.2.35](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-dot@0.2.34...@thi.ng/rstream-dot@0.2.35) (2018-08-08) diff --git a/packages/rstream-dot/package.json b/packages/rstream-dot/package.json index 21bade3336..652290e6c8 100644 --- a/packages/rstream-dot/package.json +++ b/packages/rstream-dot/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-dot", - "version": "0.2.35", + "version": "0.2.36", "description": "Graphviz DOT conversion of @thi.ng/rstream dataflow graph topologies", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/rstream": "^1.11.2" + "@thi.ng/rstream": "^1.11.3" }, "keywords": [ "conversion", diff --git a/packages/rstream-gestures/CHANGELOG.md b/packages/rstream-gestures/CHANGELOG.md index 0f48ee9225..7d484d27f2 100644 --- a/packages/rstream-gestures/CHANGELOG.md +++ b/packages/rstream-gestures/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.4.17](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-gestures@0.4.16...@thi.ng/rstream-gestures@0.4.17) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/rstream-gestures + ## [0.4.16](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-gestures@0.4.15...@thi.ng/rstream-gestures@0.4.16) (2018-08-08) diff --git a/packages/rstream-gestures/package.json b/packages/rstream-gestures/package.json index 89ec46963d..12679292c7 100644 --- a/packages/rstream-gestures/package.json +++ b/packages/rstream-gestures/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-gestures", - "version": "0.4.16", + "version": "0.4.17", "description": "Unified mouse, mouse wheel & single-touch event stream abstraction", "main": "./index.js", "typings": "./index.d.ts", @@ -28,9 +28,9 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", - "@thi.ng/rstream": "^1.11.2", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/api": "^4.1.0", + "@thi.ng/rstream": "^1.11.3", + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "dataflow", diff --git a/packages/rstream-graph/CHANGELOG.md b/packages/rstream-graph/CHANGELOG.md index 20a00a093b..a528ca1fd7 100644 --- a/packages/rstream-graph/CHANGELOG.md +++ b/packages/rstream-graph/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [2.1.21](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-graph@2.1.20...@thi.ng/rstream-graph@2.1.21) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/rstream-graph + ## [2.1.20](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-graph@2.1.19...@thi.ng/rstream-graph@2.1.20) (2018-08-08) diff --git a/packages/rstream-graph/package.json b/packages/rstream-graph/package.json index b365aa1c54..f20712229b 100644 --- a/packages/rstream-graph/package.json +++ b/packages/rstream-graph/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-graph", - "version": "2.1.20", + "version": "2.1.21", "description": "Declarative dataflow graph construction for @thi.ng/rstream", "main": "./index.js", "typings": "./index.d.ts", @@ -28,13 +28,13 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", "@thi.ng/errors": "^0.1.6", "@thi.ng/paths": "^1.5.2", - "@thi.ng/resolve-map": "^3.0.7", - "@thi.ng/rstream": "^1.11.2", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/resolve-map": "^3.0.8", + "@thi.ng/rstream": "^1.11.3", + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "compute", diff --git a/packages/rstream-log/CHANGELOG.md b/packages/rstream-log/CHANGELOG.md index fda5d78d35..3f27ca137d 100644 --- a/packages/rstream-log/CHANGELOG.md +++ b/packages/rstream-log/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.0.48](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-log@1.0.47...@thi.ng/rstream-log@1.0.48) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/rstream-log + ## [1.0.47](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-log@1.0.46...@thi.ng/rstream-log@1.0.47) (2018-08-08) diff --git a/packages/rstream-log/package.json b/packages/rstream-log/package.json index 56af579fe3..07fb685a23 100644 --- a/packages/rstream-log/package.json +++ b/packages/rstream-log/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-log", - "version": "1.0.47", + "version": "1.0.48", "description": "Structured, multilevel & hierarchical loggers based on @thi.ng/rstream", "main": "./index.js", "typings": "./index.d.ts", @@ -28,11 +28,11 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/rstream": "^1.11.2", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/rstream": "^1.11.3", + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "ES6", diff --git a/packages/rstream-query/CHANGELOG.md b/packages/rstream-query/CHANGELOG.md index 5764dcb1ae..708db97bad 100644 --- a/packages/rstream-query/CHANGELOG.md +++ b/packages/rstream-query/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.3.35](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-query@0.3.34...@thi.ng/rstream-query@0.3.35) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/rstream-query + ## [0.3.34](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream-query@0.3.33...@thi.ng/rstream-query@0.3.34) (2018-08-08) diff --git a/packages/rstream-query/package.json b/packages/rstream-query/package.json index bed0ffb37a..33e2d6a79f 100644 --- a/packages/rstream-query/package.json +++ b/packages/rstream-query/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream-query", - "version": "0.3.34", + "version": "0.3.35", "description": "@thi.ng/rstream based triple store & reactive query engine", "main": "./index.js", "typings": "./index.d.ts", @@ -28,14 +28,14 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", - "@thi.ng/associative": "^0.5.11", + "@thi.ng/api": "^4.1.0", + "@thi.ng/associative": "^0.6.0", "@thi.ng/checks": "^1.5.7", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/rstream": "^1.11.2", - "@thi.ng/rstream-dot": "^0.2.35", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/rstream": "^1.11.3", + "@thi.ng/rstream-dot": "^0.2.36", + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "dataflow", diff --git a/packages/rstream/CHANGELOG.md b/packages/rstream/CHANGELOG.md index 93238a4c82..fc7355b6f0 100644 --- a/packages/rstream/CHANGELOG.md +++ b/packages/rstream/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.11.3](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream@1.11.2...@thi.ng/rstream@1.11.3) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/rstream + ## [1.11.2](https://github.com/thi-ng/umbrella/compare/@thi.ng/rstream@1.11.1...@thi.ng/rstream@1.11.2) (2018-08-08) diff --git a/packages/rstream/package.json b/packages/rstream/package.json index fd93485f6b..00335485bf 100644 --- a/packages/rstream/package.json +++ b/packages/rstream/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/rstream", - "version": "1.11.2", + "version": "1.11.3", "description": "Reactive multi-tap streams, dataflow & transformation pipeline constructs", "main": "./index.js", "typings": "./index.d.ts", @@ -28,13 +28,13 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", - "@thi.ng/associative": "^0.5.11", - "@thi.ng/atom": "^1.4.6", + "@thi.ng/api": "^4.1.0", + "@thi.ng/associative": "^0.6.0", + "@thi.ng/atom": "^1.4.7", "@thi.ng/checks": "^1.5.7", "@thi.ng/errors": "^0.1.6", "@thi.ng/paths": "^1.5.2", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "datastructure", diff --git a/packages/sax/CHANGELOG.md b/packages/sax/CHANGELOG.md index e4a1de4409..1bd0161ab5 100644 --- a/packages/sax/CHANGELOG.md +++ b/packages/sax/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.3.14](https://github.com/thi-ng/umbrella/compare/@thi.ng/sax@0.3.13...@thi.ng/sax@0.3.14) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/sax + ## [0.3.13](https://github.com/thi-ng/umbrella/compare/@thi.ng/sax@0.3.12...@thi.ng/sax@0.3.13) (2018-08-08) diff --git a/packages/sax/package.json b/packages/sax/package.json index 0e2072e7bf..0766781cac 100644 --- a/packages/sax/package.json +++ b/packages/sax/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/sax", - "version": "0.3.13", + "version": "0.3.14", "description": "Transducer-based, SAX-like, non-validating, speedy & tiny XML parser", "main": "./index.js", "typings": "./index.d.ts", @@ -28,9 +28,9 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", - "@thi.ng/transducers": "^1.16.0", - "@thi.ng/transducers-fsm": "^0.2.12" + "@thi.ng/api": "^4.1.0", + "@thi.ng/transducers": "^2.0.0", + "@thi.ng/transducers-fsm": "^0.2.13" }, "keywords": [ "ES6", diff --git a/packages/strings/CHANGELOG.md b/packages/strings/CHANGELOG.md index 2777331297..898574ca0c 100644 --- a/packages/strings/CHANGELOG.md +++ b/packages/strings/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [0.3.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/strings@0.2.0...@thi.ng/strings@0.3.0) (2018-08-24) + + +### Bug Fixes + +* **strings:** buffer length (for null inputs) (`center()`) ([5209c42](https://github.com/thi-ng/umbrella/commit/5209c42)) + + +### Features + +* **strings:** add case converters ([653a175](https://github.com/thi-ng/umbrella/commit/653a175)) +* **strings:** add truncateLeft() & wrap() stringers ([1a20bc2](https://github.com/thi-ng/umbrella/commit/1a20bc2)) + + + + # [0.2.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/strings@0.1.1...@thi.ng/strings@0.2.0) (2018-08-08) diff --git a/packages/strings/package.json b/packages/strings/package.json index 0ade10c618..8b051efd01 100644 --- a/packages/strings/package.json +++ b/packages/strings/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/strings", - "version": "0.2.0", + "version": "0.3.0", "description": "Various string formatting & utility functions", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/memoize": "^0.1.0" + "@thi.ng/memoize": "^0.1.1" }, "keywords": [ "ES6", diff --git a/packages/transducers-fsm/CHANGELOG.md b/packages/transducers-fsm/CHANGELOG.md index 6acab0c0a9..f792a5617b 100644 --- a/packages/transducers-fsm/CHANGELOG.md +++ b/packages/transducers-fsm/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.13](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-fsm@0.2.12...@thi.ng/transducers-fsm@0.2.13) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/transducers-fsm + ## [0.2.12](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-fsm@0.2.11...@thi.ng/transducers-fsm@0.2.12) (2018-08-08) diff --git a/packages/transducers-fsm/package.json b/packages/transducers-fsm/package.json index 113f63b278..b14c8a38cc 100644 --- a/packages/transducers-fsm/package.json +++ b/packages/transducers-fsm/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/transducers-fsm", - "version": "0.2.12", + "version": "0.2.13", "description": "Transducer-based Finite State Machine transformer", "main": "./index.js", "typings": "./index.d.ts", @@ -28,8 +28,8 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/api": "^4.1.0", + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "ES6", diff --git a/packages/transducers-hdom/CHANGELOG.md b/packages/transducers-hdom/CHANGELOG.md index ce84f6e27d..cb87b83d10 100644 --- a/packages/transducers-hdom/CHANGELOG.md +++ b/packages/transducers-hdom/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.1.3](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-hdom@0.1.2...@thi.ng/transducers-hdom@0.1.3) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/transducers-hdom + ## [0.1.2](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-hdom@0.1.1...@thi.ng/transducers-hdom@0.1.2) (2018-08-08) diff --git a/packages/transducers-hdom/package.json b/packages/transducers-hdom/package.json index b55c2b286a..4be9217b4b 100644 --- a/packages/transducers-hdom/package.json +++ b/packages/transducers-hdom/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/transducers-hdom", - "version": "0.1.2", + "version": "0.1.3", "description": "Transducer based UI updater for @thi.ng/hdom", "main": "./index.js", "typings": "./index.d.ts", @@ -29,8 +29,8 @@ }, "dependencies": { "@thi.ng/checks": "^1.5.7", - "@thi.ng/hdom": "^3.0.32", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/hdom": "^3.0.33", + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "diff", diff --git a/packages/transducers-stats/CHANGELOG.md b/packages/transducers-stats/CHANGELOG.md index 40ca613732..f1775eb0ff 100644 --- a/packages/transducers-stats/CHANGELOG.md +++ b/packages/transducers-stats/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [0.4.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-stats@0.3.4...@thi.ng/transducers-stats@0.4.0) (2018-08-24) + + +### Features + +* **transducers-stats:** make xforms iterable if input given ([c9ac981](https://github.com/thi-ng/umbrella/commit/c9ac981)) + + + + ## [0.3.4](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers-stats@0.3.3...@thi.ng/transducers-stats@0.3.4) (2018-08-08) diff --git a/packages/transducers-stats/package.json b/packages/transducers-stats/package.json index efb4541a8f..2a907ca967 100644 --- a/packages/transducers-stats/package.json +++ b/packages/transducers-stats/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/transducers-stats", - "version": "0.3.4", + "version": "0.4.0", "description": "Transducers for statistical / technical analysis", "main": "./index.js", "typings": "./index.d.ts", @@ -28,9 +28,9 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/dcons": "^1.0.7", + "@thi.ng/dcons": "^1.1.0", "@thi.ng/errors": "^0.1.6", - "@thi.ng/transducers": "^1.16.0" + "@thi.ng/transducers": "^2.0.0" }, "keywords": [ "ES6", diff --git a/packages/transducers/CHANGELOG.md b/packages/transducers/CHANGELOG.md index 94bcbe0d66..dd2d1c5729 100644 --- a/packages/transducers/CHANGELOG.md +++ b/packages/transducers/CHANGELOG.md @@ -3,6 +3,57 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [2.0.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers@1.16.0...@thi.ng/transducers@2.0.0) (2018-08-24) + + +### Bug Fixes + +* **transducers:** arg handling in rename() ([7a5be21](https://github.com/thi-ng/umbrella/commit/7a5be21)) +* **transducers:** copy&paste error (push) ([832e57f](https://github.com/thi-ng/umbrella/commit/832e57f)) +* **transducers:** hex type decl ([723da5b](https://github.com/thi-ng/umbrella/commit/723da5b)) +* **transducers:** iterator1() final reduced value handling ([d861bdd](https://github.com/thi-ng/umbrella/commit/d861bdd)) + + +### Code Refactoring + +* **transducers:** rename inspect() => trace() ([e713704](https://github.com/thi-ng/umbrella/commit/e713704)) + + +### Features + +* **transducers:** add fill() & fillN() reducers ([0bd860e](https://github.com/thi-ng/umbrella/commit/0bd860e)) +* **transducers:** add GroupByOpts interface, update groupBy* reducers ([2c3a114](https://github.com/thi-ng/umbrella/commit/2c3a114)) +* **transducers:** update all reducers to accept opt iterables ([89b4ad5](https://github.com/thi-ng/umbrella/commit/89b4ad5)) +* **transducers:** update all xforms to also work as iterator ([bae8a1d](https://github.com/thi-ng/umbrella/commit/bae8a1d)) +* **transducers:** update base64Encode() to return string if input given ([599f2b6](https://github.com/thi-ng/umbrella/commit/599f2b6)) + + +### Performance Improvements + +* **transducers:** add IReducible, update reduce() ([9d83255](https://github.com/thi-ng/umbrella/commit/9d83255)) +* **transducers:** add iterator1(), update various xforms ([ab662d8](https://github.com/thi-ng/umbrella/commit/ab662d8)) + + +### BREAKING CHANGES + +* **transducers:** groupByMap() & groupByObj() args now given as +options object +* **transducers:** replace some xform args with options objects, impacted are: + +- convolve2d() +- filterFuzzy() +- hexDump() +- movingMedian() +- partitionSort() +- partitionSync() +- streamSort() +- wordWrap() +* **transducers:** rename inspect() => trace() + + + + # [1.16.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/transducers@1.15.0...@thi.ng/transducers@1.16.0) (2018-08-08) diff --git a/packages/transducers/package.json b/packages/transducers/package.json index 5fb7406187..eb23621818 100644 --- a/packages/transducers/package.json +++ b/packages/transducers/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/transducers", - "version": "1.16.0", + "version": "2.0.0", "description": "Lightweight transducer implementations for ES6 / TypeScript", "main": "./index.js", "typings": "./index.d.ts", @@ -28,13 +28,13 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7", "@thi.ng/compare": "^0.1.6", - "@thi.ng/compose": "^0.0.1", + "@thi.ng/compose": "^0.1.0", "@thi.ng/equiv": "^0.1.7", "@thi.ng/errors": "^0.1.6", - "@thi.ng/strings": "^0.2.0" + "@thi.ng/strings": "^0.3.0" }, "keywords": [ "ES6", diff --git a/packages/vectors/CHANGELOG.md b/packages/vectors/CHANGELOG.md index 4dff7184c9..db644ea934 100644 --- a/packages/vectors/CHANGELOG.md +++ b/packages/vectors/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.2.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/vectors@0.2.0...@thi.ng/vectors@0.2.1) (2018-08-24) + + + + +**Note:** Version bump only for package @thi.ng/vectors + # [0.2.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/vectors@0.1.3...@thi.ng/vectors@0.2.0) (2018-08-02) diff --git a/packages/vectors/package.json b/packages/vectors/package.json index bdbc209fd7..6320e44fb6 100644 --- a/packages/vectors/package.json +++ b/packages/vectors/package.json @@ -1,6 +1,6 @@ { "name": "@thi.ng/vectors", - "version": "0.2.0", + "version": "0.2.1", "description": "Vector algebra for fixed & variable sizes, memory mapped, flexible layouts", "main": "./index.js", "typings": "./index.d.ts", @@ -28,7 +28,7 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/api": "^4.0.6", + "@thi.ng/api": "^4.1.0", "@thi.ng/checks": "^1.5.7" }, "keywords": [

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 kfitvU&2$9+jLOxH^`^23c~f? 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 EKZG&?JOBUy literal 0 HcmV?d00001 diff --git a/packages/rle-pack/README.md b/packages/rle-pack/README.md index d4ceac866b..9c3db99fe1 100644 --- a/packages/rle-pack/README.md +++ b/packages/rle-pack/README.md @@ -7,22 +7,31 @@ This project is part of the ## About -Binary run-length encoding packer/unpacker w/ support for flexible input -word sizes and repeat bit widths. +Binary run-length encoding packer/unpacker w/ support for customizable +input word sizes (1 - 32 bits) and repeat count (run-length) bit sizes +(1 - 16 bits). The encoder uses 4 different repeat group sizes +(thresholds) to minimize the number of bits used to store the run +lengths. The range of supported run lengths is 16 bits (i.e. 65536 +repetitions). If a value is repeated more often than that, the remainder +will be encoded using additional RLE chunks... -Encoding format: +### Encoding format -- 32 bits - original size in bytes (header) +![data layout](https://github.com/thi-ng/umbrella/tree/master/packages/assets/rle-layout.png) + +- 32 bits - original number of words +- 5 bits - word size +- 16 bits - RLE repeat group bit sizes (default: 3, 4, 8, 16) Then per value: - 1 bit - encoding flag (1 = RLE encoded, 0 = single occurrence) - n bits - value -The following is only used for repeated values: +The following are only used for repeated values: - 2 bits - repeat class -- 3/4/8/16 bits - repeat count - 1 (if > 0x10000 then split into chunks...) +- m bits - repeat count - 1 (if greater than max group size then split into chunks...) Brief overview for 8-bit word size (default): @@ -63,15 +72,23 @@ let rle = require("@thi.ng/rle-pack"); src = new Uint8Array(1024); src.set([1,1,1,1,1,2,2,2,2,3,3,3,4,4,5,4,4,3,3,3,2,2,2,2,1,1,1,1,1], 512); -// pack data (word size = 3 bits, i.e. value range 0 - 7) -packed = rle.encodeBytes(src, src.length, 3); -// Uint8Array [0, 0, 4, 0, 140, 7, 254, 73, 67, 177, 96, 87, 3, 98, 161, 201, 35, 1, 226] +// pack data +packed = rle.encode(src, src.length); +// Uint8Array [0,0,4,0,65,27,252,3,1,255,128,146,4,56,24,160,129,2,193,3,3,20,8,112,18,64,48,30,32] packed.length -// 19 => 1.85% of original +// 29 => 2.83% of original + +// pack with custom word size (3 bits, i.e. our value range is only 0-7) +// and use custom repeat group sizes suitable for our data +alt = rle.encode(src, src.length, 3, [1, 2, 3, 9]); +// Uint8Array [0,0,4,0,24,9,68,127,249,165,61,182,21,195,109,79,52,143,196] + +alt.length +// 19 => 1.85% of original, ~65% of default config // unpack -unpacked = rle.decodeBytes(packed, 3); +unpacked = new Uint8Array(rle.decode(alt)); ``` ## Authors @@ -80,4 +97,4 @@ unpacked = rle.decodeBytes(packed, 3); ## License -© 2017 Karsten Schmidt // Apache Software License 2.0 \ No newline at end of file +© 2017 - 2018 Karsten Schmidt // Apache Software License 2.0 \ No newline at end of file diff --git a/packages/rle-pack/package.json b/packages/rle-pack/package.json index a25766fbba..cede746688 100644 --- a/packages/rle-pack/package.json +++ b/packages/rle-pack/package.json @@ -29,7 +29,8 @@ "typescript": "^3.0.1" }, "dependencies": { - "@thi.ng/bitstream": "^0.4.15" + "@thi.ng/bitstream": "^0.4.15", + "@thi.ng/errors": "^0.1.6" }, "keywords": [ "binary", @@ -42,4 +43,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/packages/rle-pack/src/index.ts b/packages/rle-pack/src/index.ts index 4466d5fd56..defc8fb8f8 100644 --- a/packages/rle-pack/src/index.ts +++ b/packages/rle-pack/src/index.ts @@ -1,6 +1,7 @@ import { BitInputStream, BitOutputStream } from "@thi.ng/bitstream"; +import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; -const RLE_SIZES = [3, 4, 8, 16]; +export type RLESizes = [number, number, number, number]; /** * Compresses input using dynamically sized RLE compression and returns @@ -8,22 +9,30 @@ const RLE_SIZES = [3, 4, 8, 16]; * * @param src * @param num number of input words - * @param wordSize in bits, MUST be <= 8 + * @param wordSize in bits, range 1 - 32 */ -export function encodeBytes(src: Iterable, num: number, wordSize = 8) { - const stream = new BitOutputStream(Math.ceil(num * wordSize / 8)).write(num, 32); +export function encode(src: Iterable, num: number, wordSize = 8, rleSizes: RLESizes = [3, 4, 8, 16]) { + (wordSize < 1 || wordSize > 32) && illegalArgs("word size (1-32 bits only)"); + const out = new BitOutputStream(Math.ceil(num * wordSize / 8) + 4 + 2 + 1) + .write(num, 32) + .write(wordSize, 5); + rleSizes.forEach((x) => { + (x < 1 || x > 16) && illegalArgs("RLE repeat size (1-16 bits only)"); + out.write(x - 1, 4); + }); + const [rle0, rle1, rle2, rle3] = rleSizes.map((x) => 1 << x); const n1 = num - 1; let val; let tail = true; let n = 0; let i = 0; const write = () => { - stream.write(n > 0 ? 1 : 0, 1); - stream.write(val, wordSize); + out.write(n > 0 ? 1 : 0, 1); + out.write(val, wordSize); if (n > 0) { - const t = (n < 0x8) ? 0 : (n < 0x10) ? 1 : (n < 0x100) ? 2 : 3; - stream.write(t, 2); - stream.write(n, RLE_SIZES[t]); + const t = (n < rle0) ? 0 : (n < rle1) ? 1 : (n < rle2) ? 2 : 3; + out.write(t, 2); + out.write(n, rleSizes[t]); n = 0; } }; @@ -34,37 +43,47 @@ export function encodeBytes(src: Iterable, num: number, wordSize = 8) { write(); val = x; } else { - if (++n === 0x10000) { + if (++n === rle3) { + n--; write(); tail = (i < n1); } } + if (i === n1) { + break; + } i++; } if (tail) { write(); } - return stream.bytes(); + return out.bytes(); } -export function decodeBytes(src: Uint8Array, wordSize = 8) { +export function decode(src: Uint8Array) { const input = new BitInputStream(src); - const ws1 = wordSize + 1; const num = input.read(32); - const out = new Uint8Array(num); - const flag = 1 << wordSize; - const mask = flag - 1; + const wordSize = input.read(5); + const rleSizes = [0, 0, 0, 0].map(() => input.read(4) + 1); + const out = arrayForWordSize(wordSize, num); let x, j; for (let i = 0; i < num;) { - x = input.read(ws1); - if (x & flag) { - j = i + 1 + input.read(RLE_SIZES[input.read(2)]); - out.fill(x & mask, i, j); + if (input.readBit()) { + x = input.read(wordSize); + j = i + 1 + input.read(rleSizes[input.read(2)]); + out.fill(x, i, j); i = j; } else { - out[i++] = x & mask; + out[i++] = input.read(wordSize); } } return out; } +const arrayForWordSize = (ws: number, n: number) => { + return new (ws < 9 ? + Uint8Array : + ws < 17 ? + Uint16Array : + Uint32Array)(n); +} \ No newline at end of file diff --git a/packages/rle-pack/test/index.ts b/packages/rle-pack/test/index.ts index a21dabb006..dfc7a225da 100644 --- a/packages/rle-pack/test/index.ts +++ b/packages/rle-pack/test/index.ts @@ -1,13 +1,18 @@ import * as assert from "assert"; -import { encodeBytes, decodeBytes } from "../src/index"; +import { encode, decode } from "../src/index"; + +const src = new Uint8Array(1024); +src.set([1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1], 512); describe("rle-pack", () => { it("3bit", () => { - const src = new Uint8Array(1024); - src.set([1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1], 512); - const packed = encodeBytes(src, src.length, 3); - assert.deepEqual(packed, [0, 0, 4, 0, 140, 7, 254, 73, 67, 177, 96, 87, 3, 98, 161, 201, 35, 1, 226]); - const dest = decodeBytes(packed, 3); + let packed = encode(src, src.length, 3); + assert.deepEqual(packed, [0, 0, 4, 0, 25, 27, 252, 96, 63, 242, 74, 29, 139, 2, 184, 27, 21, 14, 73, 24, 15, 16]); + let dest = decode(packed); + assert.deepEqual(dest, src); + packed = encode(src, src.length, 3, [1, 2, 4, 9]); + assert.deepEqual(packed, [0, 0, 4, 0, 24, 9, 196, 127, 249, 146, 158, 219, 10, 225, 182, 167, 153, 35, 241, 0]); + dest = decode(packed); assert.deepEqual(dest, src); }); }); From 40415217c408d069997742f951dedc59ff76878a Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 13:24:11 +0100 Subject: [PATCH 56/68] feat(rle-pack): further update data format (non-repeats) - successive non-repeat values are now chunked and waste less bits - fix wordSize header field (write size-1) - update tests --- packages/rle-pack/src/index.ts | 62 +++++++++++++++++++++++---------- packages/rle-pack/test/index.ts | 16 ++++----- 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/packages/rle-pack/src/index.ts b/packages/rle-pack/src/index.ts index defc8fb8f8..e6e5901bdd 100644 --- a/packages/rle-pack/src/index.ts +++ b/packages/rle-pack/src/index.ts @@ -10,42 +10,61 @@ export type RLESizes = [number, number, number, number]; * @param src * @param num number of input words * @param wordSize in bits, range 1 - 32 + * @param rleSizes run-length group sizes (in bits, max. 16) */ export function encode(src: Iterable, num: number, wordSize = 8, rleSizes: RLESizes = [3, 4, 8, 16]) { (wordSize < 1 || wordSize > 32) && illegalArgs("word size (1-32 bits only)"); const out = new BitOutputStream(Math.ceil(num * wordSize / 8) + 4 + 2 + 1) .write(num, 32) - .write(wordSize, 5); + .write(wordSize - 1, 5); rleSizes.forEach((x) => { (x < 1 || x > 16) && illegalArgs("RLE repeat size (1-16 bits only)"); out.write(x - 1, 4); }); const [rle0, rle1, rle2, rle3] = rleSizes.map((x) => 1 << x); + const chunk: number[] = []; const n1 = num - 1; let val; let tail = true; let n = 0; let i = 0; - const write = () => { - out.write(n > 0 ? 1 : 0, 1); + const writeRLE = () => { + const t = (n < rle0) ? 0 : (n < rle1) ? 1 : (n < rle2) ? 2 : 3; + out.writeBit(1); + out.write(t, 2); + out.write(n, rleSizes[t]); out.write(val, wordSize); - if (n > 0) { - const t = (n < rle0) ? 0 : (n < rle1) ? 1 : (n < rle2) ? 2 : 3; - out.write(t, 2); - out.write(n, rleSizes[t]); - n = 0; - } + n = 0; + }; + const writeChunk = () => { + const m = chunk.length - 1; + const t = (m < rle0) ? 0 : (m < rle1) ? 1 : (m < rle2) ? 2 : 3; + out.writeBit(0); + out.write(t, 2); + out.write(m, rleSizes[t]); + out.writeWords(chunk, wordSize); + chunk.length = 0; }; for (let x of src) { if (val === undefined) { val = x; } else if (x !== val) { - write(); + if (n > 0) { + writeRLE(); + } else { + chunk.push(val); + if (chunk.length === rle3) { + writeChunk(); + } + } val = x; } else { + if (chunk.length) { + writeChunk(); + } if (++n === rle3) { n--; - write(); + writeRLE(); tail = (i < n1); } } @@ -54,8 +73,11 @@ export function encode(src: Iterable, num: number, wordSize = 8, rleSize } i++; } - if (tail) { - write(); + if (chunk.length) { + chunk.push(val); + writeChunk(); + } else if (tail) { + writeRLE(); } return out.bytes(); } @@ -63,18 +85,20 @@ export function encode(src: Iterable, num: number, wordSize = 8, rleSize export function decode(src: Uint8Array) { const input = new BitInputStream(src); const num = input.read(32); - const wordSize = input.read(5); + const wordSize = input.read(5) + 1; const rleSizes = [0, 0, 0, 0].map(() => input.read(4) + 1); const out = arrayForWordSize(wordSize, num); let x, j; for (let i = 0; i < num;) { - if (input.readBit()) { - x = input.read(wordSize); - j = i + 1 + input.read(rleSizes[input.read(2)]); - out.fill(x, i, j); + x = input.readBit(); + j = i + 1 + input.read(rleSizes[input.read(2)]); + if (x) { + out.fill(input.read(wordSize), i, j); i = j; } else { - out[i++] = input.read(wordSize); + for (; i < j; i++) { + out[i] = input.read(wordSize); + } } } return out; diff --git a/packages/rle-pack/test/index.ts b/packages/rle-pack/test/index.ts index dfc7a225da..e5a312165b 100644 --- a/packages/rle-pack/test/index.ts +++ b/packages/rle-pack/test/index.ts @@ -1,18 +1,18 @@ import * as assert from "assert"; import { encode, decode } from "../src/index"; -const src = new Uint8Array(1024); -src.set([1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1], 512); +const src1k = new Uint8Array(1024); +src1k.set([1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1], 512); describe("rle-pack", () => { it("3bit", () => { - let packed = encode(src, src.length, 3); - assert.deepEqual(packed, [0, 0, 4, 0, 25, 27, 252, 96, 63, 242, 74, 29, 139, 2, 184, 27, 21, 14, 73, 24, 15, 16]); + let packed = encode(src1k, src1k.length, 3); + assert.deepEqual(packed, [0, 0, 4, 0, 17, 27, 255, 1, 255, 18, 24, 212, 78, 24, 5, 134, 68, 227, 82, 30, 3, 196, 0]); let dest = decode(packed); - assert.deepEqual(dest, src); - packed = encode(src, src.length, 3, [1, 2, 4, 9]); - assert.deepEqual(packed, [0, 0, 4, 0, 24, 9, 196, 127, 249, 146, 158, 219, 10, 225, 182, 167, 153, 35, 241, 0]); + assert.deepEqual(dest, src1k); + packed = encode(src1k, src1k.length, 3, [1, 2, 4, 9]); + assert.deepEqual(packed, [0, 0, 4, 0, 16, 9, 199, 255, 140, 134, 234, 206, 96, 89, 150, 119, 89, 15, 241, 0]); dest = decode(packed); - assert.deepEqual(dest, src); + assert.deepEqual(dest, src1k); }); }); From 1025996e7f3fb398a8d9a298ad9de56a02238b0d Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Fri, 24 Aug 2018 13:24:37 +0100 Subject: [PATCH 57/68] docs(rle-pack): update readme & diagram --- assets/dot/rle-layout.dot | 33 +++++++++++++++++++++-------- assets/rle-layout.png | Bin 29738 -> 55246 bytes packages/rle-pack/README.md | 40 ++++++++---------------------------- 3 files changed, 33 insertions(+), 40 deletions(-) diff --git a/assets/dot/rle-layout.dot b/assets/dot/rle-layout.dot index cf1fe6f962..6afaca09f3 100644 --- a/assets/dot/rle-layout.dot +++ b/assets/dot/rle-layout.dot @@ -1,31 +1,46 @@ digraph g { fontname=Inconsolata; rankdir=LR; - node[shape=square,width=1.5,fontname=Inconsolata]; + node[shape=square,width=1.75,fontname=Inconsolata]; subgraph cluster0 { - label="header"; + label="Header"; style="filled"; bgcolor="#eeeeee"; num[label="num values\n(32 bits)"]; - wordsize[label="word size\n(5 bits)"]; - rlesizes[label="RLE sizes\n(4x4 bits)"]; + wordsize[label="word size - 1\n(5 bits)"]; + rlesizes[label="RLE sizes - 1\n(4x4 bits)"]; } subgraph cluster1 { - label="each value"; + label="Data"; bgcolor="#cccccc"; flag[label="RLE flag\n(1 bit)"]; - val[label="value\n(word size)"]; + + subgraph cluster1a { + bgcolor="#aaaaaa"; + label="Non-repeat chunks"; + chunksizeid[label="size ID\n(2 bits)"]; + chunksize[label="chunk size - 1\n(variable)"]; + chunkval1[label="chunk val #1\n(word size)"]; + chunkvaln[label="chunk val #n\n(word size)"]; + } subgraph cluster1b { bgcolor="#aaaaaa"; - label="repeats only"; + label="RLE values only"; repeatid[label="repeat ID\n(2 bits)"]; - repeat[label="repeats\n(varying)"]; + rle[label="run length - 1\n(variable)"]; + val[label="value\n(word size)"]; } } - num -> wordsize -> rlesizes -> flag -> val -> repeatid -> repeat; + num -> wordsize -> rlesizes -> flag; + flag -> chunksizeid; //[label="0"]; + chunksizeid -> chunksize -> chunkval1; + chunkval1 -> chunkvaln[style=dotted]; + + flag -> repeatid; //[label="1"]; + repeatid -> rle -> val; } \ No newline at end of file diff --git a/assets/rle-layout.png b/assets/rle-layout.png index 7f02e4212c3fc0b6df8ef26ddd671a4a1b5cc991..8ec470a7eaa3a600e96bfd4a26ad78ed0f49f67c 100644 GIT binary patch literal 55246 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 xG>}_bRP%D~g(N((a2r&q}; zz}>BfHPtraYk6;4yIKD8nyfKA!VI>Tk!l1}1l6~V}uh^haRlZSu5(jhm6I^K`X6aVF*;H&E&Tlj0HsZof2|By%ePpiU>gg5j} zT{`F%OwnihK9-ZV1!S3M`b98jD87%o7pt085zf>U@h z?WTEpK8I$@c(oX|H)`a>sOWHf?JNV#s+Ku0Njj9vwAf#_Lf|aj>1a(8odil*;Y_>s zZ1c0Xr}DHb_>x&1i6p@$Pe0af)1Ox5-%~>@cDan;g(dTx_Fre7As5Rn#^lvP@IoK~ z8{x2;sJek$uXx+gLqWN&$&$L&6z7u}&(69#`cJIl%cfnsgNq6>ATcYuwM$XXTg5dY zi6#)hm_)Q!Y&c+rLBM~)DiJTF&mXzOPGRI&XO(2}?%>y~zKIuSnp>Zg zi_u!T=PdSC)9GS(n=HJCMt(m`vwh4Iyu|5KO}QgI1G7N9@7D70WT7!*H?mW;WNvVQ ziLu~$`VhQdf&H|pxO$S$XZ{lVTfxL5wXHpW%p?Ua(3BBu?mhX&^&eB_iEHA$Q&omo zO%2^DsTaUkw@&vM6>^-eWpM5ZjFQ={bzThP4%sNklrQU1f@`MGp8Jh+WQ zL3X>mlWl<=eX5*f9>Vw?kKUNFdfXy>?{q18EaBQKsEDRK;#rd8w~g;z+?gyZGtP-=YENeGEea63u0;a)T63%@4g9+G(WfRX+gRL`tZ{7U1{?R2$w|cE|Sc7@5 zPDE3n@o>l)43yj;Zho85I*rQ2|KjKr@}wX8#(o%PO=KQ=RQKw67BHcG>OjCW2CoG+Y z&o&C|*v|(-<@HE1s8!Njp}cL>4{uUsc&#Q+iX09Y`yTzeOPrA}aXjk{ zV;E8Erw68OxED8Okdg7lsbOEqFn0uPS6uaYx-Zr7TTwM~CDD{^)W9-w(v6LhQe&gI zW|p{Hpx!=1)*%-09}Xl?38&{50=Ur-V4w