@mark1russell7/strategy-space 0.0.0-bootstrap.0 → 0.0.1

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mark Russell
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,50 @@
1
1
  # @mark1russell7/strategy-space
2
2
 
3
- This version is a placeholder. The release workflow of https://github.com/mark1russell7/strategy-space publishes the real versions. Use a later version.
3
+ Layout strategies as data. A strategy space gives the stages of an engine, the options of each stage and the ranges of their params. The functions of this package check a space and its configs, and give the id of a config. They also count the space and make grids and seeded samples.
4
+
5
+ ```ts
6
+ import { checkSpace, configId, enumerateSpace, spaceSize, type StrategySpace } from "@mark1russell7/strategy-space";
7
+
8
+ const space: StrategySpace = {
9
+ schema: "strategy-space/1",
10
+ engine: "pack",
11
+ version: "0.0.1",
12
+ stages: [
13
+ { name: "order", options: [{ id: "area", params: [] }, { id: "height", params: [] }] },
14
+ { name: "placement", options: [{ id: "shelf", params: [{ name: "gap", kind: "int", min: 0, max: 8, default: 2 }] }] },
15
+ ],
16
+ };
17
+
18
+ checkSpace(space); // [] : the space is good
19
+ spaceSize(space, { levels: 3 }).base; // 6n : 2 orders, 3 levels of gap
20
+ const configs = enumerateSpace(space, { mode: "sample", n: 4, seed: 7 });
21
+ configId(space, configs[0]!); // the first 16 hex characters of a SHA-256
22
+ ```
23
+
24
+ ## What the package has
25
+
26
+ | Area | Functions |
27
+ | --- | --- |
28
+ | The checks | `checkSpace`, `checkConfig`, `paramProblem` |
29
+ | The id of a config | `canonicalConfig`, `configId` |
30
+ | The count | `spaceSize`, `paramLevels`, `spaceShapeKinds` |
31
+ | The configs | `enumerateSpace` (the modes `grid` and `sample`, the draws `uniform` and `walk`, fixed options) |
32
+ | Two spaces as one | `productSpace`, `joinConfigs`, `splitConfig` |
33
+ | The option schema of a strategy | `listOptions`, `optionDefaults`, `checkOptions`, `clampOptions`, `checkSchema` |
34
+ | The sweeps of the options | `sweepValues`, `sweepOf`, `sweepGrid` |
35
+ | The distinctness gate | `distinctness`, `distinctCount` |
36
+
37
+ [`docs/STRATEGY-SPACE.md`](../../docs/STRATEGY-SPACE.md) tells the schema `strategy-space/1` and the rules of each function. [`docs/DISTINCT.md`](../../docs/DISTINCT.md) tells the gate.
38
+
39
+ ## Shape kinds
40
+
41
+ An option can give the shape kinds that it supports, as tags. The option `kinds` gives the list of the known tags. Without `kinds`, each string with text is a kind.
42
+
43
+ ```ts
44
+ checkSpace(space, { kinds: ["rect", "circle"] });
45
+ spaceSize(space, { levels: 3, shapes: ["circle"], kinds: ["rect", "circle"] });
46
+ ```
47
+
48
+ ## The same ids as `layout-contract`
49
+
50
+ The schema, the ids and the samples come from `layout-contract` 0.6.1 with no change. A config has the same `configId`, and a seed gives the same sample. The hash and the random numbers come from `@mark1russell7/rigor-generators`.
@@ -0,0 +1,10 @@
1
+ /** One broken claim, with the ids of the inputs that break it. `layout-contract` uses the same form for the checks of a corpus. */
2
+ export interface ClaimBreak {
3
+ /** The name of the claim, for example `schema`, `unknown`, `shape` or `members`. */
4
+ readonly claim: string;
5
+ /** The text of the break. */
6
+ readonly detail: string;
7
+ /** The ids of the inputs that break the claim. The list is empty when the break has no input. */
8
+ readonly inputs: readonly string[];
9
+ }
10
+ //# sourceMappingURL=claim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claim.d.ts","names":[],"sources":["../src/claim.ts"],"mappings":";iBAGiB;;WAEN;;WAEA;;WAEA"}
@@ -0,0 +1,49 @@
1
+ /** The hashes of the outputs of one strategy: one hash for each input, by the id of the input. `probeHash` of `layout-contract` gives one hash. */
2
+ export interface OutputHashes {
3
+ readonly id: string;
4
+ readonly stage: string;
5
+ readonly outputs: Readonly<Record<string, string>>;
6
+ }
7
+ /** The options of the gate. */
8
+ export interface DistinctOptions {
9
+ /** The ids of the inputs of the set. Each variant needs a hash on each of them. */
10
+ readonly inputs: readonly string[];
11
+ /** The hash that a strategy gives for an input that it refuses, for example `REFUSED_PROBE` of `layout-contract`. A refused input is not a difference. */
12
+ readonly refused?: string;
13
+ }
14
+ /**
15
+ * The verdict of the gate on one variant.
16
+ * `distinct`: on at least one input, its output differs from the output of each operator of its stage.
17
+ * `same`: an operator of its stage has the same hash on each input of the set.
18
+ * `no-read`: the gate cannot decide. An input has no hash, or no input shows a difference from an operator that is not the same.
19
+ */
20
+ export type DistinctVerdict = "distinct" | "same" | "no-read";
21
+ /** The row of the gate for one variant. */
22
+ export interface DistinctRow {
23
+ readonly id: string;
24
+ readonly stage: string;
25
+ readonly verdict: DistinctVerdict;
26
+ /** The first id of the variants with the same hash on each input. A variant with a different id is a duplicate of it. */
27
+ readonly canonical: string;
28
+ /** The operators with the same hash on each input. */
29
+ readonly sameAs: readonly string[];
30
+ /** The operators with no difference on a compared input, and no equal hash on each input. */
31
+ readonly undecided: readonly string[];
32
+ /** The inputs of the set with no hash for this variant. */
33
+ readonly missing: readonly string[];
34
+ /** The first input where the outputs differ from each operator, by the id of the operator. */
35
+ readonly differsOn: Readonly<Record<string, string>>;
36
+ }
37
+ /**
38
+ * This function gives the verdict of the gate on each variant, sorted by id.
39
+ * It compares a variant only with the operators of its stage. A stage with no operator gives `distinct` to each complete variant.
40
+ *
41
+ * @param operators - The hashes of the existing operators.
42
+ * @param variants - The hashes of the variants that the gate examines.
43
+ * @param options - The inputs of the set and the refused hash.
44
+ * @throws Error when an id is in the operators or in the variants more than once, or when the set has no input.
45
+ */
46
+ export declare function distinctness(operators: readonly OutputHashes[], variants: readonly OutputHashes[], options: DistinctOptions): DistinctRow[];
47
+ /** This function gives the count of the distinct variants: the canonical variants with the verdict `distinct`. A duplicate does not count. */
48
+ export declare function distinctCount(rows: readonly DistinctRow[]): number;
49
+ //# sourceMappingURL=distinct.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distinct.d.ts","names":[],"sources":["../src/distinct.ts"],"mappings":";iBAIiB;WACN;WACA;WACA,SAAS,SAAS;;;iBAIZ;;WAEN;;WAEA;;;;;;;;YASC;;iBAGK;WACN;WACA;WACA,SAAS;;WAET;;WAEA;;WAEA;;WAEA;;WAEA,WAAW,SAAS;;;;;;;;;;;wBAuBf,aAAa,oBAAoB,gBAAgB,mBAAmB,gBAAgB,SAAS,kBAAkB;;wBAiC/G,cAAc,eAAe"}
@@ -0,0 +1,61 @@
1
+ // src/distinct.ts
2
+ /** This function gives the key of the hashes of a strategy on the inputs, in the order of the inputs. */
3
+ function vectorKey(s, inputs) {
4
+ return JSON.stringify(inputs.map((b) => s.outputs[b] ?? null));
5
+ }
6
+ /** This function gives the ids that are in the list more than once. */
7
+ function repeated(ids) {
8
+ const seen = /* @__PURE__ */ new Set();
9
+ return [...new Set(ids.filter((id) => seen.has(id) || !seen.add(id)))];
10
+ }
11
+ /**
12
+ * This function gives the verdict of the gate on each variant, sorted by id.
13
+ * It compares a variant only with the operators of its stage. A stage with no operator gives `distinct` to each complete variant.
14
+ *
15
+ * @param operators - The hashes of the existing operators.
16
+ * @param variants - The hashes of the variants that the gate examines.
17
+ * @param options - The inputs of the set and the refused hash.
18
+ * @throws Error when an id is in the operators or in the variants more than once, or when the set has no input.
19
+ */
20
+ function distinctness(operators, variants, options) {
21
+ const { inputs, refused } = options;
22
+ if (inputs.length === 0) throw new Error("The gate has no input.");
23
+ const twice = repeated([...operators.map((o) => o.id), ...variants.map((v) => v.id)]);
24
+ if (twice.length > 0) throw new Error(`These ids are not unique: ${twice.join(", ")}.`);
25
+ const canonical = /* @__PURE__ */ new Map();
26
+ for (const v of [...variants].sort((a, b) => a.id < b.id ? -1 : 1)) {
27
+ const key = `${v.stage}\u0000${vectorKey(v, inputs)}`;
28
+ if (!canonical.has(key)) canonical.set(key, v.id);
29
+ }
30
+ const compared = (a, b) => a !== void 0 && b !== void 0 && a !== refused && b !== refused;
31
+ return [...variants].sort((a, b) => a.id < b.id ? -1 : 1).map((v) => {
32
+ const missing = inputs.filter((b) => v.outputs[b] === void 0);
33
+ const sameAs = [];
34
+ const undecided = [];
35
+ const differsOn = {};
36
+ for (const op of operators.filter((o) => o.stage === v.stage).sort((a, b) => a.id < b.id ? -1 : 1)) {
37
+ const input = inputs.find((b) => compared(v.outputs[b], op.outputs[b]) && v.outputs[b] !== op.outputs[b]);
38
+ if (input !== void 0) differsOn[op.id] = input;
39
+ else if (missing.length === 0 && inputs.every((b) => op.outputs[b] === v.outputs[b])) sameAs.push(op.id);
40
+ else undecided.push(op.id);
41
+ }
42
+ const verdict = missing.length > 0 ? "no-read" : sameAs.length > 0 ? "same" : undecided.length > 0 ? "no-read" : "distinct";
43
+ return {
44
+ id: v.id,
45
+ stage: v.stage,
46
+ verdict,
47
+ canonical: canonical.get(`${v.stage}\u0000${vectorKey(v, inputs)}`),
48
+ sameAs,
49
+ undecided,
50
+ missing,
51
+ differsOn
52
+ };
53
+ });
54
+ }
55
+ /** This function gives the count of the distinct variants: the canonical variants with the verdict `distinct`. A duplicate does not count. */
56
+ function distinctCount(rows) {
57
+ return rows.filter((r) => r.verdict === "distinct" && r.canonical === r.id).length;
58
+ }
59
+ export { distinctCount, distinctness };
60
+
61
+ //# sourceMappingURL=distinct.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distinct.js","names":[],"sources":["../src/distinct.ts"],"sourcesContent":["// The distinctness gate (`docs/DISTINCT.md`). A variant counts only when its output differs from each operator of its stage on at least one input.\n// The caller gives the hash of the output of each strategy on each input of a fixed set. The gate came from `highways` 27b40c8.\n\n/** The hashes of the outputs of one strategy: one hash for each input, by the id of the input. `probeHash` of `layout-contract` gives one hash. */\nexport interface OutputHashes {\n readonly id: string;\n readonly stage: string;\n readonly outputs: Readonly<Record<string, string>>;\n}\n\n/** The options of the gate. */\nexport interface DistinctOptions {\n /** The ids of the inputs of the set. Each variant needs a hash on each of them. */\n readonly inputs: readonly string[];\n /** The hash that a strategy gives for an input that it refuses, for example `REFUSED_PROBE` of `layout-contract`. A refused input is not a difference. */\n readonly refused?: string;\n}\n\n/**\n * The verdict of the gate on one variant.\n * `distinct`: on at least one input, its output differs from the output of each operator of its stage.\n * `same`: an operator of its stage has the same hash on each input of the set.\n * `no-read`: the gate cannot decide. An input has no hash, or no input shows a difference from an operator that is not the same.\n */\nexport type DistinctVerdict = \"distinct\" | \"same\" | \"no-read\";\n\n/** The row of the gate for one variant. */\nexport interface DistinctRow {\n readonly id: string;\n readonly stage: string;\n readonly verdict: DistinctVerdict;\n /** The first id of the variants with the same hash on each input. A variant with a different id is a duplicate of it. */\n readonly canonical: string;\n /** The operators with the same hash on each input. */\n readonly sameAs: readonly string[];\n /** The operators with no difference on a compared input, and no equal hash on each input. */\n readonly undecided: readonly string[];\n /** The inputs of the set with no hash for this variant. */\n readonly missing: readonly string[];\n /** The first input where the outputs differ from each operator, by the id of the operator. */\n readonly differsOn: Readonly<Record<string, string>>;\n}\n\n/** This function gives the key of the hashes of a strategy on the inputs, in the order of the inputs. */\nfunction vectorKey(s: OutputHashes, inputs: readonly string[]): string {\n return JSON.stringify(inputs.map((b) => s.outputs[b] ?? null));\n}\n\n/** This function gives the ids that are in the list more than once. */\nfunction repeated(ids: readonly string[]): string[] {\n const seen = new Set<string>();\n return [...new Set(ids.filter((id) => seen.has(id) || !seen.add(id)))];\n}\n\n/**\n * This function gives the verdict of the gate on each variant, sorted by id.\n * It compares a variant only with the operators of its stage. A stage with no operator gives `distinct` to each complete variant.\n *\n * @param operators - The hashes of the existing operators.\n * @param variants - The hashes of the variants that the gate examines.\n * @param options - The inputs of the set and the refused hash.\n * @throws Error when an id is in the operators or in the variants more than once, or when the set has no input.\n */\nexport function distinctness(operators: readonly OutputHashes[], variants: readonly OutputHashes[], options: DistinctOptions): DistinctRow[] {\n const { inputs, refused } = options;\n if (inputs.length === 0) throw new Error(\"The gate has no input.\");\n const twice = repeated([...operators.map((o) => o.id), ...variants.map((v) => v.id)]);\n if (twice.length > 0) throw new Error(`These ids are not unique: ${twice.join(\", \")}.`);\n\n // The first id of each class of variants with the same hashes.\n const canonical = new Map<string, string>();\n for (const v of [...variants].sort((a, b) => (a.id < b.id ? -1 : 1))) {\n const key = `${v.stage}\\u0000${vectorKey(v, inputs)}`;\n if (!canonical.has(key)) canonical.set(key, v.id);\n }\n\n const compared = (a: string | undefined, b: string | undefined): boolean => a !== undefined && b !== undefined && a !== refused && b !== refused;\n return [...variants]\n .sort((a, b) => (a.id < b.id ? -1 : 1))\n .map((v) => {\n const missing = inputs.filter((b) => v.outputs[b] === undefined);\n const sameAs: string[] = [];\n const undecided: string[] = [];\n const differsOn: Record<string, string> = {};\n for (const op of operators.filter((o) => o.stage === v.stage).sort((a, b) => (a.id < b.id ? -1 : 1))) {\n const input = inputs.find((b) => compared(v.outputs[b], op.outputs[b]) && v.outputs[b] !== op.outputs[b]);\n if (input !== undefined) differsOn[op.id] = input;\n else if (missing.length === 0 && inputs.every((b) => op.outputs[b] === v.outputs[b])) sameAs.push(op.id);\n else undecided.push(op.id);\n }\n const verdict: DistinctVerdict = missing.length > 0 ? \"no-read\" : sameAs.length > 0 ? \"same\" : undecided.length > 0 ? \"no-read\" : \"distinct\";\n return { id: v.id, stage: v.stage, verdict, canonical: canonical.get(`${v.stage}\\u0000${vectorKey(v, inputs)}`)!, sameAs, undecided, missing, differsOn };\n });\n}\n\n/** This function gives the count of the distinct variants: the canonical variants with the verdict `distinct`. A duplicate does not count. */\nexport function distinctCount(rows: readonly DistinctRow[]): number {\n return rows.filter((r) => r.verdict === \"distinct\" && r.canonical === r.id).length;\n}\n"],"mappings":";;AA4CA,SAAS,UAAU,GAAiB,QAAmC;CACrE,OAAO,KAAK,UAAU,OAAO,KAAK,MAAM,EAAE,QAAQ,MAAM,IAAI,CAAC;AAC/D;;AAGA,SAAS,SAAS,KAAkC;CAClD,MAAM,uBAAO,IAAI,IAAY;CAC7B,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,QAAQ,OAAO,KAAK,IAAI,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;AACvE;;;;;;;;;;AAWA,SAAgB,aAAa,WAAoC,UAAmC,SAAyC;CAC3I,MAAM,EAAE,QAAQ,YAAY;CAC5B,IAAI,OAAO,WAAW,GAAG,MAAM,IAAI,MAAM,wBAAwB;CACjE,MAAM,QAAQ,SAAS,CAAC,GAAG,UAAU,KAAK,MAAM,EAAE,EAAE,GAAG,GAAG,SAAS,KAAK,MAAM,EAAE,EAAE,CAAC,CAAC;CACpF,IAAI,MAAM,SAAS,GAAG,MAAM,IAAI,MAAM,6BAA6B,MAAM,KAAK,IAAI,EAAE,EAAE;CAGtF,MAAM,4BAAY,IAAI,IAAoB;CAC1C,KAAK,MAAM,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,MAAM,GAAG,MAAO,EAAE,KAAK,EAAE,KAAK,KAAK,CAAE,GAAG;EACpE,MAAM,MAAM,GAAG,EAAE,MAAM,QAAQ,UAAU,GAAG,MAAM;EAClD,IAAI,CAAC,UAAU,IAAI,GAAG,GAAG,UAAU,IAAI,KAAK,EAAE,EAAE;CAClD;CAEA,MAAM,YAAY,GAAuB,MAAmC,MAAM,KAAA,KAAa,MAAM,KAAA,KAAa,MAAM,WAAW,MAAM;CACzI,OAAO,CAAC,GAAG,QAAQ,CAAC,CACjB,MAAM,GAAG,MAAO,EAAE,KAAK,EAAE,KAAK,KAAK,CAAE,CAAC,CACtC,KAAK,MAAM;EACV,MAAM,UAAU,OAAO,QAAQ,MAAM,EAAE,QAAQ,OAAO,KAAA,CAAS;EAC/D,MAAM,SAAmB,CAAC;EAC1B,MAAM,YAAsB,CAAC;EAC7B,MAAM,YAAoC,CAAC;EAC3C,KAAK,MAAM,MAAM,UAAU,QAAQ,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,MAAO,EAAE,KAAK,EAAE,KAAK,KAAK,CAAE,GAAG;GACpG,MAAM,QAAQ,OAAO,MAAM,MAAM,SAAS,EAAE,QAAQ,IAAI,GAAG,QAAQ,EAAE,KAAK,EAAE,QAAQ,OAAO,GAAG,QAAQ,EAAE;GACxG,IAAI,UAAU,KAAA,GAAW,UAAU,GAAG,MAAM;QACvC,IAAI,QAAQ,WAAW,KAAK,OAAO,OAAO,MAAM,GAAG,QAAQ,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,KAAK,GAAG,EAAE;QAClG,UAAU,KAAK,GAAG,EAAE;EAC3B;EACA,MAAM,UAA2B,QAAQ,SAAS,IAAI,YAAY,OAAO,SAAS,IAAI,SAAS,UAAU,SAAS,IAAI,YAAY;EAClI,OAAO;GAAE,IAAI,EAAE;GAAI,OAAO,EAAE;GAAO;GAAS,WAAW,UAAU,IAAI,GAAG,EAAE,MAAM,QAAQ,UAAU,GAAG,MAAM,GAAG;GAAI;GAAQ;GAAW;GAAS;EAAU;CAC1J,CAAC;AACL;;AAGA,SAAgB,cAAc,MAAsC;CAClE,OAAO,KAAK,QAAQ,MAAM,EAAE,YAAY,cAAc,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;AAC9E"}
@@ -0,0 +1,5 @@
1
+ import { ClaimBreak } from "./claim.js";
2
+ import { DistinctOptions, DistinctRow, DistinctVerdict, OutputHashes, distinctCount, distinctness } from "./distinct.js";
3
+ import { AnyOption, BooleanOption, DeclaredStrategy, EnumOption, ListItem, NoDefault, NoDefaultReason, NumberOption, OptionDeclaration, OptionIssue, OptionScale, OptionSchema, OptionSetting, SweepOptions, ValueOption, checkOptions, checkSchema, clampOptions, declarationIssues, listOptions, optionDefaults, optionIssue, sweepGrid, sweepOf, sweepValues } from "./strategy-options.js";
4
+ import { EnumerateOptions, GridOptions, KindOptions, MemberRule, OptionRef, OptionSupports, ParamKind, ParamValue, ParamWhen, STRATEGY_SPACE_SCHEMA, SampleOptions, ShapeFilter, SpaceConstraint, SpaceParam, SpaceSize, SpaceSizeOptions, SpaceStage, StageChoice, StageOption, StrategyConfig, StrategySpace, canonicalConfig, checkConfig, checkSpace, configId, enumerateSpace, joinConfigs, paramActive, paramLevels, paramProblem, paramValue, productSpace, spaceShapeKinds, spaceSize, splitConfig } from "./strategy-space.js";
5
+ export { AnyOption, BooleanOption, type ClaimBreak, DeclaredStrategy, DistinctOptions, DistinctRow, DistinctVerdict, EnumOption, EnumerateOptions, GridOptions, KindOptions, ListItem, MemberRule, NoDefault, NoDefaultReason, NumberOption, OptionDeclaration, OptionIssue, OptionRef, OptionScale, OptionSchema, OptionSetting, OptionSupports, OutputHashes, ParamKind, ParamValue, ParamWhen, STRATEGY_SPACE_SCHEMA, SampleOptions, ShapeFilter, SpaceConstraint, SpaceParam, SpaceSize, SpaceSizeOptions, SpaceStage, StageChoice, StageOption, StrategyConfig, StrategySpace, SweepOptions, ValueOption, canonicalConfig, checkConfig, checkOptions, checkSchema, checkSpace, clampOptions, configId, declarationIssues, distinctCount, distinctness, enumerateSpace, joinConfigs, listOptions, optionDefaults, optionIssue, paramActive, paramLevels, paramProblem, paramValue, productSpace, spaceShapeKinds, spaceSize, splitConfig, sweepGrid, sweepOf, sweepValues };
package/build/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { distinctCount, distinctness } from "./distinct.js";
2
+ import { checkOptions, checkSchema, clampOptions, declarationIssues, listOptions, optionDefaults, optionIssue, sweepGrid, sweepOf, sweepValues } from "./strategy-options.js";
3
+ import { STRATEGY_SPACE_SCHEMA, canonicalConfig, checkConfig, checkSpace, configId, enumerateSpace, joinConfigs, paramActive, paramLevels, paramProblem, paramValue, productSpace, spaceShapeKinds, spaceSize, splitConfig } from "./strategy-space.js";
4
+ export { STRATEGY_SPACE_SCHEMA, canonicalConfig, checkConfig, checkOptions, checkSchema, checkSpace, clampOptions, configId, declarationIssues, distinctCount, distinctness, enumerateSpace, joinConfigs, listOptions, optionDefaults, optionIssue, paramActive, paramLevels, paramProblem, paramValue, productSpace, spaceShapeKinds, spaceSize, splitConfig, sweepGrid, sweepOf, sweepValues };
@@ -0,0 +1,48 @@
1
+ // src/space-walk.ts
2
+ const refMatches = (ref, choices) => (choices.get(ref.stage) ?? null) === ref.option;
3
+ /** This function tells if the option choices keep a constraint. */
4
+ function holds(c, choices) {
5
+ if (!refMatches(c.if, choices)) return true;
6
+ return "not" in c.then ? !refMatches(c.then.not, choices) : refMatches(c.then, choices);
7
+ }
8
+ const otherStage = (c) => "not" in c.then ? c.then.not.stage : c.then.stage;
9
+ /** This function tells if an option of a stage keeps each constraint between that stage and the stages that a walk has fixed. */
10
+ function fitsWalk(constraints, fixed, stage, id) {
11
+ fixed.set(stage, id);
12
+ const ok = constraints.every((c) => !fixed.has(c.if.stage === stage ? otherStage(c) : c.if.stage) || holds(c, fixed));
13
+ fixed.delete(stage);
14
+ return ok;
15
+ }
16
+ /**
17
+ * This function gives the plan of a walk. Stages of equal size keep the order of the space.
18
+ * The stages of `first` go first, for example the stages of the sample option `fixed`. Thus the other stages draw only from the options that keep the constraints with them.
19
+ */
20
+ function walkPlan(stages, lists, constraints, n, first = /* @__PURE__ */ new Set()) {
21
+ return {
22
+ stages,
23
+ lists,
24
+ n,
25
+ order: stages.map((_, k) => k).sort((a, b) => Number(first.has(stages[b].name)) - Number(first.has(stages[a].name)) || lists[b].length - lists[a].length || a - b),
26
+ naming: stages.map((s) => constraints.filter((c) => c.if.stage === s.name || otherStage(c) === s.name))
27
+ };
28
+ }
29
+ /**
30
+ * This function gives the options of one point of a walk. It fixes the largest stage first. Thus that stage keeps its equal strata, and the constraints limit only the smaller stages.
31
+ * The value `picks[k][i]` is the stratum of the stage `k` for the point `i`. A stage with no open option gets `null`, and the caller rejects that point.
32
+ * The argument `fits` lets a test give a fault. The default is `fitsWalk`.
33
+ */
34
+ function walkPoint(plan, picks, i, fits = fitsWalk) {
35
+ const fixed = /* @__PURE__ */ new Map();
36
+ const out = /* @__PURE__ */ new Map();
37
+ for (const k of plan.order) {
38
+ const s = plan.stages[k];
39
+ const open = plan.lists[k].filter((o) => fits(plan.naming[k], fixed, s.name, o?.id ?? null));
40
+ const o = open[Math.floor(picks[k][i] * open.length / plan.n)] ?? null;
41
+ fixed.set(s.name, o?.id ?? null);
42
+ out.set(s.name, o);
43
+ }
44
+ return out;
45
+ }
46
+ export { fitsWalk, holds, walkPlan, walkPoint };
47
+
48
+ //# sourceMappingURL=space-walk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"space-walk.js","names":[],"sources":["../src/space-walk.ts"],"sourcesContent":["// The walk draw of a sample of a strategy space (`docs/STRATEGY-SPACE.md`). The package root does not export this file.\nimport type { OptionRef, SpaceConstraint, SpaceStage, StageOption } from \"./strategy-space.ts\";\n\nconst refMatches = (ref: OptionRef, choices: ReadonlyMap<string, string | null>): boolean => (choices.get(ref.stage) ?? null) === ref.option;\n\n/** This function tells if the option choices keep a constraint. */\nexport function holds(c: SpaceConstraint, choices: ReadonlyMap<string, string | null>): boolean {\n if (!refMatches(c.if, choices)) return true;\n return \"not\" in c.then ? !refMatches(c.then.not, choices) : refMatches(c.then, choices);\n}\n\nconst otherStage = (c: SpaceConstraint): string => (\"not\" in c.then ? c.then.not.stage : c.then.stage);\n\n/** This function tells if an option of a stage keeps each constraint between that stage and the stages that a walk has fixed. */\nexport function fitsWalk(constraints: readonly SpaceConstraint[], fixed: Map<string, string | null>, stage: string, id: string | null): boolean {\n fixed.set(stage, id);\n const ok = constraints.every((c) => !fixed.has(c.if.stage === stage ? otherStage(c) : c.if.stage) || holds(c, fixed));\n fixed.delete(stage);\n return ok;\n}\n\n/** The order of the stages of a walk, and the constraints that name each stage. */\nexport interface WalkPlan {\n /** The stages of the space. */\n readonly stages: readonly SpaceStage[];\n /** The options of each stage for a draw. */\n readonly lists: readonly (readonly (StageOption | null)[])[];\n /** The indexes of the stages. The stages of `first` come first, in the order of the space. The others follow, from the largest stage to the smallest. */\n readonly order: readonly number[];\n /** The constraints that name each stage. */\n readonly naming: readonly (readonly SpaceConstraint[])[];\n /** The count of points of a round. */\n readonly n: number;\n}\n\n/**\n * This function gives the plan of a walk. Stages of equal size keep the order of the space.\n * The stages of `first` go first, for example the stages of the sample option `fixed`. Thus the other stages draw only from the options that keep the constraints with them.\n */\nexport function walkPlan(\n stages: readonly SpaceStage[],\n lists: readonly (readonly (StageOption | null)[])[],\n constraints: readonly SpaceConstraint[],\n n: number,\n first: ReadonlySet<string> = new Set(),\n): WalkPlan {\n return {\n stages,\n lists,\n n,\n order: stages.map((_, k) => k).sort((a, b) => Number(first.has(stages[b]!.name)) - Number(first.has(stages[a]!.name)) || lists[b]!.length - lists[a]!.length || a - b),\n naming: stages.map((s) => constraints.filter((c) => c.if.stage === s.name || otherStage(c) === s.name)),\n };\n}\n\n/**\n * This function gives the options of one point of a walk. It fixes the largest stage first. Thus that stage keeps its equal strata, and the constraints limit only the smaller stages.\n * The value `picks[k][i]` is the stratum of the stage `k` for the point `i`. A stage with no open option gets `null`, and the caller rejects that point.\n * The argument `fits` lets a test give a fault. The default is `fitsWalk`.\n */\nexport function walkPoint(plan: WalkPlan, picks: readonly (readonly number[])[], i: number, fits: typeof fitsWalk = fitsWalk): Map<string, StageOption | null> {\n const fixed = new Map<string, string | null>();\n const out = new Map<string, StageOption | null>();\n for (const k of plan.order) {\n const s = plan.stages[k]!;\n const open = plan.lists[k]!.filter((o) => fits(plan.naming[k]!, fixed, s.name, o?.id ?? null));\n const o = open[Math.floor((picks[k]![i]! * open.length) / plan.n)] ?? null;\n fixed.set(s.name, o?.id ?? null);\n out.set(s.name, o);\n }\n return out;\n}\n"],"mappings":";AAGA,MAAM,cAAc,KAAgB,aAA0D,QAAQ,IAAI,IAAI,KAAK,KAAK,UAAU,IAAI;;AAGtI,SAAgB,MAAM,GAAoB,SAAsD;CAC9F,IAAI,CAAC,WAAW,EAAE,IAAI,OAAO,GAAG,OAAO;CACvC,OAAO,SAAS,EAAE,OAAO,CAAC,WAAW,EAAE,KAAK,KAAK,OAAO,IAAI,WAAW,EAAE,MAAM,OAAO;AACxF;AAEA,MAAM,cAAc,MAAgC,SAAS,EAAE,OAAO,EAAE,KAAK,IAAI,QAAQ,EAAE,KAAK;;AAGhG,SAAgB,SAAS,aAAyC,OAAmC,OAAe,IAA4B;CAC9I,MAAM,IAAI,OAAO,EAAE;CACnB,MAAM,KAAK,YAAY,OAAO,MAAM,CAAC,MAAM,IAAI,EAAE,GAAG,UAAU,QAAQ,WAAW,CAAC,IAAI,EAAE,GAAG,KAAK,KAAK,MAAM,GAAG,KAAK,CAAC;CACpH,MAAM,OAAO,KAAK;CAClB,OAAO;AACT;;;;;AAoBA,SAAgB,SACd,QACA,OACA,aACA,GACA,wBAA6B,IAAI,IAAI,GAC3B;CACV,OAAO;EACL;EACA;EACA;EACA,OAAO,OAAO,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,OAAO,MAAM,IAAI,OAAO,EAAE,CAAE,IAAI,CAAC,IAAI,OAAO,MAAM,IAAI,OAAO,EAAE,CAAE,IAAI,CAAC,KAAK,MAAM,EAAE,CAAE,SAAS,MAAM,EAAE,CAAE,UAAU,IAAI,CAAC;EACrK,QAAQ,OAAO,KAAK,MAAM,YAAY,QAAQ,MAAM,EAAE,GAAG,UAAU,EAAE,QAAQ,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC;CACxG;AACF;;;;;;AAOA,SAAgB,UAAU,MAAgB,OAAuC,GAAW,OAAwB,UAA2C;CAC7J,MAAM,wBAAQ,IAAI,IAA2B;CAC7C,MAAM,sBAAM,IAAI,IAAgC;CAChD,KAAK,MAAM,KAAK,KAAK,OAAO;EAC1B,MAAM,IAAI,KAAK,OAAO;EACtB,MAAM,OAAO,KAAK,MAAM,EAAE,CAAE,QAAQ,MAAM,KAAK,KAAK,OAAO,IAAK,OAAO,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;EAC7F,MAAM,IAAI,KAAK,KAAK,MAAO,MAAM,EAAE,CAAE,KAAM,KAAK,SAAU,KAAK,CAAC,MAAM;EACtE,MAAM,IAAI,EAAE,MAAM,GAAG,MAAM,IAAI;EAC/B,IAAI,IAAI,EAAE,MAAM,CAAC;CACnB;CACA,OAAO;AACT"}
@@ -0,0 +1,189 @@
1
+ import { ParamWhen } from "./strategy-space.js";
2
+ /** The scale of a number option. A sweep on the scale `log` gives values with equal ratios, not with equal differences. */
3
+ export type OptionScale = "linear" | "log";
4
+ /** The reason why an option has no default value. The strategy reads the absence, the caller sets it, the strategy calculates it, or the default is code. */
5
+ export type NoDefaultReason = "unset" | "required" | "derived" | "function";
6
+ /** The statement of an option without a default value that JSON can hold. */
7
+ export interface NoDefault {
8
+ readonly reason: NoDefaultReason;
9
+ /** One short sentence that tells what the strategy does without a value. */
10
+ readonly describe: string;
11
+ }
12
+ /** The fields of each option declaration. */
13
+ interface OptionBase {
14
+ /** One short sentence that tells what the option sets. The site and the documents show it. */
15
+ readonly describe: string;
16
+ /** This field tells why the option has no default. The catalog of an engine has this field or a `default` on each option. */
17
+ readonly noDefault?: NoDefault;
18
+ /** The option is active only when an earlier option of the same strategy has one of these values. */
19
+ readonly when?: ParamWhen;
20
+ }
21
+ /**
22
+ * The declaration of a number option. The range from `min` to `max` is the range of a control and of a sweep.
23
+ * The strategy can take a value outside the range. `checkOptions` reports such a value, and `clampOptions` moves it into the range.
24
+ */
25
+ export interface NumberOption extends OptionBase {
26
+ /** The type `integer` takes only whole numbers. */
27
+ readonly type: "number" | "integer";
28
+ readonly min: number;
29
+ readonly max: number;
30
+ /** The grain of a control and of a sweep. A value off the step is valid. Without it, the grain is free (or 1 for an integer). */
31
+ readonly step?: number;
32
+ /** The scale of a control and of a sweep. The default is `linear`. The scale `log` needs a `min` above 0. */
33
+ readonly scale?: OptionScale;
34
+ /** These values are valid outside the range. For example, `Infinity` sets no limit. */
35
+ readonly special?: readonly number[];
36
+ /** These values are the notable values of the option: the default and the values of the sweeps of the benchmark. */
37
+ readonly marks?: readonly number[];
38
+ /**
39
+ * These values are the only valid values of the option, in the order of a control. A control shows them as a list, and a sweep gives them.
40
+ * Without them, each value on the range is valid.
41
+ */
42
+ readonly values?: readonly number[];
43
+ /** The strategy uses this value when the caller and `defaults` give no value. */
44
+ readonly default?: number;
45
+ }
46
+ /** The declaration of a boolean option. */
47
+ export interface BooleanOption extends OptionBase {
48
+ readonly type: "boolean";
49
+ /** The strategy uses this value when the caller and `defaults` give no value. */
50
+ readonly default?: boolean;
51
+ }
52
+ /** The declaration of an option with a fixed list of string values. */
53
+ export interface EnumOption<V extends string = string> extends OptionBase {
54
+ readonly type: "enum";
55
+ /** The values of the option, in the order of a control. */
56
+ readonly values: readonly V[];
57
+ /**
58
+ * With `function`, the option also takes a rule of the caller in place of a name. A control sets only the names.
59
+ * Each name is a known rule of the strategy.
60
+ */
61
+ readonly custom?: "function";
62
+ /** The strategy uses this value when the caller and `defaults` give no value. */
63
+ readonly default?: V;
64
+ }
65
+ /**
66
+ * The declaration of an option that a control or a sweep cannot set from a range.
67
+ * The type `function` is a rule, `strategy` is a strategy of the step `step`, `list` is an array and `object` is any other object.
68
+ */
69
+ export interface ValueOption<V = unknown, S extends string = string> extends OptionBase {
70
+ readonly type: "function" | "strategy" | "list" | "object";
71
+ /** The step of the strategy, for the type `strategy`. A control lists the strategies of this step of a registry. */
72
+ readonly step?: S;
73
+ /** The kinds of strategy that the option takes, for the type `strategy`. Without them, the option takes each kind. */
74
+ readonly kinds?: readonly string[];
75
+ /** The key of the option that holds the options of the chosen strategy, for the type `strategy`. */
76
+ readonly optionsKey?: string;
77
+ /** The value `true` lets a value hold its options: a key, or an object with the fields `strategy`, `options` and `id`. This field is for the type `strategy`, and also for an item of a list. */
78
+ readonly inlineOptions?: boolean;
79
+ /** The value `false` leaves out the opt-in strategies, because the option finds only the default set of the engine. This field is for the type `strategy`. */
80
+ readonly optIn?: boolean;
81
+ /** For each dimension of `supports`, the value that a chosen strategy must take. This field is for the type `strategy`, and also for an item of a list. */
82
+ readonly needs?: Readonly<Record<string, string>>;
83
+ /** The declaration of each item, for the type `list`. */
84
+ readonly of?: ListItem<S>;
85
+ /** The smallest number of items, for the type `list`. */
86
+ readonly min?: number;
87
+ /** The largest number of items, for the type `list`. */
88
+ readonly max?: number;
89
+ /** The strategy uses this value when the caller and `defaults` give no value. */
90
+ readonly default?: V;
91
+ }
92
+ /** The declaration of one option of any type. */
93
+ export type AnyOption<S extends string = string> = NumberOption | BooleanOption | EnumOption | ValueOption<unknown, S>;
94
+ /** This type removes the fields of a whole option from a declaration. */
95
+ type ItemOf<T> = T extends unknown ? Omit<T, "describe" | "default" | "noDefault" | "when"> : never;
96
+ /** The declaration of one item of a list option: an option without its text, its default and its condition. */
97
+ export type ListItem<S extends string = string> = ItemOf<AnyOption<S>>;
98
+ /**
99
+ * The declaration that fits the type of an option value: numbers, booleans, string unions or other values.
100
+ * A union of strings and other values takes an enum of the strings or a value declaration. An example is a rule or the name of a rule.
101
+ * A plain `string` takes an enum or a value declaration, because the value can be the key of a strategy.
102
+ */
103
+ export type OptionDeclaration<V, S extends string = string> = [V] extends [number] ? NumberOption : [V] extends [boolean] ? BooleanOption : [V] extends [string] ? string extends V ? EnumOption<V> | ValueOption<V, S> : EnumOption<V> : [Extract<V, string>] extends [never] ? ValueOption<V, S> : EnumOption<Extract<V, string>> | ValueOption<V, S>;
104
+ /** The declarations of the options of a strategy. The schema has one declaration for each key of the options type, and no other key. */
105
+ export type OptionSchema<O, S extends string = string> = { readonly [K in keyof O]-?: OptionDeclaration<NonNullable<O[K]>, S>; };
106
+ /** The fields of a strategy that the functions of this module read. An engine can add other fields. */
107
+ export interface DeclaredStrategy<O extends object = object, S extends string = string> {
108
+ /** The name of the strategy in a message. */
109
+ readonly name: string;
110
+ readonly defaults: O;
111
+ readonly schema?: OptionSchema<O, S>;
112
+ }
113
+ /** One problem of an option value against its declaration. */
114
+ export interface OptionIssue {
115
+ /** The key of the option. */
116
+ readonly key: string;
117
+ readonly value: unknown;
118
+ /** The kind of the problem: no declaration, the wrong type, out of the range, not a whole number or not one of the values. */
119
+ readonly problem: "unknown" | "type" | "range" | "integer" | "value";
120
+ /** One sentence that tells the problem. */
121
+ readonly message: string;
122
+ }
123
+ /** One setting of a sweep: a name for the rows of a table, and the options of the strategy. */
124
+ export interface OptionSetting<O extends object> {
125
+ /** The key and the value of each option of the setting, for example `stretch 1.5`. */
126
+ readonly name: string;
127
+ readonly options: Partial<O>;
128
+ }
129
+ /** The options of `sweepValues`, `sweepOf` and `sweepGrid`. */
130
+ export interface SweepOptions {
131
+ /**
132
+ * The number of values on the range of a number option. Without it, the sweep gives the `marks` of the declaration.
133
+ * A declaration without `marks` gets 5 values.
134
+ */
135
+ readonly count?: number;
136
+ /** With `true`, a sweep of a number option on the range also gives the `special` values. The default is `false`. */
137
+ readonly special?: boolean;
138
+ }
139
+ /** This function gives the declared options of a strategy, in the order of its schema, with the effective default of each one. */
140
+ export declare function listOptions<O extends object, S extends string = string>(strategy: DeclaredStrategy<O, S>): {
141
+ readonly key: keyof O & string;
142
+ readonly declaration: AnyOption<S>;
143
+ readonly value: unknown;
144
+ }[];
145
+ /**
146
+ * This function gives the effective default of each declared option: the value of `defaults`, else the `default` of the declaration.
147
+ * An option without either value stays out. The strategy gives the same output with this object as with no options.
148
+ */
149
+ export declare function optionDefaults<O extends object, S extends string = string>(strategy: DeclaredStrategy<O, S>): Partial<O>;
150
+ /** This function gives the problem of one value against its declaration, or `undefined` when the value fits. */
151
+ export declare function optionIssue(key: string, value: unknown, d: AnyOption): OptionIssue | undefined;
152
+ /**
153
+ * This function examines option values against the schema of a strategy. It gives one issue for each key without a declaration.
154
+ * It also gives one issue for each value of the wrong type, out of the range, not whole or not one of the values.
155
+ * It changes no value.
156
+ * A strategy without a schema gives no issue.
157
+ */
158
+ export declare function checkOptions<O extends object>(strategy: DeclaredStrategy<O>, options: Partial<O>): OptionIssue[];
159
+ /**
160
+ * This function moves each number option into the range of its declaration, for a control. An integer option gets the nearest whole number.
161
+ * An option with a list of `values` gets the nearest value of the list. A special value stays. The function keeps each other value as it is. `checkOptions` reports the values that this function cannot correct.
162
+ */
163
+ export declare function clampOptions<O extends object>(strategy: DeclaredStrategy<O>, options: Partial<O>): Partial<O>;
164
+ /**
165
+ * This function gives the values of a sweep of one option declaration.
166
+ * A number option gives its `marks`, or its list of `values`, or `count` values on its range and its scale. A boolean gives `false` and `true`. An enum gives its values.
167
+ * An option of another type has no sweep, so the function throws an error.
168
+ */
169
+ export declare function sweepValues(declaration: AnyOption, options?: SweepOptions): unknown[];
170
+ /**
171
+ * This function gives the settings of a sweep of one option of a strategy, from its declaration only.
172
+ * The name of each setting is the key and the value, for example `stretch 1.5`.
173
+ */
174
+ export declare function sweepOf<O extends object>(strategy: DeclaredStrategy<O>, key: keyof O & string, options?: SweepOptions): OptionSetting<O>[];
175
+ /**
176
+ * This function gives the settings of a grid of options: each combination of the values of the sweeps of the keys.
177
+ * The name of a setting joins the names of its values with commas, in the order of the keys.
178
+ */
179
+ export declare function sweepGrid<O extends object>(strategy: DeclaredStrategy<O>, keys: readonly (keyof O & string)[], options?: SweepOptions): OptionSetting<O>[];
180
+ /** This function gives the problems of one declaration: a bad range, a bad step, or marks and a default that do not fit. */
181
+ export declare function declarationIssues(key: string, d: AnyOption): string[];
182
+ /**
183
+ * This function examines the schema of a strategy. It gives one message for each option of `defaults` without a declaration.
184
+ * It also gives one message for each bad declaration, and for each value of `defaults` that does not fit its declaration.
185
+ * A good schema gives an empty list.
186
+ */
187
+ export declare function checkSchema(strategy: DeclaredStrategy): string[];
188
+ export {};
189
+ //# sourceMappingURL=strategy-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategy-options.d.ts","names":[],"sources":["../src/strategy-options.ts"],"mappings":";;YAGY;;YAGA;;iBAGK;WACN,QAAQ;;WAER;;;UAID;;WAEC;;WAEA,YAAY;;WAEZ,OAAO;;;;;;iBAOD,qBAAqB;;WAE3B;WACA;WACA;;WAEA;;WAEA,QAAQ;;WAER;;WAEA;;;;;WAKA;;WAEA;;;iBAIM,sBAAsB;WAC5B;;WAEA;;;iBAIM,WAAW,mCAAmC;WACpD;;WAEA,iBAAiB;;;;;WAKjB;;WAEA,UAAU;;;;;;iBAOJ,YAAY,aAAa,mCAAmC;WAClE;;WAEA,OAAO;;WAEP;;WAEA;;WAEA;;WAEA;;WAEA,QAAQ,SAAS;;WAEjB,KAAK,SAAS;;WAEd;;WAEA;;WAEA,UAAU;;;YAIT,UAAU,6BAA6B,eAAe,gBAAgB,aAAa,qBAAqB;;KAG/G,OAAO,KAAK,oBAAoB,KAAK;;YAG9B,SAAS,6BAA6B,OAAO,UAAU;;;;;;YAOvD,kBAAkB,GAAG,8BAA8B,sBAC3D,gBACC,uBACC,iBACC,qCACgB,IACb,WAAW,KAAK,YAAY,GAAG,KAC/B,WAAW,MACZ,QAAQ,8BACP,YAAY,GAAG,KACf,WAAW,QAAQ,cAAc,YAAY,GAAG;;YAG9C,aAAa,GAAG,yCAAyC,WAAW,MAAM,kBAAkB,YAAY,EAAE,KAAK;;iBAG1G,iBAAiB,2BAA2B;;WAElD;WACA,UAAU;WACV,SAAS,aAAa,GAAG;;;iBAInB;;WAEN;WACA;;WAEA;;WAEA;;;iBAIM,cAAc;;WAEpB;WACA,SAAS,QAAQ;;;iBAIX;;;;;WAKN;;WAEA;;;wBAYK,YAAY,kBAAkB,2BAC5C,UAAU,iBAAiB,GAAG;WAClB,WAAW;WAAqB,aAAa,UAAU;WAAa;;;;;;wBASlE,eAAe,kBAAkB,2BAA2B,UAAU,iBAAiB,GAAG,KAAK,QAAQ;;wBAevG,YAAY,aAAa,gBAAgB,GAAG,YAAY;;;;;;;wBAiCxD,aAAa,kBAAkB,UAAU,iBAAiB,IAAI,SAAS,QAAQ,KAAK;;;;;wBAgBpF,aAAa,kBAAkB,UAAU,iBAAiB,IAAI,SAAS,QAAQ,KAAK,QAAQ;;;;;;wBAwC5F,YAAY,aAAa,WAAW,UAAS;;;;;wBA6B7C,QAAQ,kBAAkB,UAAU,iBAAiB,IAAI,WAAW,YAAY,UAAS,eAAoB,cAAc;;;;;wBAQ3H,UAAU,kBAAkB,UAAU,iBAAiB,IAAI,sBAAsB,eAAe,UAAS,eAAoB,cAAc;;wBAU3I,kBAAkB,aAAa,GAAG;;;;;;wBA8BlC,YAAY,UAAU"}