@sc-voice/tools 3.33.0 → 3.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.mjs +7 -3
- package/package.json +14 -10
- package/src/defines.mjs +36 -7
- package/src/js/uuidv7.mjs +171 -0
- package/src/math/activation.mjs +1 -2
- package/src/math/fraction.mjs +97 -24
- package/src/math/hadamard.mjs +81 -0
- package/src/math/interval.mjs +2 -12
- package/src/math/units.mjs +230 -0
- package/src/text/bilara-path.mjs +1 -3
- package/src/text/color-console.mjs +129 -18
- package/src/text/list.mjs +1 -2
- package/src/text/merkle-json.mjs +2 -5
- package/src/text/sutta-central-id.mjs +4 -14
- package/src/text/tfidf-space.mjs +11 -15
- package/src/text/unicode.mjs +18 -0
- package/src/text/word-vector.mjs +2 -3
package/index.mjs
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { Assert } from './src/js/assert.mjs';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import UUIDV7 from './src/js/uuidv7.mjs';
|
|
3
|
+
export const JS = { Assert, UUIDV7,
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
import { Activation } from './src/math/activation.mjs';
|
|
7
7
|
import { Fraction } from './src/math/fraction.mjs';
|
|
8
|
+
import { Units } from './src/math/units.mjs';
|
|
8
9
|
import { Interval } from './src/math/interval.mjs';
|
|
10
|
+
import { Hadamard } from './src/math/hadamard.mjs';
|
|
9
11
|
|
|
10
12
|
export const ScvMath = {
|
|
11
13
|
Activation,
|
|
12
14
|
Fraction,
|
|
13
|
-
|
|
15
|
+
Hadamard,
|
|
16
|
+
Interval,
|
|
17
|
+
Units,
|
|
14
18
|
};
|
|
15
19
|
|
|
16
20
|
import { BilaraPath } from './src/text/bilara-path.mjs';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sc-voice/tools",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.35.0",
|
|
4
4
|
"description": "Utilities for SC-Voice",
|
|
5
5
|
"main": "index.mjs",
|
|
6
6
|
"files": [
|
|
@@ -11,29 +11,33 @@
|
|
|
11
11
|
"src"
|
|
12
12
|
],
|
|
13
13
|
"scripts": {
|
|
14
|
-
"test": "
|
|
15
|
-
"test:test": "
|
|
14
|
+
"test": "vitest run --config test/vitest.config.mjs",
|
|
15
|
+
"test:test": "vitest --config test/vitest.config.mjs"
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/sc-voice/
|
|
19
|
+
"url": "git+https://github.com/sc-voice/nx-scv.git"
|
|
20
20
|
},
|
|
21
21
|
"keywords": [
|
|
22
|
-
"SC-Voice
|
|
23
|
-
"
|
|
22
|
+
"SC-Voice",
|
|
23
|
+
"nx-scv",
|
|
24
|
+
"Tools",
|
|
24
25
|
"Javascript"
|
|
25
26
|
],
|
|
26
27
|
"author": "Karl Lew",
|
|
27
28
|
"license": "MIT",
|
|
28
29
|
"bugs": {
|
|
29
|
-
"url": "https://github.com/sc-voice/
|
|
30
|
+
"url": "https://github.com/sc-voice/nx-scv/issues"
|
|
30
31
|
},
|
|
31
|
-
"homepage": "https://github.com/sc-voice/tools
|
|
32
|
+
"homepage": "https://github.com/sc-voice/nx-scv/pkg/tools/#readme",
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@biomejs/biome": "1.9.4",
|
|
35
|
+
"avro-js": "^1.12.0",
|
|
34
36
|
"deepl-node": "^1.15.0",
|
|
35
37
|
"eslint": "^9.17.0",
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
+
"@sc-voice/vitest": "^4.0.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"uuid": "^11.1.0"
|
|
38
42
|
}
|
|
39
43
|
}
|
package/src/defines.mjs
CHANGED
|
@@ -1,20 +1,49 @@
|
|
|
1
|
+
const COLOR_CONSOLE = {
|
|
2
|
+
AS_STRING: 0,
|
|
3
|
+
INSPECT: 0,
|
|
4
|
+
SRC: 0,
|
|
5
|
+
TEST: 0,
|
|
6
|
+
PROPS_NEXT: 0,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const FRACTION = {
|
|
10
|
+
REDUCE: 0,
|
|
11
|
+
TEST: 0,
|
|
12
|
+
};
|
|
13
|
+
|
|
1
14
|
export const DBG = {
|
|
15
|
+
COLOR_CONSOLE,
|
|
16
|
+
FRACTION,
|
|
17
|
+
|
|
2
18
|
ALIGN_ALL: 0,
|
|
3
19
|
ALIGN_LINE: 0,
|
|
4
|
-
L2T_TO_STRING: 0,
|
|
5
|
-
COLOR_CONSOLE: 0,
|
|
6
|
-
C10E_INSPECT: 0,
|
|
7
|
-
I6L_CONTAINS: 0,
|
|
8
|
-
I6L_OVERLAPS: 0,
|
|
9
|
-
ML_DOC_VECTORS: 0, // 'mn8:3.4',
|
|
10
|
-
MN8_MOHAN: 0,
|
|
11
20
|
DEEPL_ADAPTER: 0,
|
|
12
21
|
DEEPL_MOCK: 0, // use mock-deepl
|
|
13
22
|
DEEPL_MOCK_XLT: 0, // use mock translation
|
|
14
23
|
DEEPL_TEST_API: 0, // test with live DeepL API ($$$)
|
|
15
24
|
DEEPL_XLT: 0, // test live translation
|
|
25
|
+
I6L_CONTAINS: 0,
|
|
26
|
+
I6L_OVERLAPS: 0,
|
|
27
|
+
L2T_TO_STRING: 0,
|
|
16
28
|
L7C_FETCH_LEGACY: 0,
|
|
17
29
|
L7C_FETCH_LEGACY_SC: 0, // ignore test cache and use SC
|
|
30
|
+
ML_DOC_VECTORS: 0, // 'mn8:3.4'
|
|
31
|
+
MN8_MOHAN: 0,
|
|
32
|
+
M2H: {
|
|
33
|
+
H6D: {
|
|
34
|
+
FWHT: 0,
|
|
35
|
+
ENCODE: 0,
|
|
36
|
+
DECODE: 0,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
18
39
|
W7E_BOW_OF_TEXT: 0,
|
|
19
40
|
WORD_MAP_TRANFORMER: 0,
|
|
41
|
+
S5H: {
|
|
42
|
+
U3S: {
|
|
43
|
+
CONVERT_FRACTION: 0,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
T2T: {
|
|
47
|
+
HADAMARD: 0,
|
|
48
|
+
},
|
|
20
49
|
};
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { randomBytes } from 'crypto';
|
|
2
|
+
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// MonotonicityState - Ensures successive UUIDs are always strictly increasing
|
|
5
|
+
// ============================================================================
|
|
6
|
+
|
|
7
|
+
class MonotonicityState {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.previousTimestamp = 0n;
|
|
10
|
+
this.sequence = 0;
|
|
11
|
+
this.offset = 0n;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
nextMillisWithSequence(timeIntervalMs) {
|
|
15
|
+
// Convert to BigInt if needed
|
|
16
|
+
const currentTime = BigInt(Math.floor(timeIntervalMs));
|
|
17
|
+
let currentMillis = currentTime + this.offset;
|
|
18
|
+
|
|
19
|
+
if (this.previousTimestamp === currentMillis) {
|
|
20
|
+
// Same millisecond: increment sequence counter
|
|
21
|
+
this.sequence += 1; // Don't mask yet - check for overflow
|
|
22
|
+
} else if (currentMillis < this.previousTimestamp) {
|
|
23
|
+
// Clock went backward: increment sequence and adjust offset
|
|
24
|
+
this.sequence += 1;
|
|
25
|
+
this.offset = this.previousTimestamp - currentMillis;
|
|
26
|
+
currentMillis = this.previousTimestamp;
|
|
27
|
+
} else {
|
|
28
|
+
// Time advanced: reset sequence
|
|
29
|
+
this.offset = 0n;
|
|
30
|
+
this.sequence = 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// If sequence overflows 12 bits, increment time and reset sequence
|
|
34
|
+
if (this.sequence > 0xFFF) {
|
|
35
|
+
this.sequence = 0;
|
|
36
|
+
currentMillis += 1n;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Now apply 12-bit mask for the returned value
|
|
40
|
+
const maskedSequence = this.sequence & 0xFFF;
|
|
41
|
+
|
|
42
|
+
this.previousTimestamp = currentMillis;
|
|
43
|
+
return { millis: currentMillis, sequence: maskedSequence };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Global monotonicity state (thread-safe via single JS event loop)
|
|
48
|
+
const monotonicityState = new MonotonicityState();
|
|
49
|
+
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// UUIDV7 Class
|
|
52
|
+
// ============================================================================
|
|
53
|
+
|
|
54
|
+
class UUIDV7 {
|
|
55
|
+
/**
|
|
56
|
+
* Creates a monotonically increasing UUIDV7.
|
|
57
|
+
* Two successive calls will always produce different, strictly increasing UUIDs.
|
|
58
|
+
*
|
|
59
|
+
* @returns {string} UUID in format: 019cc8b2-e91e-7000-8669-15ac4a704757
|
|
60
|
+
*/
|
|
61
|
+
static create() {
|
|
62
|
+
const now = Date.now(); // milliseconds since epoch
|
|
63
|
+
const { millis, sequence } = monotonicityState.nextMillisWithSequence(now);
|
|
64
|
+
|
|
65
|
+
// Generate random bytes for the UUID
|
|
66
|
+
const randomBuf = randomBytes(16); // Get 16 random bytes
|
|
67
|
+
|
|
68
|
+
// Build UUID bytes (16 bytes total)
|
|
69
|
+
const uuid = Buffer.alloc(16);
|
|
70
|
+
|
|
71
|
+
// Bytes 0-5: timestamp in milliseconds (48 bits)
|
|
72
|
+
// Convert BigInt to bytes in big-endian
|
|
73
|
+
const millisBigInt = millis;
|
|
74
|
+
uuid[0] = Number((millisBigInt >> 40n) & 0xFFn);
|
|
75
|
+
uuid[1] = Number((millisBigInt >> 32n) & 0xFFn);
|
|
76
|
+
uuid[2] = Number((millisBigInt >> 24n) & 0xFFn);
|
|
77
|
+
uuid[3] = Number((millisBigInt >> 16n) & 0xFFn);
|
|
78
|
+
uuid[4] = Number((millisBigInt >> 8n) & 0xFFn);
|
|
79
|
+
uuid[5] = Number(millisBigInt & 0xFFn);
|
|
80
|
+
|
|
81
|
+
// Bytes 6-8: 12-bit sequence counter + version + variant
|
|
82
|
+
// Place 12-bit sequence as UInt16 big-endian in bytes 6-7, then apply version/variant masks
|
|
83
|
+
// Sequence is 12 bits: bit11-bit0, represented as 0x0000-0x0FFF
|
|
84
|
+
// When converted to big-endian bytes:
|
|
85
|
+
// bytes[6] = (sequence >> 8) & 0xFF (contains bits 11-8 in lower nibble, upper bits are 0)
|
|
86
|
+
// bytes[7] = sequence & 0xFF (contains bits 7-0)
|
|
87
|
+
uuid[6] = ((sequence >> 8) & 0x0F) | 0x70; // Upper 4 bits of sequence + version 0x7
|
|
88
|
+
uuid[7] = sequence & 0xFF; // Lower 8 bits of sequence
|
|
89
|
+
|
|
90
|
+
// Bytes 9-15: random data
|
|
91
|
+
randomBuf.copy(uuid, 9, 0, 7); // Copy 7 bytes from randomBuf[0:7] to uuid[9:16]
|
|
92
|
+
|
|
93
|
+
// Byte 8: variant (2 bits) + remaining random bits
|
|
94
|
+
uuid[8] = (randomBuf[7] & 0x3F) | 0x80; // Keep lower 6 bits of random + variant 0b10
|
|
95
|
+
|
|
96
|
+
return bytesToUuidString(uuid);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Compare two UUIDs lexicographically.
|
|
101
|
+
* Returns: -1 if a < b, 0 if a === b, 1 if a > b
|
|
102
|
+
*
|
|
103
|
+
* @param {string} a - UUID
|
|
104
|
+
* @param {string} b - UUID
|
|
105
|
+
* @returns {number} -1, 0, or 1
|
|
106
|
+
*/
|
|
107
|
+
static compare(a, b) {
|
|
108
|
+
const aBytes = typeof a === 'string' ? uuidStringToBytes(a) : a;
|
|
109
|
+
const bBytes = typeof b === 'string' ? uuidStringToBytes(b) : b;
|
|
110
|
+
|
|
111
|
+
for (let i = 0; i < 16; i++) {
|
|
112
|
+
if (aBytes[i] < bBytes[i]) return -1;
|
|
113
|
+
if (aBytes[i] > bBytes[i]) return 1;
|
|
114
|
+
}
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Check if UUID a < UUID b
|
|
120
|
+
*
|
|
121
|
+
* @param {string} a - UUID
|
|
122
|
+
* @param {string} b - UUID
|
|
123
|
+
* @returns {boolean}
|
|
124
|
+
*/
|
|
125
|
+
static isLessThan(a, b) {
|
|
126
|
+
return UUIDV7.compare(a, b) < 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Check if UUID a > UUID b
|
|
131
|
+
*
|
|
132
|
+
* @param {string} a - UUID
|
|
133
|
+
* @param {string} b - UUID
|
|
134
|
+
* @returns {boolean}
|
|
135
|
+
*/
|
|
136
|
+
static isGreaterThan(a, b) {
|
|
137
|
+
return UUIDV7.compare(a, b) > 0;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export default UUIDV7;
|
|
142
|
+
|
|
143
|
+
// ============================================================================
|
|
144
|
+
// UUID String Formatting
|
|
145
|
+
// ============================================================================
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Convert UUID bytes to standard string format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
149
|
+
*/
|
|
150
|
+
function bytesToUuidString(bytes) {
|
|
151
|
+
const hex = bytes.toString('hex');
|
|
152
|
+
return [
|
|
153
|
+
hex.slice(0, 8),
|
|
154
|
+
hex.slice(8, 12),
|
|
155
|
+
hex.slice(12, 16),
|
|
156
|
+
hex.slice(16, 20),
|
|
157
|
+
hex.slice(20),
|
|
158
|
+
].join('-');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Convert UUID string to bytes.
|
|
163
|
+
*
|
|
164
|
+
* @param {string} uuidString - UUID in format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
165
|
+
* @returns {Buffer} 16 bytes
|
|
166
|
+
*/
|
|
167
|
+
function uuidStringToBytes(uuidString) {
|
|
168
|
+
const hex = uuidString.replace(/-/g, '');
|
|
169
|
+
return Buffer.from(hex, 'hex');
|
|
170
|
+
}
|
|
171
|
+
|
package/src/math/activation.mjs
CHANGED
|
@@ -59,8 +59,7 @@ export class Activation {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
static createRareN(a = 100, b = 1) {
|
|
62
|
-
let fEval = (x, a) =>
|
|
63
|
-
x < 1 ? 1 : 1 - Math.exp(((x - a) / x) * b);
|
|
62
|
+
let fEval = (x, a) => (x < 1 ? 1 : 1 - Math.exp(((x - a) / x) * b));
|
|
64
63
|
let dEval = (x, a) =>
|
|
65
64
|
x < 1 ? 0 : -(a * b * fEval(x, a, b)) / (x * x);
|
|
66
65
|
return new Activation({ a, b, fEval, dEval });
|
package/src/math/fraction.mjs
CHANGED
|
@@ -1,17 +1,41 @@
|
|
|
1
|
+
import { DBG } from '../defines.mjs';
|
|
2
|
+
import { ColorConsole } from '../text/color-console.mjs';
|
|
3
|
+
import { Unicode } from '../text/unicode.mjs';
|
|
4
|
+
const { CHECKMARK: UOK } = Unicode;
|
|
5
|
+
const { FRACTION: F6N } = DBG;
|
|
6
|
+
const { cc } = ColorConsole;
|
|
7
|
+
|
|
1
8
|
export class Fraction {
|
|
9
|
+
#isNull;
|
|
2
10
|
constructor(...args) {
|
|
3
|
-
//constructor(numerator, denominator = 1, units = undefined) {
|
|
4
11
|
const msg = 'Fraction.ctor:';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
12
|
+
let cfg = args[0];
|
|
13
|
+
let numerator;
|
|
14
|
+
let denominator;
|
|
15
|
+
let units;
|
|
16
|
+
let isNull;
|
|
17
|
+
|
|
18
|
+
if (cfg && typeof cfg === 'object') {
|
|
19
|
+
let { isNull: i4l, numerator: n, denominator: d, units: u } = cfg;
|
|
20
|
+
isNull = i4l;
|
|
21
|
+
numerator = n;
|
|
22
|
+
denominator = d;
|
|
23
|
+
units = u;
|
|
24
|
+
} else {
|
|
25
|
+
let [n, d = 1, u = ''] = args;
|
|
26
|
+
isNull = false;
|
|
27
|
+
numerator = n;
|
|
28
|
+
denominator = d;
|
|
29
|
+
units = u;
|
|
8
30
|
}
|
|
9
|
-
let [numerator, denominator = 1, units = undefined] = args;
|
|
10
31
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
32
|
+
this.put({ isNull, numerator, denominator, units });
|
|
33
|
+
|
|
34
|
+
Object.defineProperty(this, 'isNull', {
|
|
35
|
+
enumerable: true,
|
|
36
|
+
get() {
|
|
37
|
+
return this.#isNull;
|
|
38
|
+
},
|
|
15
39
|
});
|
|
16
40
|
}
|
|
17
41
|
|
|
@@ -22,6 +46,29 @@ export class Fraction {
|
|
|
22
46
|
return Fraction.gcd(b, a % b);
|
|
23
47
|
}
|
|
24
48
|
|
|
49
|
+
put(json = {}) {
|
|
50
|
+
let { isNull, numerator, denominator = 1, units = '' } = json;
|
|
51
|
+
|
|
52
|
+
if (isNull || numerator == null) {
|
|
53
|
+
this.#isNull = true;
|
|
54
|
+
numerator = 0;
|
|
55
|
+
denominator = 1;
|
|
56
|
+
} else {
|
|
57
|
+
this.#isNull = false;
|
|
58
|
+
}
|
|
59
|
+
Object.assign(this, { numerator, denominator, units });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
patch(json = {}) {
|
|
63
|
+
let {
|
|
64
|
+
numerator = this.n,
|
|
65
|
+
denominator = this.d,
|
|
66
|
+
units = this.units,
|
|
67
|
+
} = json;
|
|
68
|
+
|
|
69
|
+
this.put({ numerator, denominator, units });
|
|
70
|
+
}
|
|
71
|
+
|
|
25
72
|
get remainder() {
|
|
26
73
|
let { n, d } = this;
|
|
27
74
|
|
|
@@ -54,8 +101,8 @@ export class Fraction {
|
|
|
54
101
|
}
|
|
55
102
|
|
|
56
103
|
get value() {
|
|
57
|
-
let { numerator, denominator } = this;
|
|
58
|
-
return numerator / denominator;
|
|
104
|
+
let { isNull, numerator, denominator } = this;
|
|
105
|
+
return isNull ? null : numerator / denominator;
|
|
59
106
|
}
|
|
60
107
|
|
|
61
108
|
increment(delta = 1) {
|
|
@@ -64,6 +111,8 @@ export class Fraction {
|
|
|
64
111
|
}
|
|
65
112
|
|
|
66
113
|
reduce() {
|
|
114
|
+
const msg = 'f6n.reduce';
|
|
115
|
+
const dbg = F6N.REDUCE;
|
|
67
116
|
let { numerator: n, denominator: d, units } = this;
|
|
68
117
|
if (Number.isInteger(n) && Number.isInteger(d)) {
|
|
69
118
|
let g = Fraction.gcd(n, d);
|
|
@@ -71,22 +120,46 @@ export class Fraction {
|
|
|
71
120
|
this.numerator /= g;
|
|
72
121
|
this.denominator /= g;
|
|
73
122
|
}
|
|
123
|
+
dbg && cc.ok1(msg + UOK, this.n, '/', this.d);
|
|
124
|
+
} else {
|
|
125
|
+
// Is this useful?
|
|
126
|
+
for (let i = 0; i < 20; i++) {
|
|
127
|
+
n *= 10;
|
|
128
|
+
d *= 10;
|
|
129
|
+
if (Number.isInteger(n) && Number.isInteger(d)) {
|
|
130
|
+
this.n = n;
|
|
131
|
+
this.d = d;
|
|
132
|
+
this.reduce();
|
|
133
|
+
dbg && cc.ok1(msg + UOK, n, '/', d);
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
throw new Error(
|
|
138
|
+
`${msg} Why are you reducing non-integers? ${n}/${d}`,
|
|
139
|
+
);
|
|
74
140
|
}
|
|
75
141
|
return this;
|
|
76
142
|
}
|
|
77
143
|
|
|
78
|
-
toString() {
|
|
79
|
-
let { units, numerator: n, denominator: d, value } = this;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
144
|
+
toString(cfg = {}) {
|
|
145
|
+
let { isNull, units, numerator: n, denominator: d, value } = this;
|
|
146
|
+
let s;
|
|
147
|
+
if (isNull) {
|
|
148
|
+
s = '?';
|
|
149
|
+
} else {
|
|
150
|
+
let { asRange, fixed = 2 } = cfg;
|
|
151
|
+
if (asRange == null) {
|
|
152
|
+
let sFraction = `${n}/${d}`;
|
|
153
|
+
let sValue = value.toString();
|
|
154
|
+
let sFixed = value.toFixed(fixed);
|
|
155
|
+
s = sValue.length < sFixed.length ? sValue : sFixed;
|
|
156
|
+
s = s.length < sFraction.length ? s : sFraction;
|
|
157
|
+
} else {
|
|
158
|
+
let sRange = `${n}${asRange}${d}`;
|
|
159
|
+
s = sRange;
|
|
160
|
+
}
|
|
86
161
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return units ? `${s} ${units}` : s;
|
|
162
|
+
return units ? `${s}${units}` : s;
|
|
90
163
|
}
|
|
91
164
|
|
|
92
165
|
add(f) {
|
|
@@ -94,9 +167,9 @@ export class Fraction {
|
|
|
94
167
|
let { numerator: n1, denominator: d1, units: u1 } = this;
|
|
95
168
|
let { numerator: n2, denominator: d2, units: u2 } = f;
|
|
96
169
|
if (this.units !== f.units) {
|
|
97
|
-
throw new Error(`${msg} units? ${u1}
|
|
170
|
+
throw new Error(`${msg} units? "${u1}" vs. "${u2}"`);
|
|
98
171
|
}
|
|
99
172
|
|
|
100
|
-
return new
|
|
173
|
+
return new this.constructor(n1 * d2 + n2 * d1, d1 * d2).reduce();
|
|
101
174
|
}
|
|
102
175
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { DBG } from '../defines.mjs';
|
|
2
|
+
import { ColorConsole } from '../text/color-console.mjs';
|
|
3
|
+
import { Unicode } from '../text/unicode.mjs';
|
|
4
|
+
const { CHECKMARK: UOK } = Unicode;
|
|
5
|
+
const { H6D } = DBG.M2H;
|
|
6
|
+
const { cc } = ColorConsole;
|
|
7
|
+
|
|
8
|
+
const SQRT2 = Math.sqrt(2);
|
|
9
|
+
|
|
10
|
+
export class Hadamard {
|
|
11
|
+
static #ctor = false;
|
|
12
|
+
constructor(cfg = {}) {
|
|
13
|
+
const msg = 'h6d.ctor:';
|
|
14
|
+
if (!Hadamard.#ctor) {
|
|
15
|
+
throw new Error(`${msg} try: encode(signal)`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
Object.assign(this, cfg);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static fwht(input) {
|
|
22
|
+
// Fast Walsh-Hadamard Transform
|
|
23
|
+
const msg = 'h6d.fwht';
|
|
24
|
+
const dbg = H6D.FWHT;
|
|
25
|
+
const length = input.length;
|
|
26
|
+
let h = 1;
|
|
27
|
+
let scale = 1;
|
|
28
|
+
let output = [...input];
|
|
29
|
+
dbg && cc.ok(msg, 'input:', ...input);
|
|
30
|
+
while (h < length) {
|
|
31
|
+
let hNext = h * 2;
|
|
32
|
+
for (let i = 0; i < length; i += hNext) {
|
|
33
|
+
for (let j = i; j < i + h; j++) {
|
|
34
|
+
let x = output[j];
|
|
35
|
+
let y = output[j + h];
|
|
36
|
+
output[j] = x + y;
|
|
37
|
+
output[j + h] = x - y;
|
|
38
|
+
dbg > 2 &&
|
|
39
|
+
cc.fyi(msg, { h, length, i, j, ih: i + h, jh: j + h });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
dbg > 1 && cc.ok(msg, 'h:', h, 'output:', ...output);
|
|
43
|
+
output = output.map((v) => v / SQRT2);
|
|
44
|
+
h = hNext;
|
|
45
|
+
}
|
|
46
|
+
dbg && cc.ok1(msg + UOK, 'output:', ...output);
|
|
47
|
+
|
|
48
|
+
return output;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static encode(signal) {
|
|
52
|
+
const msg = 'h6d.encode';
|
|
53
|
+
const dbg = H6D.ENCODE;
|
|
54
|
+
let length = signal.length;
|
|
55
|
+
let n = Math.ceil(Math.log2(length));
|
|
56
|
+
let fullLength = Math.pow(2, n);
|
|
57
|
+
let zeros = new Array(fullLength - length).fill(0);
|
|
58
|
+
let input = [...signal, ...zeros];
|
|
59
|
+
let output = Hadamard.fwht(input);
|
|
60
|
+
|
|
61
|
+
let h6d;
|
|
62
|
+
try {
|
|
63
|
+
Hadamard.#ctor = true;
|
|
64
|
+
h6d = new Hadamard({ length, signal: output });
|
|
65
|
+
} finally {
|
|
66
|
+
Hadamard.#ctor = false;
|
|
67
|
+
}
|
|
68
|
+
dbg > 1 && cc.ok(msg, 'output:', ...output);
|
|
69
|
+
dbg && cc.ok1(msg, { length, n, fullLength });
|
|
70
|
+
return h6d;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
decode() {
|
|
74
|
+
const msg = 'h6d.decode';
|
|
75
|
+
const dbg = H6D.DECODE;
|
|
76
|
+
let { length, signal } = this;
|
|
77
|
+
let output = Hadamard.fwht(signal).slice(0, length);
|
|
78
|
+
dbg && cc.ok1(msg + UOK, ...output);
|
|
79
|
+
return output;
|
|
80
|
+
}
|
|
81
|
+
}
|
package/src/math/interval.mjs
CHANGED
|
@@ -170,18 +170,8 @@ export class Interval {
|
|
|
170
170
|
overlaps(iv2) {
|
|
171
171
|
const msg = 'i6l.overlaps';
|
|
172
172
|
const dbg = DBG.I6L_OVERLAPS;
|
|
173
|
-
let {
|
|
174
|
-
|
|
175
|
-
hi: hi1,
|
|
176
|
-
leftOpen: lOpen1,
|
|
177
|
-
rightOpen: rOpen1,
|
|
178
|
-
} = this;
|
|
179
|
-
let {
|
|
180
|
-
lo: lo2,
|
|
181
|
-
hi: hi2,
|
|
182
|
-
leftOpen: lOpen2,
|
|
183
|
-
rightOpen: rOpen2,
|
|
184
|
-
} = iv2;
|
|
173
|
+
let { lo: lo1, hi: hi1, leftOpen: lOpen1, rightOpen: rOpen1 } = this;
|
|
174
|
+
let { lo: lo2, hi: hi2, leftOpen: lOpen2, rightOpen: rOpen2 } = iv2;
|
|
185
175
|
|
|
186
176
|
//console.log(msg, {lo1, lo2, hi1, hi2});
|
|
187
177
|
if (!lOpen1 && iv2.contains(lo1)) {
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { DBG } from '../../src/defines.mjs';
|
|
2
|
+
const { U3S } = DBG.S5H;
|
|
3
|
+
import { Unicode } from '../text/unicode.mjs';
|
|
4
|
+
import { Fraction } from './fraction.mjs';
|
|
5
|
+
const { CHECKMARK: UOK, RIGHT_ARROW: URA } = Unicode;
|
|
6
|
+
import { ColorConsole } from '../text/color-console.mjs';
|
|
7
|
+
const { cc } = ColorConsole;
|
|
8
|
+
|
|
9
|
+
const DEFAULT_LENGTH = {
|
|
10
|
+
in: {
|
|
11
|
+
aliases: ['inch'],
|
|
12
|
+
from: {
|
|
13
|
+
ft: [12, 0, 0, 1],
|
|
14
|
+
mm: [10, 0, 0, 254],
|
|
15
|
+
cm: [100, 0, 0, 254],
|
|
16
|
+
m: [100 * 100, 0, 0, 254],
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
ft: {
|
|
20
|
+
aliases: ['foot', 'feet'],
|
|
21
|
+
from: {
|
|
22
|
+
in: [1, 0, 0, 12],
|
|
23
|
+
mm: [100, 0, 0, 10 * 254 * 12],
|
|
24
|
+
cm: [100, 0, 0, 254 * 12],
|
|
25
|
+
m: [100 * 100, 0, 0, 254 * 12],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
m: {
|
|
29
|
+
aliases: ['meter', 'metre'],
|
|
30
|
+
from: {
|
|
31
|
+
mm: [1, 0, 0, 1000],
|
|
32
|
+
cm: [1, 0, 0, 100],
|
|
33
|
+
ft: [12 * 254, 0, 0, 100 * 100],
|
|
34
|
+
in: [254, 0, 0, 100 * 100],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
cm: {
|
|
38
|
+
aliases: ['centimeter', 'centimetre'],
|
|
39
|
+
from: {
|
|
40
|
+
in: [254, 0, 0, 100],
|
|
41
|
+
ft: [12 * 254, 0, 0, 100],
|
|
42
|
+
mm: [1, 0, 0, 10],
|
|
43
|
+
m: [1, 0, 0, 100],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
mm: {
|
|
47
|
+
aliases: ['millimeter', 'millimetre'],
|
|
48
|
+
},
|
|
49
|
+
}; // DEFAULT_LENGTH
|
|
50
|
+
|
|
51
|
+
const DEFAULT_TEMPERATURE = {
|
|
52
|
+
F: {
|
|
53
|
+
aliases: ['Fahrenheit'],
|
|
54
|
+
from: {
|
|
55
|
+
C: [9, 160, 0, 5],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
C: {
|
|
59
|
+
aliases: ['Centigrade'],
|
|
60
|
+
from: {
|
|
61
|
+
F: [5, -5 * 32, 0, 9],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const DEFAULT_TIME = {
|
|
67
|
+
ms: {
|
|
68
|
+
aliases: ['millisecond', 'milliseconds'],
|
|
69
|
+
from: {
|
|
70
|
+
s: [1000, 0, 0, 1],
|
|
71
|
+
min: [60 * 1000, 0, 0, 1],
|
|
72
|
+
h: [60 * 60 * 1000, 0, 0, 1],
|
|
73
|
+
d: [24 * 60 * 60 * 1000, 0, 0, 1],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
s: {
|
|
77
|
+
aliases: ['seconds'],
|
|
78
|
+
from: {
|
|
79
|
+
ms: [1, 0, 0, 1000],
|
|
80
|
+
min: [60, 0, 0, 1],
|
|
81
|
+
h: [60 * 60, 0, 0, 1],
|
|
82
|
+
d: [24 * 60 * 60, 0, 0, 1],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
min: {
|
|
86
|
+
aliases: ['minutes'],
|
|
87
|
+
from: {
|
|
88
|
+
ms: [1, 0, 0, 60 * 1000],
|
|
89
|
+
s: [1, 0, 0, 60],
|
|
90
|
+
h: [60, 0, 0, 1],
|
|
91
|
+
d: [24 * 60, 0, 0, 1],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
h: {
|
|
95
|
+
aliases: ['hour', 'hours', 'hr'],
|
|
96
|
+
from: {
|
|
97
|
+
ms: [1, 0, 0, 60 * 60 * 1000],
|
|
98
|
+
s: [1, 0, 0, 60 * 60],
|
|
99
|
+
min: [1, 0, 0, 60],
|
|
100
|
+
d: [24, 0, 0, 1],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
d: {
|
|
104
|
+
aliases: ['day', 'days'],
|
|
105
|
+
from: {
|
|
106
|
+
ms: [1, 0, 0, 24 * 60 * 60 * 1000],
|
|
107
|
+
s: [1, 0, 0, 24 * 60 * 60],
|
|
108
|
+
min: [1, 0, 0, 24 * 60],
|
|
109
|
+
h: [1, 0, 0, 24],
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
}; // DEFAULT_TIME
|
|
113
|
+
|
|
114
|
+
const G_OZ = new Fraction(10000000000, 352739619);
|
|
115
|
+
|
|
116
|
+
const DEFAULT_WEIGHT = {
|
|
117
|
+
mg: {
|
|
118
|
+
aliases: ['milligram', 'milligrams'],
|
|
119
|
+
from: {
|
|
120
|
+
kg: [1000 * 1000, 0, 0, 1],
|
|
121
|
+
g: [1000, 0, 0, 1],
|
|
122
|
+
oz: [G_OZ.n * 1000, 0, 0, G_OZ.d],
|
|
123
|
+
lb: [16 * G_OZ.n * 1000, 0, 0, G_OZ.d],
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
g: {
|
|
127
|
+
aliases: ['gram', 'grams'],
|
|
128
|
+
from: {
|
|
129
|
+
kg: [1000, 0, 0, 1],
|
|
130
|
+
mg: [1, 0, 0, 1000],
|
|
131
|
+
oz: [G_OZ.n, 0, 0, G_OZ.d],
|
|
132
|
+
lb: [16 * G_OZ.n, 0, 0, G_OZ.d],
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
kg: {
|
|
136
|
+
aliases: ['kilogram', 'kilograms'],
|
|
137
|
+
from: {
|
|
138
|
+
g: [1, 0, 0, 1000],
|
|
139
|
+
mg: [1, 0, 0, 1000 * 1000],
|
|
140
|
+
oz: [G_OZ.n, 0, 0, 1000 * G_OZ.d],
|
|
141
|
+
lb: [16 * G_OZ.n, 0, 0, 1000 * G_OZ.d],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
oz: {
|
|
145
|
+
aliases: ['ounce', 'ounces'],
|
|
146
|
+
from: {
|
|
147
|
+
g: [G_OZ.d, 0, 0, G_OZ.n],
|
|
148
|
+
kg: [G_OZ.d * 1000, 0, 0, G_OZ.n],
|
|
149
|
+
lb: [16, 0, 0, 1],
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
lb: {
|
|
153
|
+
aliases: ['pound', 'pounds', 'lbs'],
|
|
154
|
+
from: {
|
|
155
|
+
oz: [1, 0, 0, 16],
|
|
156
|
+
g: [G_OZ.d, 0, 0, 16 * G_OZ.n],
|
|
157
|
+
kg: [1000 * G_OZ.d, 0, 0, 16 * G_OZ.n],
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const DEFAULT_UNITS = Object.assign(
|
|
163
|
+
{},
|
|
164
|
+
DEFAULT_LENGTH,
|
|
165
|
+
DEFAULT_TEMPERATURE,
|
|
166
|
+
DEFAULT_TIME,
|
|
167
|
+
DEFAULT_WEIGHT,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
export class Units {
|
|
171
|
+
#abbrMap;
|
|
172
|
+
#unitMap;
|
|
173
|
+
constructor(cfg = {}) {
|
|
174
|
+
let { unitMap = DEFAULT_UNITS } = cfg;
|
|
175
|
+
this.#unitMap = unitMap;
|
|
176
|
+
this.#abbrMap = Object.entries(unitMap).reduce((a, entry) => {
|
|
177
|
+
const [abbr, def] = entry;
|
|
178
|
+
const { aliases } = def;
|
|
179
|
+
a[abbr] = abbr;
|
|
180
|
+
aliases.forEach((n) => {
|
|
181
|
+
a[n] = abbr;
|
|
182
|
+
});
|
|
183
|
+
return a;
|
|
184
|
+
}, {});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
abbreviation(unit) {
|
|
188
|
+
let d9t = this.#abbrMap[unit];
|
|
189
|
+
return d9t == null ? unit : d9t;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
convertFraction(vSrc) {
|
|
193
|
+
const msg = 'u3s.convertFraction';
|
|
194
|
+
const dbg = U3S.CONVERT_FRACTION;
|
|
195
|
+
let { n, d, units: uSrc } = vSrc;
|
|
196
|
+
let srcAbbr = this.abbreviation(uSrc);
|
|
197
|
+
let convertTo = (uDst) => {
|
|
198
|
+
let dstAbbr = this.abbreviation(uDst);
|
|
199
|
+
let vDst;
|
|
200
|
+
if (dstAbbr === srcAbbr) {
|
|
201
|
+
vDst = new Fraction(n, d, uDst);
|
|
202
|
+
dbg && cc.ok1(msg + 1 + UOK, vSrc, URA, vDst);
|
|
203
|
+
} else {
|
|
204
|
+
let dstBase = this.#unitMap[dstAbbr];
|
|
205
|
+
let srcMatrix = dstBase?.from?.[srcAbbr];
|
|
206
|
+
if (srcMatrix) {
|
|
207
|
+
let nDst = srcMatrix[0] * n + srcMatrix[1] * d;
|
|
208
|
+
let dDst = srcMatrix[2] * n + srcMatrix[3] * d;
|
|
209
|
+
vDst = new Fraction(nDst, dDst, uDst).reduce();
|
|
210
|
+
dbg && cc.ok1(msg + 2 + UOK, vSrc, URA, vDst);
|
|
211
|
+
} // srcMatrix
|
|
212
|
+
} // dstAbbr !== srcAbbr
|
|
213
|
+
if (vDst == null) {
|
|
214
|
+
vDst = vSrc;
|
|
215
|
+
dbg && cc.ok1(msg + 3 + UOK, vSrc, URA, vDst);
|
|
216
|
+
}
|
|
217
|
+
return vDst;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
return { to: convertTo };
|
|
221
|
+
} // convertFraction
|
|
222
|
+
|
|
223
|
+
convert(value) {
|
|
224
|
+
if (value instanceof Fraction) {
|
|
225
|
+
return this.convertFraction(value);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
throw new Error(`value?${value}`);
|
|
229
|
+
} // convert
|
|
230
|
+
} // Units
|
package/src/text/bilara-path.mjs
CHANGED
|
@@ -6,9 +6,7 @@ export class BilaraPath {
|
|
|
6
6
|
static htmlPath(mid) {
|
|
7
7
|
let lang = 'pli';
|
|
8
8
|
let auth = 'ms';
|
|
9
|
-
return ['html', lang, `${auth}/sutta`, `${mid}_html.json`].join(
|
|
10
|
-
'/',
|
|
11
|
-
);
|
|
9
|
+
return ['html', lang, `${auth}/sutta`, `${mid}_html.json`].join('/');
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
static variantPath(mid) {
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import util from 'node:util';
|
|
2
|
+
import { DBG } from '../defines.mjs';
|
|
2
3
|
import { Unicode } from './unicode.mjs';
|
|
4
|
+
const { COLOR_CONSOLE: C10E } = DBG;
|
|
5
|
+
|
|
6
|
+
const { RED_X: URX, CHECKMARK: UOK } = Unicode;
|
|
3
7
|
|
|
4
8
|
const {
|
|
5
9
|
BLACK,
|
|
@@ -23,6 +27,74 @@ const {
|
|
|
23
27
|
|
|
24
28
|
let CC;
|
|
25
29
|
|
|
30
|
+
class Props {
|
|
31
|
+
constructor(obj) {
|
|
32
|
+
let entries = Object.entries(obj);
|
|
33
|
+
|
|
34
|
+
Object.assign(this, {
|
|
35
|
+
obj,
|
|
36
|
+
entries,
|
|
37
|
+
i: 0,
|
|
38
|
+
done: false,
|
|
39
|
+
value: undefined,
|
|
40
|
+
key: undefined,
|
|
41
|
+
emitKey: true,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
[Symbol.iterator]() {
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
next() {
|
|
50
|
+
const msg = 'p3s.next';
|
|
51
|
+
const dbg = C10E.PROPS_NEXT;
|
|
52
|
+
let { entries, i, emitKey, done } = this;
|
|
53
|
+
let value;
|
|
54
|
+
let entry = entries[i];
|
|
55
|
+
if (i < entries.length) {
|
|
56
|
+
if (emitKey) {
|
|
57
|
+
value = entry[0] + ':';
|
|
58
|
+
} else {
|
|
59
|
+
value = entry[1];
|
|
60
|
+
dbg > 1 && CC.ok(msg, 'emitKey', value);
|
|
61
|
+
switch (typeof value) {
|
|
62
|
+
case 'object': {
|
|
63
|
+
if (value instanceof Array) {
|
|
64
|
+
dbg > 1 && CC.ok(msg, 'Array', value);
|
|
65
|
+
value = value === null ? null : JSON.stringify(value);
|
|
66
|
+
} else if (value && value.toString !== {}.toString) {
|
|
67
|
+
dbg > 1 && CC.ok(msg, 'toString', value);
|
|
68
|
+
value = value.toString();
|
|
69
|
+
} else {
|
|
70
|
+
dbg > 1 && CC.ok(msg, 'object', value);
|
|
71
|
+
value = value === null ? null : JSON.stringify(value);
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case 'function':
|
|
76
|
+
dbg > 1 && CC.ok(msg, 'function', value);
|
|
77
|
+
value = `[Function ${value.name}]`;
|
|
78
|
+
break;
|
|
79
|
+
default:
|
|
80
|
+
dbg > 1 && CC.ok(msg, 'default', value);
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!emitKey) {
|
|
85
|
+
this.i++;
|
|
86
|
+
}
|
|
87
|
+
this.emitKey = !this.emitKey;
|
|
88
|
+
} else {
|
|
89
|
+
done = true;
|
|
90
|
+
}
|
|
91
|
+
this.value = value;
|
|
92
|
+
dbg && CC.ok1(msg + UOK, { done, value });
|
|
93
|
+
|
|
94
|
+
return { done, value };
|
|
95
|
+
}
|
|
96
|
+
} // Props
|
|
97
|
+
|
|
26
98
|
export class ColorConsole {
|
|
27
99
|
constructor(opts = {}) {
|
|
28
100
|
let {
|
|
@@ -58,6 +130,14 @@ export class ColorConsole {
|
|
|
58
130
|
});
|
|
59
131
|
}
|
|
60
132
|
|
|
133
|
+
static get URX() {
|
|
134
|
+
return URX;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static get UOK() {
|
|
138
|
+
return UOK;
|
|
139
|
+
}
|
|
140
|
+
|
|
61
141
|
static get cc() {
|
|
62
142
|
CC = CC || new ColorConsole();
|
|
63
143
|
return CC;
|
|
@@ -102,6 +182,10 @@ export class ColorConsole {
|
|
|
102
182
|
}
|
|
103
183
|
}
|
|
104
184
|
|
|
185
|
+
props(obj) {
|
|
186
|
+
return new Props(obj);
|
|
187
|
+
}
|
|
188
|
+
|
|
105
189
|
writeColor(color, rest) {
|
|
106
190
|
let { styles, defaultOptions } = util?.inspect || {};
|
|
107
191
|
if (styles) {
|
|
@@ -136,31 +220,60 @@ export class ColorConsole {
|
|
|
136
220
|
tf = thing;
|
|
137
221
|
}
|
|
138
222
|
|
|
139
|
-
let v = this.
|
|
223
|
+
let v = this.asString(thing);
|
|
140
224
|
let color = tf ? this.okColor2 : this.badColor2;
|
|
141
225
|
return color + v;
|
|
142
226
|
}
|
|
143
227
|
|
|
144
|
-
|
|
145
|
-
const msg = 'c10e.
|
|
146
|
-
|
|
228
|
+
asString(thing) {
|
|
229
|
+
const msg = 'c10e.asString';
|
|
230
|
+
const dbg = C10E.AS_STRING;
|
|
231
|
+
let { okColor1, okColor2, precision } = this;
|
|
232
|
+
dbg > 2 && console.log(okColor2, msg, 'thing:', thing);
|
|
147
233
|
switch (typeof thing) {
|
|
148
234
|
case 'undefined':
|
|
149
235
|
return 'undefined';
|
|
150
236
|
case 'object': {
|
|
151
237
|
if (thing == null) {
|
|
238
|
+
dbg > 1 && console.log(okColor2, msg, 'null');
|
|
152
239
|
return '' + thing;
|
|
153
240
|
}
|
|
154
241
|
if (thing instanceof Date) {
|
|
155
242
|
return this.dateFormat.format(thing);
|
|
156
243
|
}
|
|
157
|
-
|
|
158
|
-
thing.
|
|
159
|
-
|
|
160
|
-
|
|
244
|
+
let ownToString =
|
|
245
|
+
typeof thing.toString === 'function' &&
|
|
246
|
+
thing.toString !== Array.prototype.toString &&
|
|
247
|
+
thing.toString !== Object.prototype.toString;
|
|
248
|
+
dbg > 1 && this.ok(okColor2, msg, 'ownToString:', ownToString);
|
|
249
|
+
if (ownToString) {
|
|
250
|
+
let s = thing.toString();
|
|
251
|
+
dbg > 1 && this.ok(okColor2, msg, 'ownToString1:', s);
|
|
161
252
|
return thing.toString();
|
|
162
253
|
}
|
|
163
|
-
|
|
254
|
+
if (thing instanceof Array) {
|
|
255
|
+
let s =
|
|
256
|
+
'[' +
|
|
257
|
+
thing.map((item) => this.asString(item)).join(', ') +
|
|
258
|
+
']';
|
|
259
|
+
dbg > 1 && this.ok(okColor2, msg, 'array:', s);
|
|
260
|
+
return s;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Generic Object
|
|
264
|
+
let sEntries = Object.entries(thing)
|
|
265
|
+
.map((kv) => kv[0] + ':' + this.asString(kv[1]))
|
|
266
|
+
.join(', ');
|
|
267
|
+
let cname = thing.constructor?.name;
|
|
268
|
+
if (cname === 'Object') {
|
|
269
|
+
cname = '';
|
|
270
|
+
} else if (cname === 'anonymous') {
|
|
271
|
+
cname = Unicode.INVERSE_BULLET;
|
|
272
|
+
}
|
|
273
|
+
let s = cname + '{' + sEntries + '}';
|
|
274
|
+
dbg > 1 &&
|
|
275
|
+
console.log(okColor2, msg, { ownToString }, 'object:', s);
|
|
276
|
+
return s;
|
|
164
277
|
}
|
|
165
278
|
case 'string':
|
|
166
279
|
return thing;
|
|
@@ -171,10 +284,13 @@ export class ColorConsole {
|
|
|
171
284
|
}
|
|
172
285
|
return v;
|
|
173
286
|
}
|
|
287
|
+
case 'function': {
|
|
288
|
+
return thing.name;
|
|
289
|
+
}
|
|
174
290
|
default:
|
|
175
291
|
return JSON.stringify(thing);
|
|
176
292
|
}
|
|
177
|
-
} //
|
|
293
|
+
} // asString
|
|
178
294
|
|
|
179
295
|
color(textColor, ...things) {
|
|
180
296
|
let { valueColor } = this;
|
|
@@ -184,20 +300,15 @@ export class ColorConsole {
|
|
|
184
300
|
let eol;
|
|
185
301
|
return things.reduce((a, thing) => {
|
|
186
302
|
let newLabel = '';
|
|
187
|
-
let v = this.
|
|
303
|
+
let v = this.asString(thing);
|
|
188
304
|
let aLast = a.at(-1);
|
|
189
|
-
if (
|
|
190
|
-
typeof aLast === 'string' &&
|
|
191
|
-
aLast.endsWith('\n' + endColor)
|
|
192
|
-
) {
|
|
305
|
+
if (typeof aLast === 'string' && aLast.endsWith('\n' + endColor)) {
|
|
193
306
|
if (aLast === textColor + '\n' + endColor) {
|
|
194
307
|
a.pop();
|
|
195
308
|
} else {
|
|
196
309
|
const iLast = aLast.lastIndexOf('\n');
|
|
197
310
|
a.pop();
|
|
198
|
-
a.push(
|
|
199
|
-
aLast.substring(0, iLast) + aLast.substring(iLast + 1),
|
|
200
|
-
);
|
|
311
|
+
a.push(aLast.substring(0, iLast) + aLast.substring(iLast + 1));
|
|
201
312
|
}
|
|
202
313
|
v = '\n' + v;
|
|
203
314
|
}
|
package/src/text/list.mjs
CHANGED
|
@@ -180,8 +180,7 @@ export class ListFactory {
|
|
|
180
180
|
separator: rowSeparator,
|
|
181
181
|
precision,
|
|
182
182
|
});
|
|
183
|
-
let newRow = (separator) =>
|
|
184
|
-
this.createRow({ separator, precision });
|
|
183
|
+
let newRow = (separator) => this.createRow({ separator, precision });
|
|
185
184
|
name = name || singleList.name;
|
|
186
185
|
switch (order) {
|
|
187
186
|
case 'col-major':
|
package/src/text/merkle-json.mjs
CHANGED
|
@@ -159,8 +159,7 @@ function rhex(n) {
|
|
|
159
159
|
j = 0;
|
|
160
160
|
for (; j < 4; j++)
|
|
161
161
|
s +=
|
|
162
|
-
hex_chr[(n >> (j * 8 + 4)) & 0x0f] +
|
|
163
|
-
hex_chr[(n >> (j * 8)) & 0x0f];
|
|
162
|
+
hex_chr[(n >> (j * 8 + 4)) & 0x0f] + hex_chr[(n >> (j * 8)) & 0x0f];
|
|
164
163
|
return s;
|
|
165
164
|
}
|
|
166
165
|
|
|
@@ -237,9 +236,7 @@ export class MerkleJson {
|
|
|
237
236
|
stringify(value) {
|
|
238
237
|
if (value instanceof Array) {
|
|
239
238
|
let body = value.reduce((a, v) => {
|
|
240
|
-
return a
|
|
241
|
-
? `${a},${this.stringify(v)}`
|
|
242
|
-
: `${this.stringify(v)}`;
|
|
239
|
+
return a ? `${a},${this.stringify(v)}` : `${this.stringify(v)}`;
|
|
243
240
|
}, '');
|
|
244
241
|
return `[${body}]`;
|
|
245
242
|
} else if (value instanceof Date) {
|
|
@@ -124,9 +124,7 @@ export class SuttaCentralId {
|
|
|
124
124
|
n0 = Number(c0dig);
|
|
125
125
|
n1 = c0let.charCodeAt(0) - 'a'.charCodeAt(0) + 1;
|
|
126
126
|
if (Number.isNaN(n0) || Number.isNaN(n1)) {
|
|
127
|
-
throw new Error(
|
|
128
|
-
`partNumber() cannot parse ${part} in ${id}`,
|
|
129
|
-
);
|
|
127
|
+
throw new Error(`partNumber() cannot parse ${part} in ${id}`);
|
|
130
128
|
}
|
|
131
129
|
} else {
|
|
132
130
|
n0 = Number(c0);
|
|
@@ -142,10 +140,7 @@ export class SuttaCentralId {
|
|
|
142
140
|
static scidNumbersLow(id_or_path) {
|
|
143
141
|
let scid = BilaraPath.pathParts(id_or_path).suid;
|
|
144
142
|
let colonParts = scid.replace(/^[-a-z]*/, '').split(':');
|
|
145
|
-
let dotParts = colonParts.reduce(
|
|
146
|
-
(a, c) => a.concat(c.split('.')),
|
|
147
|
-
[],
|
|
148
|
-
);
|
|
143
|
+
let dotParts = colonParts.reduce((a, c) => a.concat(c.split('.')), []);
|
|
149
144
|
let nums = dotParts.reduce((a, n) => {
|
|
150
145
|
let lowPart = n.split('-')[0];
|
|
151
146
|
return a.concat(SuttaCentralId.partNumber(lowPart, id_or_path));
|
|
@@ -156,15 +151,10 @@ export class SuttaCentralId {
|
|
|
156
151
|
static scidNumbersHigh(id_or_path) {
|
|
157
152
|
let scid = BilaraPath.pathParts(id_or_path).suid;
|
|
158
153
|
let colonParts = scid.replace(/^[-a-z]*/, '').split(':');
|
|
159
|
-
let dotParts = colonParts.reduce(
|
|
160
|
-
(a, c) => a.concat(c.split('.')),
|
|
161
|
-
[],
|
|
162
|
-
);
|
|
154
|
+
let dotParts = colonParts.reduce((a, c) => a.concat(c.split('.')), []);
|
|
163
155
|
let nums = dotParts.reduce((a, n) => {
|
|
164
156
|
let highPart = n.split('-').pop();
|
|
165
|
-
return a.concat(
|
|
166
|
-
SuttaCentralId.partNumber(highPart, id_or_path),
|
|
167
|
-
);
|
|
157
|
+
return a.concat(SuttaCentralId.partNumber(highPart, id_or_path));
|
|
168
158
|
}, []);
|
|
169
159
|
return nums;
|
|
170
160
|
}
|
package/src/text/tfidf-space.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DBG } from '../defines.mjs';
|
|
2
|
+
import { ColorConsole } from './color-console.mjs';
|
|
2
3
|
import { Corpus } from './corpus.mjs';
|
|
3
4
|
import { WordVector } from './word-vector.mjs';
|
|
4
|
-
import { ColorConsole } from './color-console.mjs';
|
|
5
5
|
const { cc } = ColorConsole;
|
|
6
6
|
|
|
7
7
|
// The golden ratio is pretty.
|
|
@@ -52,17 +52,17 @@ export class TfidfSpace {
|
|
|
52
52
|
|
|
53
53
|
// Create wordWeight function that weighs the first words
|
|
54
54
|
// of a document more than the remainder
|
|
55
|
-
static wordWeightFromPrefix(prefixLength, prefixBias=0.5) {
|
|
55
|
+
static wordWeightFromPrefix(prefixLength, prefixBias = 0.5) {
|
|
56
56
|
const msg = 't8e.wordWeightFromPrefix';
|
|
57
57
|
|
|
58
|
-
let wordWeight = (w,i,nWords) => {
|
|
58
|
+
let wordWeight = (w, i, nWords) => {
|
|
59
59
|
const nWeighted = Math.min(nWords, prefixLength);
|
|
60
60
|
const nUnweighted = nWords - nWeighted;
|
|
61
61
|
const wf = nUnweighted ? prefixBias : 1;
|
|
62
|
-
return i < nWeighted
|
|
63
|
-
? wf * nWords / nWeighted
|
|
64
|
-
: (1 - wf) * nWords / nUnweighted;
|
|
65
|
-
|
|
62
|
+
return i < nWeighted
|
|
63
|
+
? (wf * nWords) / nWeighted
|
|
64
|
+
: ((1 - wf) * nWords) / nUnweighted;
|
|
65
|
+
};
|
|
66
66
|
return wordWeight;
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -110,9 +110,7 @@ export class TfidfSpace {
|
|
|
110
110
|
const msg = 'w7e.idfTunable:';
|
|
111
111
|
// NOTE: This is NOT the usual formula
|
|
112
112
|
// Map to [0:ignore..1:important]
|
|
113
|
-
return nDocs
|
|
114
|
-
? 1 - Math.exp(((wdc - nDocs) / wdc) * idfWeight)
|
|
115
|
-
: 1;
|
|
113
|
+
return nDocs ? 1 - Math.exp(((wdc - nDocs) / wdc) * idfWeight) : 1;
|
|
116
114
|
}
|
|
117
115
|
|
|
118
116
|
idf(word, idfWeight = this.idfWeight) {
|
|
@@ -208,22 +206,20 @@ export class TfidfSpace {
|
|
|
208
206
|
return { bow, words };
|
|
209
207
|
}
|
|
210
208
|
|
|
211
|
-
bowOfText(text, opts={}) {
|
|
209
|
+
bowOfText(text, opts = {}) {
|
|
212
210
|
const msg = 'w7e.bowOfText:';
|
|
213
211
|
let dbg = DBG.W7E_BOW_OF_TEXT;
|
|
214
212
|
if (text == null) {
|
|
215
213
|
throw new Error(`${msg} text?`);
|
|
216
214
|
}
|
|
217
|
-
let {
|
|
218
|
-
wordWeight = (word,i,n) => 1,
|
|
219
|
-
} = opts;
|
|
215
|
+
let { wordWeight = (word, i, n) => 1 } = opts;
|
|
220
216
|
let sNorm = this.normalizeText(text);
|
|
221
217
|
let words = sNorm.split(' ');
|
|
222
218
|
let nWords = words.length;
|
|
223
219
|
let bow = words.reduce((a, word, i) => {
|
|
224
220
|
let ww = wordWeight(word, i, nWords);
|
|
225
221
|
a[word] = (a[word] || 0) + ww;
|
|
226
|
-
dbg && cc.fyi1(msg+0.1, {i, word, ww, sum:a[word]});
|
|
222
|
+
dbg && cc.fyi1(msg + 0.1, { i, word, ww, sum: a[word] });
|
|
227
223
|
return a;
|
|
228
224
|
}, new WordVector());
|
|
229
225
|
|
package/src/text/unicode.mjs
CHANGED
|
@@ -235,6 +235,24 @@ export class Unicode {
|
|
|
235
235
|
static get u_MACRON() {
|
|
236
236
|
return '\u016d'; /* UTF-8 c5ab */
|
|
237
237
|
}
|
|
238
|
+
static get WHITE_CIRCLE() {
|
|
239
|
+
return '\u25CB';
|
|
240
|
+
}
|
|
241
|
+
static get INVERSE_BULLET() {
|
|
242
|
+
return '\u25D8';
|
|
243
|
+
}
|
|
244
|
+
static get CIRCLED_BULLET() {
|
|
245
|
+
return '\u29BF';
|
|
246
|
+
}
|
|
247
|
+
static get FISHEYE() {
|
|
248
|
+
return '\u25C9';
|
|
249
|
+
}
|
|
250
|
+
static get WHITE_BULLET() {
|
|
251
|
+
return '\u25E6';
|
|
252
|
+
}
|
|
253
|
+
static get BULLET() {
|
|
254
|
+
return '\u2022';
|
|
255
|
+
}
|
|
238
256
|
static get LEFT_ARROW() {
|
|
239
257
|
return '\u2190';
|
|
240
258
|
}
|
package/src/text/word-vector.mjs
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { DBG } from '../defines.mjs';
|
|
2
2
|
import { Unicode } from './unicode.mjs';
|
|
3
|
-
const {
|
|
4
|
-
ELLIPSIS,
|
|
5
|
-
} = Unicode;
|
|
3
|
+
const { ELLIPSIS } = Unicode;
|
|
6
4
|
|
|
7
5
|
// The golden ratio is pretty.
|
|
8
6
|
// 1.6180339887498948482045868343656381177203091798057628621354;
|
|
@@ -106,6 +104,7 @@ export class WordVector extends Object {
|
|
|
106
104
|
}
|
|
107
105
|
|
|
108
106
|
multiply(vec2) {
|
|
107
|
+
// Hadabard product: multipy element by element
|
|
109
108
|
const msg = 'w8r.multiply:';
|
|
110
109
|
let keys = Object.keys(vec2);
|
|
111
110
|
return keys.reduce((a, k) => {
|