@hatiolab/figure-model 0.1.32 → 0.1.34
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/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/sizing.d.ts +11 -0
- package/dist/sizing.d.ts.map +1 -1
- package/dist/sizing.js +8 -4
- package/dist/sizing.js.map +1 -1
- package/dist/v3-asset-types.d.ts +48 -2
- package/dist/v3-asset-types.d.ts.map +1 -1
- package/dist/v3-asset.d.ts.map +1 -1
- package/dist/v3-asset.js +19 -3
- package/dist/v3-asset.js.map +1 -1
- package/dist/v3-capabilities.d.ts.map +1 -1
- package/dist/v3-capabilities.js +13 -1
- package/dist/v3-capabilities.js.map +1 -1
- package/dist/v3-create.js +1 -1
- package/dist/v3-create.js.map +1 -1
- package/dist/v3-driver.d.ts +16 -0
- package/dist/v3-driver.d.ts.map +1 -0
- package/dist/v3-driver.js +145 -0
- package/dist/v3-driver.js.map +1 -0
- package/dist/v3-from-v2.d.ts +116 -0
- package/dist/v3-from-v2.d.ts.map +1 -0
- package/dist/v3-from-v2.js +1203 -0
- package/dist/v3-from-v2.js.map +1 -0
- package/dist/v3-gate.d.ts +38 -0
- package/dist/v3-gate.d.ts.map +1 -0
- package/dist/v3-gate.js +134 -0
- package/dist/v3-gate.js.map +1 -0
- package/dist/v3-graph-types.d.ts +1 -1
- package/dist/v3-graph-types.d.ts.map +1 -1
- package/dist/v3-graph.d.ts +14 -0
- package/dist/v3-graph.d.ts.map +1 -1
- package/dist/v3-graph.js +162 -10
- package/dist/v3-graph.js.map +1 -1
- package/docs/prototypes/v3-asset-samples.mjs +1 -1
- package/docs/prototypes/v3-asset.schema.json +1 -1
- package/docs/v3-asset-persistence.md +3 -1
- package/docs/v3-design.md +3 -0
- package/docs/v3-motion-contract.md +178 -0
- package/docs/v3-operator-contracts.md +5 -0
- package/docs/v3-review-2026-09-22.md +127 -0
- package/docs/v3-status.md +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/*
|
|
5
|
+
* Drivers: time → state value (docs/v3-motion-contract.md).
|
|
6
|
+
*
|
|
7
|
+
* This is the one place interpolation, looping and phase normalisation are written. things-scene, a thumbnail
|
|
8
|
+
* renderer and a test all call `driverValue`; none of them reimplements it. The kernel itself never reads time:
|
|
9
|
+
* the consumer takes the value this returns and passes it as a state override to `compileV3Asset(...).evaluate`.
|
|
10
|
+
*
|
|
11
|
+
* Continuous rotation is two numbers, an accumulated angle and a phase. Keys hold the accumulated angle; the
|
|
12
|
+
* interpolation happens on it; only then is the result wrapped into [-180°, 180°) for the kernel. Wrapping the
|
|
13
|
+
* keys first would make 350° → 370° turn the wrong way.
|
|
14
|
+
*/
|
|
15
|
+
import { V3ContractError } from "./v3-contract.js";
|
|
16
|
+
const fail = (code, path, detail) => {
|
|
17
|
+
throw new V3ContractError(code, path, detail);
|
|
18
|
+
};
|
|
19
|
+
/** The inputs a driver may write, with their units: the asset's state inputs. */
|
|
20
|
+
function stateUnits(asset) {
|
|
21
|
+
return new Map(asset.document.model.inputs.filter(i => i.role === 'state').map(i => [i.id, i.unit]));
|
|
22
|
+
}
|
|
23
|
+
/** Refuses a driver list the contract does not allow. Called by `compileV3Asset`. */
|
|
24
|
+
export function validateV3Drivers(asset) {
|
|
25
|
+
const drivers = asset.drivers;
|
|
26
|
+
if (drivers === undefined)
|
|
27
|
+
return;
|
|
28
|
+
if (!Array.isArray(drivers))
|
|
29
|
+
fail('DRIVER', 'drivers', 'array required');
|
|
30
|
+
const states = stateUnits(asset);
|
|
31
|
+
const seenIds = new Set();
|
|
32
|
+
const seenStates = new Set();
|
|
33
|
+
for (const d of drivers) {
|
|
34
|
+
const path = `drivers.${String(d?.id ?? '?')}`;
|
|
35
|
+
const keysOf = (o) => (o && typeof o === 'object' ? Object.keys(o).sort() : null);
|
|
36
|
+
if (JSON.stringify(keysOf(d)) !== JSON.stringify(['accumulates', 'id', 'interpolation', 'keys', 'loop', 'state', 'time']))
|
|
37
|
+
fail('DRIVER', path, 'exactly id, state, time, keys, interpolation, loop, accumulates required');
|
|
38
|
+
if (typeof d.id !== 'string' || !d.id.trim())
|
|
39
|
+
fail('DRIVER', path, 'id required');
|
|
40
|
+
if (seenIds.has(d.id))
|
|
41
|
+
fail('DRIVER', path, 'duplicate driver id');
|
|
42
|
+
seenIds.add(d.id);
|
|
43
|
+
if (!states.has(d.state))
|
|
44
|
+
fail('DRIVER_STATE', path, `${String(d.state)} is not a state input of this asset`);
|
|
45
|
+
if (seenStates.has(d.state))
|
|
46
|
+
fail('DRIVER_STATE', path, `two drivers write ${d.state}; one writer per state`);
|
|
47
|
+
seenStates.add(d.state);
|
|
48
|
+
if (JSON.stringify(keysOf(d.time)) !== JSON.stringify(['duration', 'unit']) || d.time.unit !== 's')
|
|
49
|
+
fail('DRIVER_TIME', path, 'time must be { unit: "s", duration }');
|
|
50
|
+
if (!(Number.isFinite(d.time.duration) && d.time.duration > 0))
|
|
51
|
+
fail('DRIVER_TIME', path, 'positive duration in seconds required');
|
|
52
|
+
if (!Array.isArray(d.keys) || d.keys.length < 2)
|
|
53
|
+
fail('DRIVER_KEYS', path, 'at least two keys required');
|
|
54
|
+
let last = -Infinity;
|
|
55
|
+
for (const k of d.keys) {
|
|
56
|
+
if (JSON.stringify(keysOf(k)) !== JSON.stringify(['at', 'value']))
|
|
57
|
+
fail('DRIVER_KEYS', path, 'a key is { at, value }');
|
|
58
|
+
if (!(Number.isFinite(k.at) && k.at >= 0 && k.at <= 1))
|
|
59
|
+
fail('DRIVER_KEYS', path, 'key at must be a fraction of the duration in [0, 1]');
|
|
60
|
+
if (!(k.at > last))
|
|
61
|
+
fail('DRIVER_KEYS', path, 'key at values must strictly increase');
|
|
62
|
+
last = k.at;
|
|
63
|
+
if (!Number.isFinite(k.value))
|
|
64
|
+
fail('DRIVER_KEYS', path, 'finite key value required');
|
|
65
|
+
}
|
|
66
|
+
if (d.keys[0].at !== 0)
|
|
67
|
+
fail('DRIVER_KEYS', path, 'the first key is at 0');
|
|
68
|
+
if (!['linear', 'step'].includes(d.interpolation))
|
|
69
|
+
fail('DRIVER', path, 'interpolation is linear or step');
|
|
70
|
+
if (!['wrap', 'hold'].includes(d.loop))
|
|
71
|
+
fail('DRIVER', path, 'loop is wrap or hold');
|
|
72
|
+
if (typeof d.accumulates !== 'boolean')
|
|
73
|
+
fail('DRIVER', path, 'accumulates must be a boolean');
|
|
74
|
+
const unit = states.get(d.state);
|
|
75
|
+
if (d.accumulates && unit !== 'deg' && unit !== 'rad')
|
|
76
|
+
fail('DRIVER_STATE', path, `an accumulating driver writes an angle; ${d.state} is in ${unit}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Reads the keys at a fraction of the duration in [0, 1]. Outside the keys' span, holds the end value. */
|
|
80
|
+
function sampleKeys(driver, fraction) {
|
|
81
|
+
const keys = driver.keys;
|
|
82
|
+
if (fraction <= keys[0].at)
|
|
83
|
+
return keys[0].value;
|
|
84
|
+
const last = keys[keys.length - 1];
|
|
85
|
+
if (fraction >= last.at)
|
|
86
|
+
return last.value;
|
|
87
|
+
let i = 0;
|
|
88
|
+
while (i < keys.length - 2 && keys[i + 1].at <= fraction)
|
|
89
|
+
i++;
|
|
90
|
+
const from = keys[i], to = keys[i + 1];
|
|
91
|
+
if (driver.interpolation === 'step')
|
|
92
|
+
return from.value;
|
|
93
|
+
const span = to.at - from.at;
|
|
94
|
+
return from.value + ((fraction - from.at) / span) * (to.value - from.value);
|
|
95
|
+
}
|
|
96
|
+
/** Wraps an angle into [-half, half) for the unit: half is 180 for degrees, π for radians. */
|
|
97
|
+
export function normalisePhase(value, unit) {
|
|
98
|
+
const full = unit === 'deg' ? 360 : Math.PI * 2;
|
|
99
|
+
const half = full / 2;
|
|
100
|
+
const wrapped = ((((value + half) % full) + full) % full) - half;
|
|
101
|
+
return wrapped === half ? -half : wrapped;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The state value a driver writes at a time in seconds. Time before 0 reads as 0.
|
|
105
|
+
* Interpolation first, then the loop, then (for an accumulating driver) the phase. Never the other order.
|
|
106
|
+
*/
|
|
107
|
+
export function driverValue(driver, timeSeconds, unit = 'other') {
|
|
108
|
+
if (!Number.isFinite(timeSeconds))
|
|
109
|
+
fail('DRIVER_TIME', driver.id, 'finite time required');
|
|
110
|
+
const t = Math.max(0, timeSeconds);
|
|
111
|
+
const duration = driver.time.duration;
|
|
112
|
+
const first = driver.keys[0].value, lastKey = driver.keys[driver.keys.length - 1];
|
|
113
|
+
let value;
|
|
114
|
+
if (driver.loop === 'hold') {
|
|
115
|
+
value = sampleKeys(driver, Math.min(t / duration, 1));
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
const periods = Math.floor(t / duration);
|
|
119
|
+
const within = t - periods * duration;
|
|
120
|
+
value = sampleKeys(driver, within / duration);
|
|
121
|
+
// A wrapping accumulating driver keeps adding each period's travel, so a roller keeps turning.
|
|
122
|
+
if (driver.accumulates)
|
|
123
|
+
value += periods * (lastKey.value - first);
|
|
124
|
+
}
|
|
125
|
+
if (driver.accumulates) {
|
|
126
|
+
if (unit === 'deg' || unit === 'rad')
|
|
127
|
+
return normalisePhase(value, unit);
|
|
128
|
+
return fail('DRIVER_STATE', driver.id, 'an accumulating driver needs an angle unit');
|
|
129
|
+
}
|
|
130
|
+
return value;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Every driven state at one time, ready to pass as state overrides. The consumer chooses, per state, whether
|
|
134
|
+
* the driver or an external input is the active control source; this returns the drivers' side only.
|
|
135
|
+
*/
|
|
136
|
+
export function driverStates(asset, timeSeconds) {
|
|
137
|
+
const units = stateUnits(asset);
|
|
138
|
+
const out = {};
|
|
139
|
+
for (const d of asset.drivers ?? []) {
|
|
140
|
+
const unit = units.get(d.state);
|
|
141
|
+
out[d.state] = driverValue(d, timeSeconds, unit === 'deg' || unit === 'rad' ? unit : 'other');
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=v3-driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3-driver.js","sourceRoot":"","sources":["../src/v3-driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { type V3WorldBox } from './v3-gate.ts';
|
|
2
|
+
import { type InstanceScale } from './sizing.ts';
|
|
3
|
+
import type { AnimationChannel, Axis, FigureSource, Vec3 } from './types.ts';
|
|
4
|
+
import type { V3Asset } from './v3-asset-types.ts';
|
|
5
|
+
/** A rule the converter cannot write in V3. The asset is not converted. */
|
|
6
|
+
export interface V3ConversionRefusal {
|
|
7
|
+
code: string;
|
|
8
|
+
part?: string;
|
|
9
|
+
detail: string;
|
|
10
|
+
}
|
|
11
|
+
/** Something the V3 asset does not carry over from the V2 source. Listed, never dropped quietly. */
|
|
12
|
+
export interface V3ConversionLoss {
|
|
13
|
+
code: string;
|
|
14
|
+
part?: string;
|
|
15
|
+
detail: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Something the converter normalised on purpose, with the value before and after. Not a loss: the V3 asset draws
|
|
19
|
+
* what V2 drew. The report keeps it so nobody has to rediscover why a number differs from the source.
|
|
20
|
+
*/
|
|
21
|
+
export interface V3ConversionNote {
|
|
22
|
+
code: string;
|
|
23
|
+
part?: string;
|
|
24
|
+
detail: string;
|
|
25
|
+
}
|
|
26
|
+
export type V3ConversionResult = {
|
|
27
|
+
status: 'converted';
|
|
28
|
+
asset: V3Asset;
|
|
29
|
+
lost: V3ConversionLoss[];
|
|
30
|
+
notes: V3ConversionNote[];
|
|
31
|
+
} | {
|
|
32
|
+
status: 'refused';
|
|
33
|
+
refusals: V3ConversionRefusal[];
|
|
34
|
+
lost: V3ConversionLoss[];
|
|
35
|
+
notes: V3ConversionNote[];
|
|
36
|
+
};
|
|
37
|
+
export interface V3ConversionOptions {
|
|
38
|
+
/** Colour of every palette token the source uses. The converter invents no colours. */
|
|
39
|
+
palette: Record<string, string>;
|
|
40
|
+
/** What that palette is called, for the report (ADR-0087 ruling 5). Without it the report carries a hash. */
|
|
41
|
+
paletteId?: string;
|
|
42
|
+
/** Asset name. Defaults to the V2 `type`. */
|
|
43
|
+
name?: string;
|
|
44
|
+
}
|
|
45
|
+
/** A short stable fingerprint of the palette, so a report can say which colours it snapshotted. */
|
|
46
|
+
export declare function paletteHash(palette: Record<string, string>): string;
|
|
47
|
+
/** The V3 design inputs that stand for the instance size, in mm. */
|
|
48
|
+
export declare const V3_SIZE_INPUTS: Readonly<Record<Axis, string>>;
|
|
49
|
+
/** Rx·Ry·Rz for degrees, the order V2 (`three` 'XYZ') and V3 `rigid@1` share. */
|
|
50
|
+
export declare function eulerXYZ(rotation: Partial<Vec3> | undefined): number[][];
|
|
51
|
+
/**
|
|
52
|
+
* Convert one validated V2 source to a V3 asset that places every part where V2 places it, at every
|
|
53
|
+
* instance size in the input range. See the file comment for what is refused and what is listed as lost.
|
|
54
|
+
*/
|
|
55
|
+
export declare function convertV2ToV3(source: unknown, options: V3ConversionOptions): V3ConversionResult;
|
|
56
|
+
/** One placed body in the world, from either side, in the bottom-origin asset frame. */
|
|
57
|
+
export type WorldBox = V3WorldBox;
|
|
58
|
+
/** Values that move a V2 figure: parameter values by name and, per animation clip, an elapsed time in seconds. */
|
|
59
|
+
export interface V2MotionState {
|
|
60
|
+
parameters?: Record<string, number>;
|
|
61
|
+
clipTime?: Record<string, number>;
|
|
62
|
+
}
|
|
63
|
+
type Mat = number[][];
|
|
64
|
+
/** Rotation about a unit axis by degrees (Rodrigues), the matrix three's setFromAxisAngle builds. */
|
|
65
|
+
export declare function axisAngle(axis: Vec3, deg: number): Mat;
|
|
66
|
+
/** V2's clip length: the last key time across its channels, in seconds. */
|
|
67
|
+
export declare function v2ClipDuration(clip: {
|
|
68
|
+
channels: AnimationChannel[];
|
|
69
|
+
}): number;
|
|
70
|
+
/**
|
|
71
|
+
* Where V2 draws every part (and copy) at an instance scale and a motion state, as oriented world boxes.
|
|
72
|
+
* Motion follows things-scene: a translation channel shifts the part in the figure frame by the part's world
|
|
73
|
+
* factor; a rotation channel turns it about its own centre in its own frame (R_part·R_ch·R_part⁻¹); a joint turns
|
|
74
|
+
* everything in its frame about its sized origin, parents first (ADR-0066).
|
|
75
|
+
*/
|
|
76
|
+
export declare function v2WorldBoxes(source: FigureSource, scale: InstanceScale, state?: V2MotionState): WorldBox[];
|
|
77
|
+
/** Where a converted V3 asset draws every part at an instance size, as world boxes. */
|
|
78
|
+
export declare function v3WorldBoxes(asset: V3Asset, size: Vec3, stateOverrides?: Record<string, number>): WorldBox[];
|
|
79
|
+
export interface V3SameDifference {
|
|
80
|
+
part: string;
|
|
81
|
+
scale: InstanceScale;
|
|
82
|
+
/** Which motion state was being compared; `rest` when none. */
|
|
83
|
+
state: string;
|
|
84
|
+
what: string;
|
|
85
|
+
v2: string;
|
|
86
|
+
v3: string;
|
|
87
|
+
}
|
|
88
|
+
export interface V3SameReport {
|
|
89
|
+
same: boolean;
|
|
90
|
+
/** Instance scales checked: the base and every combination of doubled axes. */
|
|
91
|
+
scales: InstanceScale[];
|
|
92
|
+
/** Motion states checked; `rest` is always first. */
|
|
93
|
+
states: string[];
|
|
94
|
+
boxesCompared: number;
|
|
95
|
+
differences: V3SameDifference[];
|
|
96
|
+
}
|
|
97
|
+
/** ADR-0087 decision 2 tolerances. */
|
|
98
|
+
export declare const SAME_TOLERANCE_MM = 1;
|
|
99
|
+
export declare const SAME_TOLERANCE_DEG = 0.1;
|
|
100
|
+
export interface V3CompareOptions {
|
|
101
|
+
factor?: number;
|
|
102
|
+
/** Motion states to compare beyond rest, each with a label for the report. */
|
|
103
|
+
states?: Array<{
|
|
104
|
+
label: string;
|
|
105
|
+
} & V2MotionState>;
|
|
106
|
+
}
|
|
107
|
+
/** The V3 state overrides that stand for a V2 motion state: parameters by name, drivers at their clip's time. */
|
|
108
|
+
export declare function v3StateOverrides(asset: V3Asset, state: V2MotionState): Record<string, number>;
|
|
109
|
+
/**
|
|
110
|
+
* "The same" (ADR-0087 decision 2): the V2 source and the V3 asset draw the same parts, each with the same
|
|
111
|
+
* centre and local dimensions within 1 mm and the same rotation within 0.1° (as a relative angle), with the same
|
|
112
|
+
* material, at the base size and at every combination of doubled axes, at rest and at every motion state given.
|
|
113
|
+
*/
|
|
114
|
+
export declare function compareV2WithV3(source: FigureSource, asset: V3Asset, options?: V3CompareOptions | number): V3SameReport;
|
|
115
|
+
export {};
|
|
116
|
+
//# sourceMappingURL=v3-from-v2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3-from-v2.d.ts","sourceRoot":"","sources":["../src/v3-from-v2.ts"],"names":[],"mappings":"AA6BA,OAAO,EAA+B,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAK3E,OAAO,EAQL,KAAK,aAAa,EACnB,MAAM,aAAa,CAAA;AAEpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAqD,YAAY,EAAgB,IAAI,EAAE,MAAM,YAAY,CAAA;AAC7I,OAAO,KAAK,EAAE,OAAO,EAAsC,MAAM,qBAAqB,CAAA;AAKtF,2EAA2E;AAC3E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,oGAAoG;AACpG,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,gBAAgB,EAAE,CAAC;IAAC,KAAK,EAAE,gBAAgB,EAAE,CAAA;CAAE,GAC5F;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAAC,IAAI,EAAE,gBAAgB,EAAE,CAAC;IAAC,KAAK,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAAA;AAE/G,MAAM,WAAW,mBAAmB;IAClC,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,6GAA6G;IAC7G,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,mGAAmG;AACnG,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAKnE;AAED,oEAAoE;AACpE,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAA4D,CAAA;AA4EtH,iFAAiF;AACjF,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,GAAG,MAAM,EAAE,EAAE,CAaxE;AA0CD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CAwa/F;AAOD,wFAAwF;AACxF,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAA;AAEjC,kHAAkH;AAClH,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAClC;AAED,KAAK,GAAG,GAAG,MAAM,EAAE,EAAE,CAAA;AAKrB,qGAAqG;AACrG,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,GAAG,CAYtD;AAqBD,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAAE,GAAG,MAAM,CAO7E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,GAAE,aAAkB,GAAG,QAAQ,EAAE,CA0H9G;AAOD,uFAAuF;AACvF,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,QAAQ,EAAE,CAIhH;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,aAAa,CAAA;IACpB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;CACX;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAA;IACb,+EAA+E;IAC/E,MAAM,EAAE,aAAa,EAAE,CAAA;IACvB,qDAAqD;IACrD,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,gBAAgB,EAAE,CAAA;CAChC;AAED,sCAAsC;AACtC,eAAO,MAAM,iBAAiB,IAAI,CAAA;AAClC,eAAO,MAAM,kBAAkB,MAAM,CAAA;AAErC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa,CAAC,CAAA;CAClD;AAED,iHAAiH;AACjH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAW7F;AAUD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,gBAAgB,GAAG,MAAW,GAAG,YAAY,CA8D3H"}
|