@onrail-xyz/amount 1.0.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/LICENSE +201 -0
- package/README.md +617 -0
- package/dist/aggregating.d.ts +31 -0
- package/dist/aggregating.d.ts.map +1 -0
- package/dist/aggregating.js +31 -0
- package/dist/allocating.d.ts +9 -0
- package/dist/allocating.d.ts.map +1 -0
- package/dist/allocating.js +31 -0
- package/dist/amount.d.ts +68 -0
- package/dist/amount.d.ts.map +1 -0
- package/dist/amount.js +184 -0
- package/dist/format.d.ts +15 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +226 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/jsonCodecs.d.ts +9 -0
- package/dist/jsonCodecs.d.ts.map +1 -0
- package/dist/jsonCodecs.js +46 -0
- package/dist/kind.d.ts +126 -0
- package/dist/kind.d.ts.map +1 -0
- package/dist/kind.js +118 -0
- package/dist/rate.d.ts +58 -0
- package/dist/rate.d.ts.map +1 -0
- package/dist/rate.js +178 -0
- package/dist/rational.d.ts +49 -0
- package/dist/rational.d.ts.map +1 -0
- package/dist/rational.js +378 -0
- package/dist/segmenting.d.ts +15 -0
- package/dist/segmenting.d.ts.map +1 -0
- package/dist/segmenting.js +97 -0
- package/dist/unitSpecs.d.ts +47 -0
- package/dist/unitSpecs.d.ts.map +1 -0
- package/dist/unitSpecs.js +8 -0
- package/package.json +56 -0
- package/src/aggregating.ts +160 -0
- package/src/allocating.ts +70 -0
- package/src/amount.ts +291 -0
- package/src/format.ts +330 -0
- package/src/index.ts +8 -0
- package/src/jsonCodecs.ts +63 -0
- package/src/kind.ts +442 -0
- package/src/rate.ts +316 -0
- package/src/rational.ts +471 -0
- package/src/segmenting.ts +154 -0
- package/src/unitSpecs.ts +37 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { isArray, invalidPayload, expectString } from "@onrail-xyz/utils";
|
|
2
|
+
import { Rational } from "./rational.js";
|
|
3
|
+
import { Amount, isAmount } from "./amount.js";
|
|
4
|
+
import { Rate, isRate } from "./rate.js";
|
|
5
|
+
const expectFields = (encoded, tag, fields) => {
|
|
6
|
+
if (typeof encoded !== "object" || encoded === null || isArray(encoded))
|
|
7
|
+
throw invalidPayload(encoded, tag);
|
|
8
|
+
const out = {};
|
|
9
|
+
for (const field of fields) {
|
|
10
|
+
const value = encoded[field];
|
|
11
|
+
if (typeof value !== "string")
|
|
12
|
+
throw invalidPayload(encoded, tag);
|
|
13
|
+
out[field] = value;
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
};
|
|
17
|
+
const namedKind = (candidates, name, tag) => {
|
|
18
|
+
const kind = (isArray(candidates) ? candidates : [candidates]).find(k => k.name === name);
|
|
19
|
+
if (!kind)
|
|
20
|
+
throw new Error(`No candidate kind named "${name}" for ${tag}`);
|
|
21
|
+
return kind;
|
|
22
|
+
};
|
|
23
|
+
export const rationalCodec = {
|
|
24
|
+
tag: "Rational",
|
|
25
|
+
test: (value) => value instanceof Rational,
|
|
26
|
+
encode: value => value.toString(),
|
|
27
|
+
decode: encoded => Rational.from(expectString(encoded, "Rational")),
|
|
28
|
+
};
|
|
29
|
+
export const amountCodec = (kinds) => ({
|
|
30
|
+
tag: "Amount",
|
|
31
|
+
test: isAmount,
|
|
32
|
+
encode: value => ({ kind: value.kind.name, value: value.toJSON() }),
|
|
33
|
+
decode: encoded => {
|
|
34
|
+
const { kind, value } = expectFields(encoded, "Amount", ["kind", "value"]);
|
|
35
|
+
return Amount.parse(value, namedKind(kinds, kind, "Amount"));
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
export const rateCodec = (numKinds, denKinds) => ({
|
|
39
|
+
tag: "Rate",
|
|
40
|
+
test: isRate,
|
|
41
|
+
encode: value => ({ num: value.num.name, den: value.den.name, value: value.toJSON() }),
|
|
42
|
+
decode: encoded => {
|
|
43
|
+
const { num, den, value } = expectFields(encoded, "Rate", ["num", "den", "value"]);
|
|
44
|
+
return Rate.parse(value, namedKind(numKinds, num, "Rate"), namedKind(denKinds, den, "Rate"));
|
|
45
|
+
},
|
|
46
|
+
});
|
package/dist/kind.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { Opts, RoArray, RoNeTuple, RoPair, Brand, If, IsAny, IsNever, Extends, OptionalArg } from "@onrail-xyz/utils";
|
|
2
|
+
import { type Rationalish, Rational } from "./rational.js";
|
|
3
|
+
export type SymbolSpec = Readonly<{
|
|
4
|
+
symbol: string;
|
|
5
|
+
plural?: string;
|
|
6
|
+
position?: "postfix" | "prefix";
|
|
7
|
+
spacing?: "spaced" | "compact";
|
|
8
|
+
}>;
|
|
9
|
+
export type DecimalSpec<N extends number = number> = {
|
|
10
|
+
readonly oom: N;
|
|
11
|
+
readonly scale?: never;
|
|
12
|
+
};
|
|
13
|
+
export type ScaleSpec<N extends Rationalish = Rationalish> = {
|
|
14
|
+
readonly oom?: never;
|
|
15
|
+
readonly scale: N;
|
|
16
|
+
};
|
|
17
|
+
export type Unit = SymbolSpec & {
|
|
18
|
+
readonly scale: Rational;
|
|
19
|
+
readonly oom?: number;
|
|
20
|
+
};
|
|
21
|
+
export type SystemInfo<N extends string = string, U extends string = string, D extends boolean = boolean> = {
|
|
22
|
+
name: N;
|
|
23
|
+
symbols: U;
|
|
24
|
+
decimal: D;
|
|
25
|
+
};
|
|
26
|
+
export type StandardInfo<SY extends string = string, SU extends string = string> = {
|
|
27
|
+
system: SY;
|
|
28
|
+
unit: SU;
|
|
29
|
+
};
|
|
30
|
+
export type ValidStandardInfo<Y extends SystemInfo> = Y extends SystemInfo<infer N, infer U, boolean> ? StandardInfo<N, U> : never;
|
|
31
|
+
export type Kind<U extends string = string, N extends string = string, Y extends SystemInfo = SystemInfo, S extends ValidStandardInfo<Y> = ValidStandardInfo<Y>, H extends U | undefined = U | undefined, A extends U | undefined = U | undefined> = {
|
|
32
|
+
readonly name: N;
|
|
33
|
+
readonly units: KindUnits<U>;
|
|
34
|
+
readonly standard: S;
|
|
35
|
+
readonly systems: KindSystems<Y>;
|
|
36
|
+
} & ([
|
|
37
|
+
U | undefined
|
|
38
|
+
] extends [H] ? {
|
|
39
|
+
readonly human?: U;
|
|
40
|
+
} : [H] extends [U] ? {
|
|
41
|
+
readonly human: H;
|
|
42
|
+
} : [H] extends [undefined] ? unknown : {
|
|
43
|
+
readonly human?: Exclude<H, undefined>;
|
|
44
|
+
}) & ([
|
|
45
|
+
U | undefined
|
|
46
|
+
] extends [A] ? {
|
|
47
|
+
readonly atomic?: U;
|
|
48
|
+
} : [A] extends [U] ? {
|
|
49
|
+
readonly atomic: A;
|
|
50
|
+
} : [A] extends [undefined] ? unknown : {
|
|
51
|
+
readonly atomic?: Exclude<A, undefined>;
|
|
52
|
+
});
|
|
53
|
+
export type KindWithHuman<U extends string = string, N extends string = string, Y extends SystemInfo = SystemInfo, S extends ValidStandardInfo<Y> = ValidStandardInfo<Y>, H extends U = U, A extends U | undefined = U | undefined> = Kind<U, N, Y, S, H, A>;
|
|
54
|
+
export type KindWithAtomic<U extends string = string, N extends string = string, Y extends SystemInfo = SystemInfo, S extends ValidStandardInfo<Y> = ValidStandardInfo<Y>, H extends U | undefined = U | undefined, A extends U = U> = Kind<U, N, Y, S, H, A>;
|
|
55
|
+
export type KindWithHumanAndAtomic<U extends string = string, N extends string = string, Y extends SystemInfo = SystemInfo, S extends ValidStandardInfo<Y> = ValidStandardInfo<Y>, H extends U = U, A extends U = U> = Kind<U, N, Y, S, H, A>;
|
|
56
|
+
export type KindWithDecimalHumanAndAtomic<U extends string = string, N extends string = string, Y extends SystemInfo = SystemInfo, S extends ValidStandardInfo<Y> = ValidStandardInfo<Y>, H extends U = U, A extends U = U> = Brand<Kind<U, N, Y, S, H, A>, "decimalHuman" | "decimalAtomic">;
|
|
57
|
+
export type KindUnitSymbols<K extends Kind> = Extract<keyof K["units"], string>;
|
|
58
|
+
type MetaSymbolsOf<K extends Kind> = "standard" | (K["human"] extends string ? "human" : never) | (K["atomic"] extends string ? "atomic" : never);
|
|
59
|
+
export type SymbolsOf<K extends Kind> = If<IsAny<K>, string, If<Extends<string, KindUnitSymbols<K>>, If<IsNever<("human" | "atomic") & MetaSymbolsOf<K>>, string, never>, KindUnitSymbols<K>>> | MetaSymbolsOf<K>;
|
|
60
|
+
export type DecimalSymbolsOf<K extends Kind> = DecimalUnitSymbols<K> | DecimalMetaSymbolOf<K>;
|
|
61
|
+
export type ResolvedSymbolOf<K extends Kind, M extends SymbolsOf<K>> = M extends "standard" ? K["standard"]["unit"] : M extends "human" ? K["human"] : M extends "atomic" ? K["atomic"] : M;
|
|
62
|
+
export type IsBareKind<K extends Kind> = Extends<string, K["name"]>;
|
|
63
|
+
export type CandidateKinds<K extends Kind> = If<IsBareKind<K>, Kind, K>;
|
|
64
|
+
export declare function sameKind(a: Kind, b: Kind): boolean;
|
|
65
|
+
export declare function getUnit<const K extends Kind, S extends SymbolsOf<K>>(kind: K, unitSymbol: S): Unit;
|
|
66
|
+
export declare function getDecimals<const K extends KindWithDecimalHumanAndAtomic>(kind: K, opts?: GetDecimalsOpts<K>): number;
|
|
67
|
+
export declare function getDecimals<const K extends Kind>(kind: K, opts: GetDecimalsOpts<K>): number;
|
|
68
|
+
type MetaBrandTags<H, A, S, I extends KindUnitsInput> = [
|
|
69
|
+
H,
|
|
70
|
+
"human"
|
|
71
|
+
] | [A, "atomic"] | [S, "standard"] extends infer M ? M extends [DecimalSymbolsOfSystem<SystemInfoOf<I>>, MetaSymbols] ? `decimal${Capitalize<M[1]>}` : "" : never;
|
|
72
|
+
type KindOpts<I extends KindUnitsInput> = Opts<{
|
|
73
|
+
human: UnitSymbolsOf<UnitsSpecOf<I>>;
|
|
74
|
+
atomic: UnitSymbolsOf<UnitsSpecOf<I>>;
|
|
75
|
+
}>;
|
|
76
|
+
type MetaOf<O, K extends "human" | "atomic"> = K extends keyof O ? O[K] : undefined;
|
|
77
|
+
export declare function kind<N extends string, const I extends KindUnitsInput, const O extends KindOpts<I> = {}>(name: N, unitsInput: I, ...[opts]: OptionalArg<O>): Brand<Kind<UnitSymbolsOf<UnitsSpecOf<I>>, N, SystemInfoOf<I>, StandardInfoOf<I>, MetaOf<O, "human">, MetaOf<O, "atomic">>, MetaBrandTags<MetaOf<O, "human">, MetaOf<O, "atomic">, StandardInfoOf<I>["unit"], I>>;
|
|
78
|
+
export declare function identifyKind<const K extends Kind, A extends boolean = false>(kinds: RoArray<K>, str: string, allowAmbiguous?: A): A extends true ? K[] : K | undefined;
|
|
79
|
+
type UnitBaseSpec = {
|
|
80
|
+
readonly symbols: RoNeTuple<SymbolSpec>;
|
|
81
|
+
};
|
|
82
|
+
type UnitSpec<F extends boolean, D extends boolean> = UnitBaseSpec & (F extends true ? D extends true ? Partial<DecimalSpec<0>> : Partial<ScaleSpec<1 | 1n>> : D extends true ? DecimalSpec : ScaleSpec);
|
|
83
|
+
type KindUnitsSpec<F extends boolean, D extends boolean> = D extends any ? F extends true ? readonly [UnitSpec<true, D>, ...UnitSpec<false, D>[]] : RoNeTuple<UnitSpec<false, D>> : never;
|
|
84
|
+
type KindUnits<U extends string> = {
|
|
85
|
+
readonly [K in U]?: Unit;
|
|
86
|
+
};
|
|
87
|
+
type KindSystems<Y extends SystemInfo> = {
|
|
88
|
+
readonly [Sys in Y as Sys["name"]]: Readonly<{
|
|
89
|
+
symbols: RoArray<Sys["symbols"]>;
|
|
90
|
+
decimal: Sys["decimal"];
|
|
91
|
+
}>;
|
|
92
|
+
};
|
|
93
|
+
type UnitSymbolsOf<U extends RoArray<UnitBaseSpec>> = U[number]["symbols"][number] extends infer S ? S extends SymbolSpec ? S["symbol"] | Extract<S["plural"], string> : never : never;
|
|
94
|
+
type SystemEntry<F extends boolean = boolean, N extends string = string, S extends KindUnitsSpec<F, boolean> = KindUnitsSpec<F, boolean>> = RoPair<N, S>;
|
|
95
|
+
type SystemsSpec = readonly [SystemEntry<true>, ...SystemEntry<false>[]];
|
|
96
|
+
type KindUnitsInput = KindUnitsSpec<true, boolean> | SystemsSpec;
|
|
97
|
+
type IsSystemDecimal<Spec extends KindUnitsSpec<boolean, boolean>> = Spec[0] extends DecimalSpec ? true : Spec[0] extends ScaleSpec ? false : Spec extends readonly [unknown] | readonly [unknown, DecimalSpec, ...unknown[]] ? true : false;
|
|
98
|
+
type SystemInfoOf<I extends KindUnitsInput> = I extends SystemsSpec ? {
|
|
99
|
+
[K in keyof I & `${number}`]: I[K] extends SystemEntry<boolean, infer Name, infer Spec> ? SystemInfo<Name, UnitSymbolsOf<Spec>, IsSystemDecimal<Spec>> : never;
|
|
100
|
+
}[keyof I & `${number}`] : I extends KindUnitsSpec<true, boolean> ? SystemInfo<"default", UnitSymbolsOf<I>, IsSystemDecimal<I>> : never;
|
|
101
|
+
type UnitsSpecOf<I extends KindUnitsInput> = I extends SystemsSpec ? I[number][1] : I;
|
|
102
|
+
type StandardSystemOf<I extends KindUnitsInput> = I extends SystemsSpec ? I[0][0] : "default";
|
|
103
|
+
type StandardUnitOf<I extends KindUnitsInput> = I extends SystemsSpec ? I[0][1][0]["symbols"][0]["symbol"] : I extends KindUnitsSpec<boolean, boolean> ? I[0]["symbols"][0]["symbol"] : never;
|
|
104
|
+
type StandardInfoOf<I extends KindUnitsInput> = StandardInfo<StandardSystemOf<I>, StandardUnitOf<I>> extends infer S extends ValidStandardInfo<SystemInfoOf<I>> ? S : never;
|
|
105
|
+
declare const metaSymbols: readonly ["standard", "human", "atomic"];
|
|
106
|
+
type MetaSymbols = typeof metaSymbols[number];
|
|
107
|
+
type DecimalMetaSymbolOf<K extends Kind, M extends MetaSymbols = MetaSymbols> = M extends MetaSymbols ? K extends Brand<unknown, `decimal${Capitalize<M>}`> ? M : never : never;
|
|
108
|
+
type DecimalSymbolsOfSystem<Y extends SystemInfo> = Y extends {
|
|
109
|
+
symbols: infer Syms extends string;
|
|
110
|
+
decimal: true;
|
|
111
|
+
} ? Syms : never;
|
|
112
|
+
type DecimalUnitSymbols<K extends Kind> = K["systems"][keyof K["systems"]] extends infer Sys ? Sys extends {
|
|
113
|
+
symbols: RoArray<infer S extends string>;
|
|
114
|
+
decimal: true;
|
|
115
|
+
} ? S : never : never;
|
|
116
|
+
type GetDecimalsOpts<K extends Kind> = DecimalSymbolsOf<K> extends infer D ? ("human" extends D ? Opts<{
|
|
117
|
+
of: D;
|
|
118
|
+
}> : {
|
|
119
|
+
readonly of: D;
|
|
120
|
+
}) & ("atomic" extends D ? Opts<{
|
|
121
|
+
in: D;
|
|
122
|
+
}> : {
|
|
123
|
+
readonly in: D;
|
|
124
|
+
}) : never;
|
|
125
|
+
export {};
|
|
126
|
+
//# sourceMappingURL=kind.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kind.d.ts","sourceRoot":"","sources":["../src/kind.ts"],"names":[],"mappings":"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"}
|
package/dist/kind.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { omit, fromEntries, pick, isArray } from "@onrail-xyz/utils";
|
|
2
|
+
import { Rational } from "./rational.js";
|
|
3
|
+
import { findUnit, segment, symbolKey } from "./segmenting.js";
|
|
4
|
+
export function sameKind(a, b) {
|
|
5
|
+
return a === b || a.name === b.name;
|
|
6
|
+
}
|
|
7
|
+
export function getUnit(kind, unitSymbol) {
|
|
8
|
+
const resolved = unitSymbol === "standard" ? kind.standard.unit :
|
|
9
|
+
unitSymbol === "human" ? kind.human :
|
|
10
|
+
unitSymbol === "atomic" ? kind.atomic :
|
|
11
|
+
unitSymbol;
|
|
12
|
+
const unit = resolved === undefined ? undefined : kind.units[resolved];
|
|
13
|
+
if (!unit)
|
|
14
|
+
throw new Error(`Kind ${kind.name} has no unit ${unitSymbol}`);
|
|
15
|
+
return unit;
|
|
16
|
+
}
|
|
17
|
+
export function getDecimals(kind, opts) {
|
|
18
|
+
const { of: ofSymbol = "human", in: inSymbol = "atomic" } = opts ?? {};
|
|
19
|
+
const oomOf = (symbol) => {
|
|
20
|
+
const { oom } = getUnit(kind, symbol);
|
|
21
|
+
if (oom === undefined)
|
|
22
|
+
throw new Error(`Unit ${symbol} of kind ${kind.name} is not decimal`);
|
|
23
|
+
return oom;
|
|
24
|
+
};
|
|
25
|
+
return oomOf(ofSymbol) - oomOf(inSymbol);
|
|
26
|
+
}
|
|
27
|
+
export function kind(name, unitsInput, ...[opts]) {
|
|
28
|
+
const isSystemsSpec = isArray(unitsInput) && isArray(unitsInput[0]);
|
|
29
|
+
const systemEntries = (isSystemsSpec ? unitsInput : [["default", unitsInput]]);
|
|
30
|
+
const firstSpec = systemEntries[0][1];
|
|
31
|
+
const standard = {
|
|
32
|
+
system: systemEntries[0][0],
|
|
33
|
+
unit: firstSpec[0].symbols[0].symbol,
|
|
34
|
+
};
|
|
35
|
+
const meta = pick(opts ?? {}, ["human", "atomic"]);
|
|
36
|
+
const allUnits = [];
|
|
37
|
+
const systems = {};
|
|
38
|
+
for (let i = 0; i < systemEntries.length; ++i) {
|
|
39
|
+
const [sysName, unitsSpec] = systemEntries[i];
|
|
40
|
+
if (displayModes.some(mode => mode === sysName))
|
|
41
|
+
throw new Error(`"${sysName}" is a display mode and cannot name a system`);
|
|
42
|
+
//mirrors IsSystemDecimal: an explicit oom/scale on the first unit decides; a bare first
|
|
43
|
+
// unit defers to the second, and a lone bare unit counts as decimal
|
|
44
|
+
const sysDecimal = i === 0
|
|
45
|
+
? "oom" in firstSpec[0]
|
|
46
|
+
? true
|
|
47
|
+
: "scale" in firstSpec[0]
|
|
48
|
+
? false
|
|
49
|
+
: firstSpec.length === 1 || "oom" in firstSpec[1]
|
|
50
|
+
: unitsSpec.every(u => "oom" in u);
|
|
51
|
+
if (Object.hasOwn(systems, sysName))
|
|
52
|
+
throw new Error(`Duplicate system "${sysName}"`);
|
|
53
|
+
systems[sysName] = { symbols: [], decimal: sysDecimal };
|
|
54
|
+
const processed = unitsSpec
|
|
55
|
+
.map(u => ({ ...u, ...ensureScale(sysDecimal, u) }))
|
|
56
|
+
.sort((a, b) => b.scale.gt(a.scale) ? 1 : b.scale.lt(a.scale) ? -1 : 0);
|
|
57
|
+
for (const unit of processed) {
|
|
58
|
+
if (unit.scale.sign() !== 1)
|
|
59
|
+
throw new Error(`Unit scales must be positive, got ${unit.scale.toString()}`);
|
|
60
|
+
const magScale = omit(unit, "symbols");
|
|
61
|
+
for (const symbolSpec of unit.symbols) {
|
|
62
|
+
const unitData = { ...symbolSpec, ...magScale };
|
|
63
|
+
const symbols = [
|
|
64
|
+
symbolSpec.symbol,
|
|
65
|
+
...(symbolSpec.plural !== undefined ? [symbolSpec.plural] : []),
|
|
66
|
+
];
|
|
67
|
+
for (const symbol of symbols) {
|
|
68
|
+
if (metaSymbols.some(meta => meta === symbol))
|
|
69
|
+
throw new Error(`"${symbol}" is a reserved symbol and cannot name a unit`);
|
|
70
|
+
//parsing tokenizes on these characters (and takes a leading "-" for the sign), so a
|
|
71
|
+
// symbol containing them could never round-trip through its own kind. Digits end a
|
|
72
|
+
// value, so no symbol may start with one, and a prefix symbol (which the value follows,
|
|
73
|
+
// as in "$100") may hold none; a postfix one ends at the next space regardless
|
|
74
|
+
const prefix = (symbolSpec.position ?? "postfix") === "prefix";
|
|
75
|
+
if (symbol === "" || /[\s,_./]/u.test(symbol) || symbol.startsWith("-") ||
|
|
76
|
+
/^[0-9]/.test(symbol) || (prefix && /[0-9]/.test(symbol)))
|
|
77
|
+
throw new Error(`Invalid unit symbol "${symbol}": symbols must be non-empty and must not ` +
|
|
78
|
+
`contain whitespace, ",", "_", ".", "/", a leading "-" or a leading digit ` +
|
|
79
|
+
`(nor any digit when prefixed)`);
|
|
80
|
+
if (systems[sysName].symbols.includes(symbol))
|
|
81
|
+
throw new Error(`Duplicate symbol "${symbol}" in system ${sysName}`);
|
|
82
|
+
const existing = allUnits.find(([s]) => symbolKey(s) === symbolKey(symbol));
|
|
83
|
+
if (existing && existing[0] !== symbol)
|
|
84
|
+
throw new Error(`Symbol "${symbol}" is equivalent to "${existing[0]}" (NFKC)`);
|
|
85
|
+
systems[sysName].symbols.push(symbol);
|
|
86
|
+
if (!existing)
|
|
87
|
+
allUnits.push([symbol, unitData]);
|
|
88
|
+
else if (!existing[1].scale.eq(unitData.scale))
|
|
89
|
+
throw new Error(`Symbol "${symbol}" has conflicting scales across systems`);
|
|
90
|
+
else
|
|
91
|
+
existing[1] = { ...unitData, ...existing[1] };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//descending by scale: a promise to consumers walking `units`, which the type states too
|
|
97
|
+
allUnits.sort((a, b) => b[1].scale.gt(a[1].scale) ? 1 : b[1].scale.lt(a[1].scale) ? -1 : 0);
|
|
98
|
+
const units = fromEntries(allUnits);
|
|
99
|
+
return { name, units, standard, systems, ...meta };
|
|
100
|
+
}
|
|
101
|
+
export function identifyKind(kinds, str, allowAmbiguous) {
|
|
102
|
+
const { pairs } = segment(str);
|
|
103
|
+
const symbols = pairs.map(p => str.substring(p.symbol[0], p.symbol[1]));
|
|
104
|
+
const matches = kinds.filter(k => symbols.every(s => findUnit(k.units, s) !== undefined));
|
|
105
|
+
return (allowAmbiguous ? matches : matches.length === 1 ? matches[0] : undefined);
|
|
106
|
+
}
|
|
107
|
+
const metaSymbols = ["standard", "human", "atomic"];
|
|
108
|
+
//Amount.toString takes a system name in the position of its mode argument, so a system named
|
|
109
|
+
// like a mode could never be selected
|
|
110
|
+
const displayModes = ["approximate", "exact", "inUnit"];
|
|
111
|
+
const addScale = (spec) => ({ oom: spec.oom, scale: Rational.powerOfTen(spec.oom) });
|
|
112
|
+
const ensureScale = (decimal, spec) => "oom" in spec
|
|
113
|
+
? addScale(spec)
|
|
114
|
+
: "scale" in spec
|
|
115
|
+
? { scale: Rational.from(spec.scale) }
|
|
116
|
+
: decimal
|
|
117
|
+
? { oom: 0, scale: Rational.from(1n) }
|
|
118
|
+
: { scale: Rational.from(1n) };
|
package/dist/rate.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Opts, MaybeArray, Brand, NarrowTo, RoArray } from "@onrail-xyz/utils";
|
|
2
|
+
import type { Rationalish, ToFixedOptions } from "./rational.js";
|
|
3
|
+
import { Rational } from "./rational.js";
|
|
4
|
+
import type { Kind, KindWithHuman, CandidateKinds, SymbolsOf, DecimalSymbolsOf } from "./kind.js";
|
|
5
|
+
import { Amount } from "./amount.js";
|
|
6
|
+
export declare const numKindOf: <NK extends Kind, DK extends Kind>(rate: Rate<NK, DK>) => NK;
|
|
7
|
+
export declare const denKindOf: <NK extends Kind, DK extends Kind>(rate: Rate<NK, DK>) => DK;
|
|
8
|
+
export declare const invert: <NK extends Kind, DK extends Kind>(rate: Rate<NK, DK>) => Rate<DK, NK>;
|
|
9
|
+
export declare const isRate: <T>(value: T) => value is NarrowTo<T, Rate<Kind, Kind>>;
|
|
10
|
+
export declare class _Rate<NK extends Kind, DK extends Kind> {
|
|
11
|
+
readonly ratio: Rational;
|
|
12
|
+
readonly num: NK;
|
|
13
|
+
readonly den: DK;
|
|
14
|
+
private constructor();
|
|
15
|
+
static from<const NK extends Kind, const DK extends Kind>(ratio: Rationalish, num: KindWithHuman & NK, den: KindWithHuman & DK): Rate<NK, DK>;
|
|
16
|
+
static from<const NK extends Kind, const DK extends Kind>(num: Amount<NK>, den: (KindWithHuman & DK) | Amount<DK>): Rate<NK, DK>;
|
|
17
|
+
static parse<const NK extends Kind, const DK extends Kind>(str: string, numKinds: MaybeArray<NK>, denKinds: MaybeArray<DK>): Rate<NK, DK>;
|
|
18
|
+
static hasNum<R extends Rate<Kind, Kind>, K extends CandidateKinds<R["num"]>>(rate: R, numKind: K): rate is NarrowTo<R, Rate<K, Kind>>;
|
|
19
|
+
static hasDen<R extends Rate<Kind, Kind>, K extends CandidateKinds<R["den"]>>(rate: R, denKind: K): rate is NarrowTo<R, Rate<Kind, K>>;
|
|
20
|
+
static allHaveNum<R extends Rate<Kind, Kind>, K extends CandidateKinds<R["num"]>>(rates: RoArray<R>, numKind: K): rates is RoArray<NarrowTo<R, Rate<K, Kind>>>;
|
|
21
|
+
static allHaveDen<R extends Rate<Kind, Kind>, K extends CandidateKinds<R["den"]>>(rates: RoArray<R>, denKind: K): rates is RoArray<NarrowTo<R, Rate<Kind, K>>>;
|
|
22
|
+
zero(): this;
|
|
23
|
+
ofSame<NS extends SymbolsOf<NK>, DS extends SymbolsOf<DK>>(numericalValue: Rationalish | string, numUnit: NS, denUnit: DS): this;
|
|
24
|
+
toString<NS extends SymbolsOf<NK> = SymbolsOf<NK>, DS extends SymbolsOf<DK> = SymbolsOf<DK>>(opts?: Opts<ToFixedOptions & {
|
|
25
|
+
numSymbol: NS;
|
|
26
|
+
denSymbol: DS;
|
|
27
|
+
precision: number | (NS extends DecimalSymbolsOf<NK> ? DecimalSymbolsOf<NK> : never);
|
|
28
|
+
}>): string;
|
|
29
|
+
toString(mode: "exact", opts?: Opts<ToFixedOptions>): string;
|
|
30
|
+
toJSON(): string;
|
|
31
|
+
in<NS extends SymbolsOf<NK>, DS extends SymbolsOf<DK>>(numUnit: NS, denUnit: DS): Rational;
|
|
32
|
+
ceilTo<NS extends SymbolsOf<NK>, DS extends SymbolsOf<DK>>(numUnit: NS, denUnit: DS): this;
|
|
33
|
+
roundTo<NS extends SymbolsOf<NK>, DS extends SymbolsOf<DK>>(numUnit: NS, denUnit: DS): this;
|
|
34
|
+
floorTo<NS extends SymbolsOf<NK>, DS extends SymbolsOf<DK>>(numUnit: NS, denUnit: DS): this;
|
|
35
|
+
isZero(): boolean;
|
|
36
|
+
sign(): -1 | 0 | 1;
|
|
37
|
+
eq(other: this): boolean;
|
|
38
|
+
ne(other: this): boolean;
|
|
39
|
+
lt(other: this): boolean;
|
|
40
|
+
le(other: this): boolean;
|
|
41
|
+
gt(other: this): boolean;
|
|
42
|
+
ge(other: this): boolean;
|
|
43
|
+
abs(): this;
|
|
44
|
+
neg(): this;
|
|
45
|
+
add(other: this): this;
|
|
46
|
+
sub(other: this): this;
|
|
47
|
+
mul(scalar: Rationalish | Amount<Brand<Kind, "scalar">>): this;
|
|
48
|
+
div(scalar: Rationalish | Amount<Brand<Kind, "scalar">>): this;
|
|
49
|
+
inv(): Rate<DK, NK>;
|
|
50
|
+
combine<NKO extends DK, DKO extends Kind>(other: Rate<NKO, DKO>): Rate<NK, DKO>;
|
|
51
|
+
cancel(other: Rate<DK, NK>): Rational;
|
|
52
|
+
private checkKinds;
|
|
53
|
+
private static checkedNew;
|
|
54
|
+
}
|
|
55
|
+
type Rate<NK extends Kind, DK extends Kind> = NK extends Kind ? [DK] extends [never] ? never : DK extends Kind ? _Rate<NK, DK> : never : never;
|
|
56
|
+
declare const Rate: typeof _Rate;
|
|
57
|
+
export { Rate };
|
|
58
|
+
//# sourceMappingURL=rate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate.d.ts","sourceRoot":"","sources":["../src/rate.ts"],"names":[],"mappings":"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"}
|
package/dist/rate.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { isArray } from "@onrail-xyz/utils";
|
|
2
|
+
import { Rational } from "./rational.js";
|
|
3
|
+
import { getUnit, sameKind } from "./kind.js";
|
|
4
|
+
import { Amount, isAmount } from "./amount.js";
|
|
5
|
+
import { bestDenUnit, exactRate, inUnit, inUnitApprox } from "./format.js";
|
|
6
|
+
import { findUnit } from "./segmenting.js";
|
|
7
|
+
//most things in here rhyme with Amount and so the rationales transfer
|
|
8
|
+
export const numKindOf = (rate) => rate.num;
|
|
9
|
+
export const denKindOf = (rate) => rate.den;
|
|
10
|
+
export const invert = (rate) => rate.inv();
|
|
11
|
+
export const isRate = (value) => value instanceof _Rate;
|
|
12
|
+
export class _Rate {
|
|
13
|
+
ratio;
|
|
14
|
+
num;
|
|
15
|
+
den;
|
|
16
|
+
constructor(ratio, num, den) {
|
|
17
|
+
this.ratio = ratio;
|
|
18
|
+
this.num = num;
|
|
19
|
+
this.den = den;
|
|
20
|
+
}
|
|
21
|
+
static from(ratioOrNum, numOrDen, maybeDen) {
|
|
22
|
+
const [amtNum, den] = isAmount(ratioOrNum)
|
|
23
|
+
? [ratioOrNum, numOrDen]
|
|
24
|
+
: [Amount.from(ratioOrNum, numOrDen, "human"), maybeDen];
|
|
25
|
+
const amtDen = isAmount(den)
|
|
26
|
+
? den
|
|
27
|
+
: Amount.from(1, den, "human");
|
|
28
|
+
return _Rate.checkedNew(amtNum.in("standard").div(amtDen.in("standard")), amtNum.kind, amtDen.kind);
|
|
29
|
+
}
|
|
30
|
+
static parse(str, numKinds, denKinds) {
|
|
31
|
+
const lastSlash = str.lastIndexOf("/");
|
|
32
|
+
if (lastSlash === -1)
|
|
33
|
+
throw new Error("Expected string in format 'numerator/denominator'");
|
|
34
|
+
const numKindsArray = isArray(numKinds) ? numKinds : [numKinds];
|
|
35
|
+
const denKindsArray = isArray(denKinds) ? denKinds : [denKinds];
|
|
36
|
+
const numAmount = Amount.parse(str.substring(0, lastSlash), ...numKindsArray);
|
|
37
|
+
const denStr = str.substring(lastSlash + 1);
|
|
38
|
+
const denKindRes = denKindsArray.filter(k => findUnit(k.units, denStr) !== undefined);
|
|
39
|
+
if (denKindRes.length !== 1)
|
|
40
|
+
throw new Error("Could not identify denominator kind from string");
|
|
41
|
+
const denKind = denKindRes[0];
|
|
42
|
+
const denUnit = findUnit(denKind.units, denStr);
|
|
43
|
+
const ratio = numAmount.in("standard").div(denUnit.scale);
|
|
44
|
+
return _Rate.checkedNew(ratio, numAmount.kind, denKind);
|
|
45
|
+
}
|
|
46
|
+
static hasNum(rate, numKind) {
|
|
47
|
+
return sameKind(rate.num, numKind);
|
|
48
|
+
}
|
|
49
|
+
static hasDen(rate, denKind) {
|
|
50
|
+
return sameKind(rate.den, denKind);
|
|
51
|
+
}
|
|
52
|
+
static allHaveNum(rates, numKind) {
|
|
53
|
+
return rates.every(rate => sameKind(rate.num, numKind));
|
|
54
|
+
}
|
|
55
|
+
static allHaveDen(rates, denKind) {
|
|
56
|
+
return rates.every(rate => sameKind(rate.den, denKind));
|
|
57
|
+
}
|
|
58
|
+
zero() {
|
|
59
|
+
return new _Rate(Rational.from(0n), this.num, this.den);
|
|
60
|
+
}
|
|
61
|
+
ofSame(numericalValue, numUnit, denUnit) {
|
|
62
|
+
const num = getUnit(this.num, numUnit);
|
|
63
|
+
const den = getUnit(this.den, denUnit);
|
|
64
|
+
return new _Rate(Rational.from(numericalValue).mul(num.scale).div(den.scale), this.num, this.den);
|
|
65
|
+
}
|
|
66
|
+
toString(modeOrOpts, exactOpts) {
|
|
67
|
+
if (modeOrOpts === "exact")
|
|
68
|
+
return exactRate(this.num, this.den, this.ratio, exactOpts);
|
|
69
|
+
const opts = modeOrOpts;
|
|
70
|
+
const numSym = (opts?.numSymbol ?? this.num.human ?? this.num.standard.unit);
|
|
71
|
+
const numUnit = getUnit(this.num, numSym);
|
|
72
|
+
const denUnit = opts?.denSymbol !== undefined
|
|
73
|
+
? getUnit(this.den, opts.denSymbol)
|
|
74
|
+
: bestDenUnit(this.num, this.den, this.ratio);
|
|
75
|
+
const stdVal = this.ratio.mul(denUnit.scale);
|
|
76
|
+
const prec = typeof opts?.precision === "string"
|
|
77
|
+
? getUnit(this.num, opts.precision).symbol
|
|
78
|
+
: opts?.precision;
|
|
79
|
+
const numSymbol = numUnit.symbol;
|
|
80
|
+
const num = prec === undefined
|
|
81
|
+
? inUnitApprox(this.num, stdVal, numSymbol, opts)
|
|
82
|
+
: inUnit(this.num, stdVal, numSymbol, prec, opts);
|
|
83
|
+
return `${num}/${denUnit.symbol}`;
|
|
84
|
+
}
|
|
85
|
+
toJSON() {
|
|
86
|
+
return this.toString("exact");
|
|
87
|
+
}
|
|
88
|
+
in(numUnit, denUnit) {
|
|
89
|
+
const num = getUnit(this.num, numUnit);
|
|
90
|
+
const den = getUnit(this.den, denUnit);
|
|
91
|
+
return this.ratio.mul(den.scale).div(num.scale);
|
|
92
|
+
}
|
|
93
|
+
ceilTo(numUnit, denUnit) {
|
|
94
|
+
return this.ofSame(this.in(numUnit, denUnit).ceil(), numUnit, denUnit);
|
|
95
|
+
}
|
|
96
|
+
roundTo(numUnit, denUnit) {
|
|
97
|
+
return this.ofSame(this.in(numUnit, denUnit).round(), numUnit, denUnit);
|
|
98
|
+
}
|
|
99
|
+
floorTo(numUnit, denUnit) {
|
|
100
|
+
return this.ofSame(this.in(numUnit, denUnit).floor(), numUnit, denUnit);
|
|
101
|
+
}
|
|
102
|
+
isZero() {
|
|
103
|
+
return this.ratio.eq(0n);
|
|
104
|
+
}
|
|
105
|
+
sign() {
|
|
106
|
+
return this.ratio.sign();
|
|
107
|
+
}
|
|
108
|
+
eq(other) {
|
|
109
|
+
this.checkKinds(other);
|
|
110
|
+
return this.ratio.eq(other.ratio);
|
|
111
|
+
}
|
|
112
|
+
ne(other) {
|
|
113
|
+
this.checkKinds(other);
|
|
114
|
+
return this.ratio.ne(other.ratio);
|
|
115
|
+
}
|
|
116
|
+
lt(other) {
|
|
117
|
+
this.checkKinds(other);
|
|
118
|
+
return this.ratio.lt(other.ratio);
|
|
119
|
+
}
|
|
120
|
+
le(other) {
|
|
121
|
+
this.checkKinds(other);
|
|
122
|
+
return this.ratio.le(other.ratio);
|
|
123
|
+
}
|
|
124
|
+
gt(other) {
|
|
125
|
+
this.checkKinds(other);
|
|
126
|
+
return this.ratio.gt(other.ratio);
|
|
127
|
+
}
|
|
128
|
+
ge(other) {
|
|
129
|
+
this.checkKinds(other);
|
|
130
|
+
return this.ratio.ge(other.ratio);
|
|
131
|
+
}
|
|
132
|
+
abs() {
|
|
133
|
+
return new _Rate(this.ratio.abs(), this.num, this.den);
|
|
134
|
+
}
|
|
135
|
+
neg() {
|
|
136
|
+
return new _Rate(this.ratio.neg(), this.num, this.den);
|
|
137
|
+
}
|
|
138
|
+
add(other) {
|
|
139
|
+
this.checkKinds(other);
|
|
140
|
+
return new _Rate(this.ratio.add(other.ratio), this.num, this.den);
|
|
141
|
+
}
|
|
142
|
+
sub(other) {
|
|
143
|
+
this.checkKinds(other);
|
|
144
|
+
return new _Rate(this.ratio.sub(other.ratio), this.num, this.den);
|
|
145
|
+
}
|
|
146
|
+
mul(scalar) {
|
|
147
|
+
scalar = isAmount(scalar) ? scalar.in("standard") : scalar;
|
|
148
|
+
return new _Rate(this.ratio.mul(scalar), this.num, this.den);
|
|
149
|
+
}
|
|
150
|
+
div(scalar) {
|
|
151
|
+
scalar = isAmount(scalar) ? scalar.in("standard") : scalar;
|
|
152
|
+
return new _Rate(this.ratio.div(scalar), this.num, this.den);
|
|
153
|
+
}
|
|
154
|
+
inv() {
|
|
155
|
+
return new _Rate(this.ratio.inv(), this.den, this.num);
|
|
156
|
+
}
|
|
157
|
+
combine(other) {
|
|
158
|
+
if (!sameKind(this.den, other.num))
|
|
159
|
+
throw new Error(`Kind mismatch: ${this.den.name} vs ${other.num.name}`);
|
|
160
|
+
return _Rate.checkedNew(this.ratio.mul(other.ratio), this.num, other.den);
|
|
161
|
+
}
|
|
162
|
+
cancel(other) {
|
|
163
|
+
if (!sameKind(this.den, other.num) || !sameKind(this.num, other.den))
|
|
164
|
+
throw new Error(`Kind mismatch: ${this.den.name}/${this.num.name} vs ${other.num.name}/${other.den.name}`);
|
|
165
|
+
return this.ratio.mul(other.ratio);
|
|
166
|
+
}
|
|
167
|
+
checkKinds(other) {
|
|
168
|
+
if (!sameKind(this.num, other.num) || !sameKind(this.den, other.den))
|
|
169
|
+
throw new Error(`Kind mismatch: ${this.num.name}/${this.den.name} vs ${other.num.name}/${other.den.name}`);
|
|
170
|
+
}
|
|
171
|
+
static checkedNew(ratio, num, den) {
|
|
172
|
+
if (sameKind(num, den))
|
|
173
|
+
throw new Error(`Must be distinct kinds: ${num.name} vs ${den.name}`);
|
|
174
|
+
return new _Rate(ratio, num, den);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const Rate = _Rate;
|
|
178
|
+
export { Rate };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type Opts } from "@onrail-xyz/utils";
|
|
2
|
+
export type Rationalish = Rational | number | bigint;
|
|
3
|
+
export type ThousandsSep = "" | "," | "_";
|
|
4
|
+
export type ToFixedOptions = {
|
|
5
|
+
thousandsSep: ThousandsSep;
|
|
6
|
+
trimZeros: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare const tenToThe: (exp: number) => bigint;
|
|
9
|
+
export declare class Rational {
|
|
10
|
+
static powerOfTen(oom: number): Rational;
|
|
11
|
+
private readonly n;
|
|
12
|
+
private readonly d;
|
|
13
|
+
private constructor();
|
|
14
|
+
static from(value: Rationalish | string): Rational;
|
|
15
|
+
static from(numerator: bigint, denominator?: bigint): Rational;
|
|
16
|
+
unwrap(): [bigint, bigint];
|
|
17
|
+
toNumber(): number;
|
|
18
|
+
toString(opts?: Opts<{
|
|
19
|
+
thousandsSep: ThousandsSep;
|
|
20
|
+
}>): string;
|
|
21
|
+
toJSON(): string;
|
|
22
|
+
toFixed(precision?: number, opts?: Opts<ToFixedOptions>): string;
|
|
23
|
+
isInteger(): boolean;
|
|
24
|
+
decimalPlaces(): number | undefined;
|
|
25
|
+
sign(): -1 | 0 | 1;
|
|
26
|
+
ceil(): bigint;
|
|
27
|
+
round(): bigint;
|
|
28
|
+
floor(): bigint;
|
|
29
|
+
abs(): Rational;
|
|
30
|
+
neg(): Rational;
|
|
31
|
+
inv(): Rational;
|
|
32
|
+
eq(other: Rationalish): boolean;
|
|
33
|
+
ne(other: Rationalish): boolean;
|
|
34
|
+
gt(other: Rationalish): boolean;
|
|
35
|
+
ge(other: Rationalish): boolean;
|
|
36
|
+
lt(other: Rationalish): boolean;
|
|
37
|
+
cmp(other: Rationalish): -1 | 0 | 1;
|
|
38
|
+
le(other: Rationalish): boolean;
|
|
39
|
+
add(other: Rationalish): Rational;
|
|
40
|
+
sub(other: Rationalish): Rational;
|
|
41
|
+
mul(other: Rationalish): Rational;
|
|
42
|
+
div(other: Rationalish): Rational;
|
|
43
|
+
mod(other: Rationalish): Rational;
|
|
44
|
+
private static addSep;
|
|
45
|
+
private static gcd;
|
|
46
|
+
private static stripSign;
|
|
47
|
+
private static normalize;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=rational.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rational.d.ts","sourceRoot":"","sources":["../src/rational.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAgB,MAAM,mBAAmB,CAAC;AAI5D,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AACrD,MAAM,MAAM,YAAY,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC;AAC1C,MAAM,MAAM,cAAc,GAAG;IAAE,YAAY,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAIhF,eAAO,MAAM,QAAQ,QAAS,MAAM,KAAG,MAA4C,CAAC;AAEpF,qBAAa,QAAQ;IACnB,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAIvC;IAED,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAU;IAG5B,OAAO,eAGN;IAED,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;IACnD,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAkH/D,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAEzB;IAGD,QAAQ,IAAI,MAAM,CAkCjB;IAID,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;QAAE,YAAY,EAAE,YAAY,CAAA;KAAE,CAAC,GAAG,MAAM,CAY5D;IAID,MAAM,IAAI,MAAM,CAEf;IAED,OAAO,CAAC,SAAS,GAAE,MAAU,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,GAAG,MAAM,CAyBlE;IAED,SAAS,IAAI,OAAO,CAEnB;IAID,aAAa,IAAI,MAAM,GAAG,SAAS,CAKlC;IAED,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAEjB;IAED,IAAI,IAAI,MAAM,CAGb;IAGD,KAAK,IAAI,MAAM,CAId;IAED,KAAK,IAAI,MAAM,CAGd;IAED,GAAG,IAAI,QAAQ,CAEd;IAED,GAAG,IAAI,QAAQ,CAEd;IAED,GAAG,IAAI,QAAQ,CAOd;IAED,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAW9B;IAED,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE9B;IAED,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAW9B;IAED,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAW9B;IAED,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE9B;IAID,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAelC;IAED,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE9B;IAED,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,CAuBhC;IAED,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,CAEhC;IAED,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,CAkBhC;IAED,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,CAoBhC;IAGD,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,CAGhC;IAED,OAAO,CAAC,MAAM,CAAC,MAAM;IAIrB,OAAO,CAAC,MAAM,CAAC,GAAG;IAOlB,OAAO,CAAC,MAAM,CAAC,SAAS;IAIxB,OAAO,CAAC,MAAM,CAAC,SAAS;CAIzB"}
|