@genome-spy/core 0.48.1 → 0.49.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/dist/bundle/index.es.js +7485 -7097
- package/dist/bundle/index.js +124 -111
- package/dist/schema.json +838 -344
- package/dist/src/data/collector.d.ts +10 -8
- package/dist/src/data/collector.d.ts.map +1 -1
- package/dist/src/data/collector.js +131 -33
- package/dist/src/data/collector.test.d.ts +2 -0
- package/dist/src/data/collector.test.d.ts.map +1 -0
- package/dist/src/data/collector.test.js +55 -1
- package/dist/src/data/dataFlow.test.d.ts +2 -0
- package/dist/src/data/dataFlow.test.d.ts.map +1 -0
- package/dist/src/data/flow.test.d.ts +2 -0
- package/dist/src/data/flow.test.d.ts.map +1 -0
- package/dist/src/data/flow.test.js +19 -14
- package/dist/src/data/flowNode.test.d.ts +2 -0
- package/dist/src/data/flowNode.test.d.ts.map +1 -0
- package/dist/src/data/flowOptimizer.test.d.ts +2 -0
- package/dist/src/data/flowOptimizer.test.d.ts.map +1 -0
- package/dist/src/data/flowOptimizer.test.js +9 -10
- package/dist/src/data/formats/fasta.test.d.ts +2 -0
- package/dist/src/data/formats/fasta.test.d.ts.map +1 -0
- package/dist/src/data/sources/inlineSource.test.d.ts +2 -0
- package/dist/src/data/sources/inlineSource.test.d.ts.map +1 -0
- package/dist/src/data/sources/inlineSource.test.js +23 -16
- package/dist/src/data/sources/sequenceSource.test.d.ts +2 -0
- package/dist/src/data/sources/sequenceSource.test.d.ts.map +1 -0
- package/dist/src/data/sources/sequenceSource.test.js +59 -42
- package/dist/src/data/transforms/clone.test.d.ts +2 -0
- package/dist/src/data/transforms/clone.test.d.ts.map +1 -0
- package/dist/src/data/transforms/coverage.test.d.ts +2 -0
- package/dist/src/data/transforms/coverage.test.d.ts.map +1 -0
- package/dist/src/data/transforms/coverage.test.js +1 -1
- package/dist/src/data/transforms/filter.d.ts +10 -0
- package/dist/src/data/transforms/filter.d.ts.map +1 -1
- package/dist/src/data/transforms/filter.js +30 -1
- package/dist/src/data/transforms/filter.test.d.ts +2 -0
- package/dist/src/data/transforms/filter.test.d.ts.map +1 -0
- package/dist/src/data/transforms/flatten.test.d.ts +2 -0
- package/dist/src/data/transforms/flatten.test.d.ts.map +1 -0
- package/dist/src/data/transforms/flatten.test.js +10 -7
- package/dist/src/data/transforms/flattenDelimited.test.d.ts +2 -0
- package/dist/src/data/transforms/flattenDelimited.test.d.ts.map +1 -0
- package/dist/src/data/transforms/flattenDelimited.test.js +16 -13
- package/dist/src/data/transforms/flattenSequence.test.d.ts +2 -0
- package/dist/src/data/transforms/flattenSequence.test.d.ts.map +1 -0
- package/dist/src/data/transforms/flattenSequence.test.js +1 -1
- package/dist/src/data/transforms/formula.test.d.ts +2 -0
- package/dist/src/data/transforms/formula.test.d.ts.map +1 -0
- package/dist/src/data/transforms/formula.test.js +1 -1
- package/dist/src/data/transforms/identifier.d.ts +1 -1
- package/dist/src/data/transforms/identifier.d.ts.map +1 -1
- package/dist/src/data/transforms/identifier.js +2 -2
- package/dist/src/data/transforms/identifier.test.d.ts +2 -0
- package/dist/src/data/transforms/identifier.test.d.ts.map +1 -0
- package/dist/src/data/transforms/identifier.test.js +23 -14
- package/dist/src/data/transforms/pileup.test.d.ts +2 -0
- package/dist/src/data/transforms/pileup.test.d.ts.map +1 -0
- package/dist/src/data/transforms/project.test.d.ts +2 -0
- package/dist/src/data/transforms/project.test.d.ts.map +1 -0
- package/dist/src/data/transforms/project.test.js +1 -1
- package/dist/src/data/transforms/regexExtract.test.d.ts +2 -0
- package/dist/src/data/transforms/regexExtract.test.d.ts.map +1 -0
- package/dist/src/data/transforms/regexExtract.test.js +6 -3
- package/dist/src/data/transforms/regexFold.test.d.ts +2 -0
- package/dist/src/data/transforms/regexFold.test.d.ts.map +1 -0
- package/dist/src/data/transforms/sample.test.d.ts +2 -0
- package/dist/src/data/transforms/sample.test.d.ts.map +1 -0
- package/dist/src/data/transforms/stack.test.d.ts +2 -0
- package/dist/src/data/transforms/stack.test.d.ts.map +1 -0
- package/dist/src/data/transforms/stack.test.js +8 -8
- package/dist/src/encoder/accessor.d.ts +17 -14
- package/dist/src/encoder/accessor.d.ts.map +1 -1
- package/dist/src/encoder/accessor.js +127 -56
- package/dist/src/encoder/accessor.test.d.ts +2 -0
- package/dist/src/encoder/accessor.test.d.ts.map +1 -0
- package/dist/src/encoder/accessor.test.js +145 -31
- package/dist/src/encoder/encoder.d.ts +26 -13
- package/dist/src/encoder/encoder.d.ts.map +1 -1
- package/dist/src/encoder/encoder.js +98 -114
- package/dist/src/encoder/encoder.test.d.ts +2 -0
- package/dist/src/encoder/encoder.test.d.ts.map +1 -0
- package/dist/src/encoder/encoder.test.js +85 -82
- package/dist/src/fonts/bmFontManager.d.ts.map +1 -1
- package/dist/src/fonts/bmFontManager.js +10 -4
- package/dist/src/genome/genome.test.d.ts +2 -0
- package/dist/src/genome/genome.test.d.ts.map +1 -0
- package/dist/src/genome/scaleIndex.test.d.ts +2 -0
- package/dist/src/genome/scaleIndex.test.d.ts.map +1 -0
- package/dist/src/genome/scaleLocus.test.d.ts +2 -0
- package/dist/src/genome/scaleLocus.test.d.ts.map +1 -0
- package/dist/src/genomeSpy.d.ts +3 -2
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +29 -21
- package/dist/src/gl/dataToVertices.d.ts +5 -7
- package/dist/src/gl/dataToVertices.d.ts.map +1 -1
- package/dist/src/gl/dataToVertices.js +42 -30
- package/dist/src/gl/glslScaleGenerator.d.ts +84 -15
- package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
- package/dist/src/gl/glslScaleGenerator.js +260 -73
- package/dist/src/gl/includes/picking.vertex.glsl.js +1 -1
- package/dist/src/marks/link.common.glsl.js +1 -1
- package/dist/src/marks/link.d.ts.map +1 -1
- package/dist/src/marks/link.js +10 -0
- package/dist/src/marks/link.vertex.glsl.js +1 -1
- package/dist/src/marks/mark.d.ts +6 -9
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +212 -95
- package/dist/src/marks/point.d.ts.map +1 -1
- package/dist/src/marks/point.js +5 -1
- package/dist/src/marks/rect.d.ts.map +1 -1
- package/dist/src/marks/rect.js +9 -4
- package/dist/src/marks/rule.d.ts.map +1 -1
- package/dist/src/marks/rule.js +4 -0
- package/dist/src/marks/text.d.ts.map +1 -1
- package/dist/src/marks/text.js +5 -1
- package/dist/src/scale/scale.test.d.ts +2 -0
- package/dist/src/scale/scale.test.d.ts.map +1 -0
- package/dist/src/scale/scale.test.js +2 -0
- package/dist/src/scale/ticks.test.d.ts +2 -0
- package/dist/src/scale/ticks.test.d.ts.map +1 -0
- package/dist/src/scale/ticks.test.js +6 -0
- package/dist/src/selection/selection.d.ts +39 -0
- package/dist/src/selection/selection.d.ts.map +1 -0
- package/dist/src/selection/selection.js +78 -0
- package/dist/src/spec/channel.d.ts +137 -83
- package/dist/src/spec/mark.d.ts +9 -0
- package/dist/src/spec/parameter.d.ts +112 -3
- package/dist/src/spec/root.d.ts +0 -1
- package/dist/src/spec/transform.d.ts +19 -1
- package/dist/src/spec/view.d.ts +3 -3
- package/dist/src/tooltip/dataTooltipHandler.js +1 -1
- package/dist/src/types/encoder.d.ts +80 -26
- package/dist/src/types/rendering.d.ts +1 -0
- package/dist/src/types/selectionTypes.d.ts +44 -0
- package/dist/src/types/viewContext.d.ts +1 -4
- package/dist/src/utils/addBaseUrl.test.d.ts +2 -0
- package/dist/src/utils/addBaseUrl.test.d.ts.map +1 -0
- package/dist/src/utils/animator.d.ts.map +1 -1
- package/dist/src/utils/animator.js +3 -1
- package/dist/src/utils/binnedIndex.test.d.ts +2 -0
- package/dist/src/utils/binnedIndex.test.d.ts.map +1 -0
- package/dist/src/utils/cloner.test.d.ts +2 -0
- package/dist/src/utils/cloner.test.d.ts.map +1 -0
- package/dist/src/utils/coalesce.test.d.ts +2 -0
- package/dist/src/utils/coalesce.test.d.ts.map +1 -0
- package/dist/src/utils/concatIterables.test.d.ts +2 -0
- package/dist/src/utils/concatIterables.test.d.ts.map +1 -0
- package/dist/src/utils/domainArray.test.d.ts +2 -0
- package/dist/src/utils/domainArray.test.d.ts.map +1 -0
- package/dist/src/utils/expression.d.ts +2 -2
- package/dist/src/utils/expression.d.ts.map +1 -1
- package/dist/src/utils/expression.js +11 -2
- package/dist/src/utils/indexer.test.d.ts +2 -0
- package/dist/src/utils/indexer.test.d.ts.map +1 -0
- package/dist/src/utils/inertia.d.ts.map +1 -1
- package/dist/src/utils/inertia.js +4 -0
- package/dist/src/utils/inputBinding.d.ts.map +1 -1
- package/dist/src/utils/inputBinding.js +4 -0
- package/dist/src/utils/iterateNestedMaps.d.ts +4 -3
- package/dist/src/utils/iterateNestedMaps.d.ts.map +1 -1
- package/dist/src/utils/iterateNestedMaps.js +3 -2
- package/dist/src/utils/iterateNestedMaps.test.d.ts +2 -0
- package/dist/src/utils/iterateNestedMaps.test.d.ts.map +1 -0
- package/dist/src/utils/kWayMerge.test.d.ts +2 -0
- package/dist/src/utils/kWayMerge.test.d.ts.map +1 -0
- package/dist/src/utils/mergeObjects.test.d.ts +2 -0
- package/dist/src/utils/mergeObjects.test.d.ts.map +1 -0
- package/dist/src/utils/numberExtractor.test.d.ts +2 -0
- package/dist/src/utils/numberExtractor.test.d.ts.map +1 -0
- package/dist/src/utils/propertyCacher.test.d.ts +2 -0
- package/dist/src/utils/propertyCacher.test.d.ts.map +1 -0
- package/dist/src/utils/propertyCoalescer.test.d.ts +2 -0
- package/dist/src/utils/propertyCoalescer.test.d.ts.map +1 -0
- package/dist/src/utils/propertyCoalescer.test.js +3 -0
- package/dist/src/utils/radixSort.d.ts +9 -0
- package/dist/src/utils/radixSort.d.ts.map +1 -0
- package/dist/src/utils/radixSort.js +130 -0
- package/dist/src/utils/radixSort.test.d.ts +2 -0
- package/dist/src/utils/radixSort.test.d.ts.map +1 -0
- package/dist/src/utils/radixSort.test.js +51 -0
- package/dist/src/utils/reservationMap.test.d.ts +2 -0
- package/dist/src/utils/reservationMap.test.d.ts.map +1 -0
- package/dist/src/utils/ringBuffer.test.d.ts +2 -0
- package/dist/src/utils/ringBuffer.test.d.ts.map +1 -0
- package/dist/src/utils/topK.test.d.ts +2 -0
- package/dist/src/utils/topK.test.d.ts.map +1 -0
- package/dist/src/utils/trees.test.d.ts +2 -0
- package/dist/src/utils/trees.test.d.ts.map +1 -0
- package/dist/src/utils/trees.test.js +8 -3
- package/dist/src/utils/variableTools.test.d.ts +2 -0
- package/dist/src/utils/variableTools.test.d.ts.map +1 -0
- package/dist/src/view/axisResolution.d.ts +19 -6
- package/dist/src/view/axisResolution.d.ts.map +1 -1
- package/dist/src/view/axisResolution.js +16 -7
- package/dist/src/view/axisResolution.test.d.ts +2 -0
- package/dist/src/view/axisResolution.test.d.ts.map +1 -0
- package/dist/src/view/axisResolution.test.js +16 -11
- package/dist/src/view/facetView.d.ts +1 -1
- package/dist/src/view/facetView.d.ts.map +1 -1
- package/dist/src/view/flowBuilder.d.ts +1 -1
- package/dist/src/view/flowBuilder.d.ts.map +1 -1
- package/dist/src/view/flowBuilder.js +34 -5
- package/dist/src/view/flowBuilder.test.d.ts +2 -0
- package/dist/src/view/flowBuilder.test.d.ts.map +1 -0
- package/dist/src/view/gridView.d.ts +0 -6
- package/dist/src/view/gridView.d.ts.map +1 -1
- package/dist/src/view/layerView.d.ts +0 -6
- package/dist/src/view/layerView.d.ts.map +1 -1
- package/dist/src/view/layout/flexLayout.test.d.ts +2 -0
- package/dist/src/view/layout/flexLayout.test.d.ts.map +1 -0
- package/dist/src/view/layout/grid.test.d.ts +2 -0
- package/dist/src/view/layout/grid.test.d.ts.map +1 -0
- package/dist/src/view/layout/rectangle.test.d.ts +2 -0
- package/dist/src/view/layout/rectangle.test.d.ts.map +1 -0
- package/dist/src/view/paramMediator.d.ts +32 -5
- package/dist/src/view/paramMediator.d.ts.map +1 -1
- package/dist/src/view/paramMediator.js +97 -9
- package/dist/src/view/paramMediator.test.d.ts +2 -0
- package/dist/src/view/paramMediator.test.d.ts.map +1 -0
- package/dist/src/view/paramMediator.test.js +17 -1
- package/dist/src/view/scaleResolution.d.ts +17 -9
- package/dist/src/view/scaleResolution.d.ts.map +1 -1
- package/dist/src/view/scaleResolution.js +51 -34
- package/dist/src/view/scaleResolution.test.d.ts +2 -0
- package/dist/src/view/scaleResolution.test.d.ts.map +1 -0
- package/dist/src/view/scaleResolution.test.js +2 -0
- package/dist/src/view/testUtils.d.ts.map +1 -1
- package/dist/src/view/testUtils.js +15 -3
- package/dist/src/view/unitView.d.ts +5 -15
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +81 -101
- package/dist/src/view/view.d.ts +1 -1
- package/dist/src/view/view.d.ts.map +1 -1
- package/dist/src/view/view.test.d.ts +2 -0
- package/dist/src/view/view.test.d.ts.map +1 -0
- package/dist/src/view/view.test.js +73 -55
- package/dist/src/view/viewFactory.test.d.ts +2 -0
- package/dist/src/view/viewFactory.test.d.ts.map +1 -0
- package/dist/src/view/viewFactory.test.js +2 -2
- package/dist/src/view/zoom.js +2 -2
- package/package.json +5 -2
package/dist/src/marks/mark.js
CHANGED
|
@@ -14,6 +14,7 @@ import createEncoders, {
|
|
|
14
14
|
isChannelDefWithScale,
|
|
15
15
|
isChannelWithScale,
|
|
16
16
|
isDatumDef,
|
|
17
|
+
isExprDef,
|
|
17
18
|
isFieldDef,
|
|
18
19
|
isValueDef,
|
|
19
20
|
} from "../encoder/encoder.js";
|
|
@@ -25,9 +26,14 @@ import {
|
|
|
25
26
|
toHighPrecisionDomainUniform,
|
|
26
27
|
dedupeEncodingFields,
|
|
27
28
|
generateDynamicValueGlslAndUniform,
|
|
28
|
-
isLargeGenome,
|
|
29
29
|
splitLargeHighPrecision,
|
|
30
30
|
getRangeForGlsl,
|
|
31
|
+
getAttributeAndArrayTypes,
|
|
32
|
+
generateDataGlsl,
|
|
33
|
+
generateDatumGlslAndUniform,
|
|
34
|
+
generateConditionalEncoderGlsl,
|
|
35
|
+
PARAM_PREFIX,
|
|
36
|
+
ATTRIBUTE_PREFIX,
|
|
31
37
|
} from "../gl/glslScaleGenerator.js";
|
|
32
38
|
import GLSL_COMMON from "../gl/includes/common.glsl.js";
|
|
33
39
|
import GLSL_SCALES from "../gl/includes/scales.glsl.js";
|
|
@@ -40,7 +46,9 @@ import coalesceProperties from "../utils/propertyCoalescer.js";
|
|
|
40
46
|
import { isScalar } from "../utils/variableTools.js";
|
|
41
47
|
import { InternMap } from "internmap";
|
|
42
48
|
import ViewError from "../view/viewError.js";
|
|
43
|
-
import { isExprRef } from "../view/paramMediator.js";
|
|
49
|
+
import { isExprRef, validateParameterName } from "../view/paramMediator.js";
|
|
50
|
+
import { UNIQUE_ID_KEY } from "../data/transforms/identifier.js";
|
|
51
|
+
import { isSinglePointSelection } from "../selection/selection.js";
|
|
44
52
|
|
|
45
53
|
export const SAMPLE_FACET_UNIFORM = "SAMPLE_FACET_UNIFORM";
|
|
46
54
|
export const SAMPLE_FACET_TEXTURE = "SAMPLE_FACET_TEXTURE";
|
|
@@ -80,7 +88,7 @@ export default class Mark {
|
|
|
80
88
|
constructor(unitView) {
|
|
81
89
|
this.unitView = unitView;
|
|
82
90
|
|
|
83
|
-
/** @type {Record<
|
|
91
|
+
/** @type {Partial<Record<Channel, import("../types/encoder.js").Encoder>>} */
|
|
84
92
|
this.encoders = undefined;
|
|
85
93
|
|
|
86
94
|
// TODO: Consolidate the following webgl stuff into a single object
|
|
@@ -187,9 +195,6 @@ export default class Mark {
|
|
|
187
195
|
/**
|
|
188
196
|
* Returns attribute info for WebGL attributes that match visual channels.
|
|
189
197
|
*
|
|
190
|
-
* Note: attributes and channels do not necessarily match.
|
|
191
|
-
* For example, rectangles have x, y, x2, and y2 channels but only x and y as attributes.
|
|
192
|
-
*
|
|
193
198
|
* @returns {string[]}
|
|
194
199
|
*/
|
|
195
200
|
getAttributes() {
|
|
@@ -225,7 +230,7 @@ export default class Mark {
|
|
|
225
230
|
|
|
226
231
|
if (this.isPickingParticipant()) {
|
|
227
232
|
encoding.uniqueId = {
|
|
228
|
-
field:
|
|
233
|
+
field: UNIQUE_ID_KEY,
|
|
229
234
|
};
|
|
230
235
|
}
|
|
231
236
|
|
|
@@ -358,7 +363,7 @@ export default class Mark {
|
|
|
358
363
|
* the ranges of the visual channels.
|
|
359
364
|
*/
|
|
360
365
|
initializeEncoders() {
|
|
361
|
-
this.encoders = createEncoders(this);
|
|
366
|
+
this.encoders = createEncoders(this.unitView, this.encoding);
|
|
362
367
|
}
|
|
363
368
|
|
|
364
369
|
/**
|
|
@@ -401,7 +406,12 @@ export default class Mark {
|
|
|
401
406
|
*/
|
|
402
407
|
// eslint-disable-next-line complexity
|
|
403
408
|
createAndLinkShaders(vertexShader, fragmentShader, extraHeaders = []) {
|
|
404
|
-
const
|
|
409
|
+
const shaderChannels = this.getAttributes();
|
|
410
|
+
const encoders = this.encoders;
|
|
411
|
+
const sampleFacetMode = this.getSampleFacetMode();
|
|
412
|
+
if (sampleFacetMode) {
|
|
413
|
+
extraHeaders.push(`#define ${sampleFacetMode}`);
|
|
414
|
+
}
|
|
405
415
|
|
|
406
416
|
// For debugging
|
|
407
417
|
const debugHeader = "// view: " + this.unitView.getPathString();
|
|
@@ -416,36 +426,83 @@ export default class Mark {
|
|
|
416
426
|
*/
|
|
417
427
|
const attributeCode = new Set();
|
|
418
428
|
|
|
419
|
-
const dedupedEncodingFields = dedupeEncodingFields(
|
|
420
|
-
|
|
421
|
-
const sampleFacetMode = this.getSampleFacetMode();
|
|
422
|
-
if (sampleFacetMode) {
|
|
423
|
-
extraHeaders.push(`#define ${sampleFacetMode}`);
|
|
424
|
-
}
|
|
429
|
+
const dedupedEncodingFields = dedupeEncodingFields(encoders);
|
|
425
430
|
|
|
426
431
|
/** @type {string[]} */
|
|
427
432
|
const dynamicMarkUniforms = [];
|
|
428
433
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
434
|
+
const paramPredicates = Object.values(encoders)
|
|
435
|
+
.flatMap((e) => e.accessors)
|
|
436
|
+
.map((a) => a.predicate)
|
|
437
|
+
.filter((p) => p.param);
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Prevent duplicate registration.
|
|
441
|
+
* @type {Map<string, "single" | "multi" | "range">}
|
|
442
|
+
*/
|
|
443
|
+
const selectionParameterUniforms = new Map();
|
|
444
|
+
|
|
445
|
+
for (const predicate of paramPredicates) {
|
|
446
|
+
const param = predicate.param;
|
|
447
|
+
const selection = this.unitView.paramMediator.getValue(param);
|
|
448
|
+
|
|
449
|
+
// The selection is supposed to have an empty value at this point
|
|
450
|
+
// so that we can figure out the type of the selection.
|
|
451
|
+
if (!selection) {
|
|
452
|
+
throw new Error(
|
|
453
|
+
`Cannot infer selection type as the parameter "${param}" has no value. Please ensure that the parameter is properly defined!`
|
|
454
|
+
);
|
|
436
455
|
}
|
|
437
456
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
457
|
+
if (isSinglePointSelection(selection)) {
|
|
458
|
+
// Register a mark uniform for each param. The uniform will have
|
|
459
|
+
// the value of uniqueId of the selected datum.
|
|
460
|
+
if (!selectionParameterUniforms.has(param)) {
|
|
461
|
+
const uniformName =
|
|
462
|
+
PARAM_PREFIX + validateParameterName(param);
|
|
463
|
+
selectionParameterUniforms.set(param, "single");
|
|
464
|
+
|
|
465
|
+
dynamicMarkUniforms.push(` // Selection parameter`);
|
|
466
|
+
dynamicMarkUniforms.push(
|
|
467
|
+
` uniform highp uint ${uniformName};`
|
|
468
|
+
);
|
|
469
|
+
this.#callAfterShaderCompilation.push(() => {
|
|
470
|
+
this.registerMarkUniformValue(
|
|
471
|
+
uniformName,
|
|
472
|
+
{ expr: param },
|
|
473
|
+
(
|
|
474
|
+
/** @type {import("../types/selectionTypes.js").SinglePointSelection} */ selection
|
|
475
|
+
) => selection.uniqueId ?? 0
|
|
476
|
+
);
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
} else {
|
|
480
|
+
throw new Error(
|
|
481
|
+
`Unsupported selection (${param}) in condition: ${JSON.stringify(
|
|
482
|
+
selection
|
|
483
|
+
)}`
|
|
484
|
+
);
|
|
441
485
|
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* @param {Channel} channel
|
|
490
|
+
* @param {import("../types/encoder.js").Accessor} accessor
|
|
491
|
+
* @param {number} conditionNumber
|
|
492
|
+
* @param {import("../types/encoder.js").VegaScale} scale
|
|
493
|
+
*/
|
|
494
|
+
const addAccessor = (channel, accessor, conditionNumber, scale) => {
|
|
495
|
+
const channelDef = accessor.channelDef;
|
|
442
496
|
|
|
443
497
|
if (isValueDef(channelDef)) {
|
|
444
498
|
if (isExprRef(channelDef.value)) {
|
|
445
499
|
// An expression that evaluates to a value
|
|
446
|
-
const { uniformName, uniformGlsl,
|
|
447
|
-
generateDynamicValueGlslAndUniform(
|
|
448
|
-
|
|
500
|
+
const { uniformName, uniformGlsl, accessorGlsl, adjuster } =
|
|
501
|
+
generateDynamicValueGlslAndUniform(
|
|
502
|
+
channel,
|
|
503
|
+
conditionNumber
|
|
504
|
+
);
|
|
505
|
+
scaleCode.push(accessorGlsl);
|
|
449
506
|
dynamicMarkUniforms.push(uniformGlsl);
|
|
450
507
|
|
|
451
508
|
this.#callAfterShaderCompilation.push(() => {
|
|
@@ -458,50 +515,127 @@ export default class Mark {
|
|
|
458
515
|
} else {
|
|
459
516
|
// A constant value
|
|
460
517
|
scaleCode.push(
|
|
461
|
-
generateConstantValueGlsl(
|
|
518
|
+
generateConstantValueGlsl(
|
|
519
|
+
channel,
|
|
520
|
+
conditionNumber,
|
|
521
|
+
channelDef.value
|
|
522
|
+
).accessorGlsl
|
|
462
523
|
);
|
|
463
524
|
}
|
|
525
|
+
} else if (isDatumDef(channelDef)) {
|
|
526
|
+
const { uniformName, uniformGlsl, accessorGlsl } =
|
|
527
|
+
generateDatumGlslAndUniform(
|
|
528
|
+
channel,
|
|
529
|
+
scale,
|
|
530
|
+
conditionNumber
|
|
531
|
+
);
|
|
532
|
+
|
|
533
|
+
dynamicMarkUniforms.push(uniformGlsl);
|
|
534
|
+
scaleCode.push(accessorGlsl);
|
|
535
|
+
|
|
536
|
+
const { largeHp, discrete } = getAttributeAndArrayTypes(
|
|
537
|
+
scale,
|
|
538
|
+
channel
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Discrete variables both numeric and strings must be "indexed",
|
|
543
|
+
* 64 bit floats must be converted to vec2.
|
|
544
|
+
* 32 bit continuous variables go to GPU as is.
|
|
545
|
+
*
|
|
546
|
+
* @type {function(import("../spec/channel.js").Scalar):(number | number[])}
|
|
547
|
+
*/
|
|
548
|
+
const adjuster =
|
|
549
|
+
discrete && "domain" in scale
|
|
550
|
+
? (d) => scale.domain().indexOf(d)
|
|
551
|
+
: largeHp
|
|
552
|
+
? splitLargeHighPrecision
|
|
553
|
+
: (d) => +d;
|
|
554
|
+
|
|
555
|
+
this.#callAfterShaderCompilation.push(() => {
|
|
556
|
+
this.registerMarkUniformValue(
|
|
557
|
+
uniformName,
|
|
558
|
+
channelDef.datum,
|
|
559
|
+
adjuster
|
|
560
|
+
);
|
|
561
|
+
});
|
|
562
|
+
} else if (isFieldDef(channelDef)) {
|
|
563
|
+
const fields = dedupedEncodingFields.get([
|
|
564
|
+
channelDef.field,
|
|
565
|
+
true,
|
|
566
|
+
]);
|
|
567
|
+
const { attributeGlsl, accessorGlsl } = generateDataGlsl(
|
|
568
|
+
channel,
|
|
569
|
+
scale,
|
|
570
|
+
conditionNumber,
|
|
571
|
+
fields?.includes(channel) ? fields : undefined
|
|
572
|
+
);
|
|
573
|
+
attributeCode.add(attributeGlsl);
|
|
574
|
+
scaleCode.push(accessorGlsl);
|
|
575
|
+
} else if (isExprDef(channelDef)) {
|
|
576
|
+
const { attributeGlsl, accessorGlsl } = generateDataGlsl(
|
|
577
|
+
channel,
|
|
578
|
+
scale,
|
|
579
|
+
conditionNumber
|
|
580
|
+
);
|
|
581
|
+
attributeCode.add(attributeGlsl);
|
|
582
|
+
scaleCode.push(accessorGlsl);
|
|
464
583
|
} else {
|
|
584
|
+
throw new ViewError(
|
|
585
|
+
`Unsupported channel definition: ${JSON.stringify(
|
|
586
|
+
channelDef
|
|
587
|
+
)}`,
|
|
588
|
+
this.unitView
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
for (const [channel, encoder] of Object.entries(encoders)) {
|
|
594
|
+
if (!shaderChannels.includes(channel)) {
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const { channelDef, accessors, scale } = encoder;
|
|
599
|
+
|
|
600
|
+
// Generate accessors, one for each condition -------------
|
|
601
|
+
|
|
602
|
+
for (let i = 0; i < accessors.length; i++) {
|
|
603
|
+
addAccessor(channel, accessors[i], i, scale);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// Generate scale if needed -------------------------------
|
|
607
|
+
|
|
608
|
+
if (scale) {
|
|
465
609
|
const resolutionChannel =
|
|
466
610
|
(isChannelDefWithScale(channelDef) &&
|
|
467
611
|
channelDef.resolutionChannel) ||
|
|
468
612
|
channel;
|
|
469
613
|
|
|
614
|
+
// TODO: The event listener should be in the scale, not the resolution
|
|
470
615
|
const scaleResolution = isChannelWithScale(resolutionChannel)
|
|
471
616
|
? this.unitView.getScaleResolution(resolutionChannel)
|
|
472
617
|
: null;
|
|
473
618
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
619
|
+
const {
|
|
620
|
+
glsl,
|
|
621
|
+
domainUniform,
|
|
622
|
+
domainUniformName,
|
|
623
|
+
rangeUniform,
|
|
624
|
+
rangeUniformName,
|
|
625
|
+
} = generateScaleGlsl(channel, scale, channelDef);
|
|
480
626
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
channelDef,
|
|
485
|
-
sharedChannels?.includes(channel)
|
|
486
|
-
? sharedChannels
|
|
487
|
-
: [channel]
|
|
488
|
-
);
|
|
627
|
+
scaleCode.push(glsl);
|
|
628
|
+
dynamicMarkUniforms.push(domainUniform);
|
|
629
|
+
dynamicMarkUniforms.push(rangeUniform);
|
|
489
630
|
|
|
490
|
-
|
|
491
|
-
dynamicMarkUniforms.push(generated.domainUniform);
|
|
492
|
-
dynamicMarkUniforms.push(generated.rangeUniform);
|
|
493
|
-
attributeCode.add(generated.attributeGlsl);
|
|
494
|
-
|
|
495
|
-
if (generated.rangeUniform) {
|
|
631
|
+
if (rangeUniform) {
|
|
496
632
|
this.#callAfterShaderCompilation.push(() => {
|
|
497
|
-
const rangeSetter =
|
|
498
|
-
|
|
499
|
-
);
|
|
633
|
+
const rangeSetter =
|
|
634
|
+
this.createMarkUniformSetter(rangeUniformName);
|
|
500
635
|
|
|
501
636
|
const set = () =>
|
|
502
|
-
rangeSetter(
|
|
503
|
-
|
|
504
|
-
);
|
|
637
|
+
rangeSetter(getRangeForGlsl(scale, channel));
|
|
638
|
+
// TODO: The event listener should be in the scale, not the resolution
|
|
505
639
|
scaleResolution.addEventListener("range", set);
|
|
506
640
|
|
|
507
641
|
// Initial value
|
|
@@ -509,47 +643,10 @@ export default class Mark {
|
|
|
509
643
|
});
|
|
510
644
|
}
|
|
511
645
|
|
|
512
|
-
if (
|
|
513
|
-
if (!isDatumDef(channelDef)) {
|
|
514
|
-
throw new Error("Bug!");
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
const encoder = this.encoders[channel];
|
|
518
|
-
|
|
519
|
-
const indexer = encoder.indexer;
|
|
520
|
-
const hp = isHighPrecisionScale(encoder.scale.type);
|
|
521
|
-
const largeHp = hp && isLargeGenome(encoder.scale.domain());
|
|
522
|
-
|
|
523
|
-
/**
|
|
524
|
-
* Discrete variables both numeric and strings must be "indexed",
|
|
525
|
-
* 64 bit floats must be converted to vec2.
|
|
526
|
-
* 32 bit continuous variables go to GPU as is.
|
|
527
|
-
*
|
|
528
|
-
* @type {function(import("../spec/channel.js").Scalar):(number | number[])}
|
|
529
|
-
*/
|
|
530
|
-
const adjuster = indexer
|
|
531
|
-
? indexer
|
|
532
|
-
: largeHp
|
|
533
|
-
? splitLargeHighPrecision
|
|
534
|
-
: (d) => +d;
|
|
535
|
-
|
|
536
|
-
dynamicMarkUniforms.push(generated.markUniformGlsl);
|
|
537
|
-
|
|
646
|
+
if (domainUniform) {
|
|
538
647
|
this.#callAfterShaderCompilation.push(() => {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
channelDef.datum,
|
|
542
|
-
adjuster
|
|
543
|
-
);
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
if (generated.domainUniform) {
|
|
548
|
-
this.#callAfterShaderCompilation.push(() => {
|
|
549
|
-
const domainSetter = this.createMarkUniformSetter(
|
|
550
|
-
generated.domainUniformName
|
|
551
|
-
);
|
|
552
|
-
const scale = scaleResolution.scale;
|
|
648
|
+
const domainSetter =
|
|
649
|
+
this.createMarkUniformSetter(domainUniformName);
|
|
553
650
|
const set = () => {
|
|
554
651
|
const domain = isDiscrete(scale.type)
|
|
555
652
|
? [0, scale.domain().length]
|
|
@@ -562,6 +659,7 @@ export default class Mark {
|
|
|
562
659
|
);
|
|
563
660
|
};
|
|
564
661
|
|
|
662
|
+
// TODO: The event listener should be in the scale, not the resolution
|
|
565
663
|
scaleResolution.addEventListener("domain", set);
|
|
566
664
|
|
|
567
665
|
// Initial value
|
|
@@ -569,8 +667,27 @@ export default class Mark {
|
|
|
569
667
|
});
|
|
570
668
|
}
|
|
571
669
|
}
|
|
670
|
+
|
|
671
|
+
// Generate conditional encoder -------------------------------
|
|
672
|
+
|
|
673
|
+
scaleCode.push(generateConditionalEncoderGlsl(channel, accessors));
|
|
572
674
|
}
|
|
573
675
|
|
|
676
|
+
// Generate a function that checks if the datum is subject to any point selection
|
|
677
|
+
const conditions = [...selectionParameterUniforms.entries()]
|
|
678
|
+
.filter(([, v]) => v == "single")
|
|
679
|
+
.map(
|
|
680
|
+
([param]) =>
|
|
681
|
+
`${PARAM_PREFIX}${param} == ${ATTRIBUTE_PREFIX}uniqueId`
|
|
682
|
+
);
|
|
683
|
+
scaleCode.push(
|
|
684
|
+
"bool isPointSelected() {",
|
|
685
|
+
this.encoders.uniqueId && conditions.length > 0
|
|
686
|
+
? ` return ${conditions.join(" || ")};`
|
|
687
|
+
: " return false;",
|
|
688
|
+
"}"
|
|
689
|
+
);
|
|
690
|
+
|
|
574
691
|
const vertexPrecision = "precision highp float;\nprecision highp int;";
|
|
575
692
|
|
|
576
693
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"point.d.ts","sourceRoot":"","sources":["../../../src/marks/point.js"],"names":[],"mappings":"AAmBA;IA0HY,oCAMC;
|
|
1
|
+
{"version":3,"file":"point.d.ts","sourceRoot":"","sources":["../../../src/marks/point.js"],"names":[],"mappings":"AAmBA;IA0HY,oCAMC;IAiET,+BAkBC;;CAgDJ;iBA3QgB,WAAW"}
|
package/dist/src/marks/point.js
CHANGED
|
@@ -135,7 +135,7 @@ export default class PointMark extends Mark {
|
|
|
135
135
|
// Semantic zooming is currently solely a feature of point mark.
|
|
136
136
|
// Build a sorted sample that allows for computing p-quantiles
|
|
137
137
|
const semanticScoreAccessor =
|
|
138
|
-
this.
|
|
138
|
+
this.encoders["semanticScore"]?.dataAccessor?.asNumberAccessor();
|
|
139
139
|
if (semanticScoreAccessor) {
|
|
140
140
|
// n chosen using Stetson-Harrison
|
|
141
141
|
// TODO: Throw on missing scores
|
|
@@ -177,6 +177,10 @@ export default class PointMark extends Mark {
|
|
|
177
177
|
|
|
178
178
|
updateGraphicsData() {
|
|
179
179
|
const collector = this.unitView.getCollector();
|
|
180
|
+
if (!collector) {
|
|
181
|
+
console.debug("No collector");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
180
184
|
const itemCount = collector.getItemCount();
|
|
181
185
|
|
|
182
186
|
const builder = new PointVertexBuilder({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/marks/rect.js"],"names":[],"mappings":"AAaA;
|
|
1
|
+
{"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/marks/rect.js"],"names":[],"mappings":"AAaA;IA8NI;;;;;;;;;;OAUG;IACH,8BALW,GAAG,KACH,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAyBf;;CACJ;iBAvQgB,WAAW"}
|
package/dist/src/marks/rect.js
CHANGED
|
@@ -126,7 +126,8 @@ export default class RectMark extends Mark {
|
|
|
126
126
|
|
|
127
127
|
#isStroked() {
|
|
128
128
|
const sw = this.encoding.strokeWidth;
|
|
129
|
-
|
|
129
|
+
// True if there's any chance for a stroke to be drawn
|
|
130
|
+
return !(isValueDef(sw) && !sw.value) || "condition" in sw;
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
async initializeGraphics() {
|
|
@@ -177,6 +178,10 @@ export default class RectMark extends Mark {
|
|
|
177
178
|
|
|
178
179
|
updateGraphicsData() {
|
|
179
180
|
const collector = this.unitView.getCollector();
|
|
181
|
+
if (!collector) {
|
|
182
|
+
console.debug("No collector");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
180
185
|
const numItems = collector.getItemCount();
|
|
181
186
|
|
|
182
187
|
const builder = new RectVertexBuilder({
|
|
@@ -251,13 +256,13 @@ export default class RectMark extends Mark {
|
|
|
251
256
|
const scaleType = e.x.scale.type;
|
|
252
257
|
|
|
253
258
|
if (isDiscrete(scaleType)) {
|
|
254
|
-
const a = e.x.
|
|
259
|
+
const a = e.x.dataAccessor;
|
|
255
260
|
// TODO: Binary search
|
|
256
261
|
return data.find((d) => x == a(d));
|
|
257
262
|
} else {
|
|
258
263
|
// TODO: Handle point features on locus/index scales
|
|
259
|
-
const a = e.x.
|
|
260
|
-
const a2 = e.x2.
|
|
264
|
+
const a = e.x.dataAccessor;
|
|
265
|
+
const a2 = e.x2.dataAccessor;
|
|
261
266
|
// TODO: Binary search
|
|
262
267
|
return data.find((d) => x >= a(d) && x < a2(d));
|
|
263
268
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../../src/marks/rule.js"],"names":[],"mappings":"AAcA;IAOQ,wBAAwB;IA4GpB,0BAOE;
|
|
1
|
+
{"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../../src/marks/rule.js"],"names":[],"mappings":"AAcA;IAOQ,wBAAwB;IA4GpB,0BAOE;CAgGb;iBAxOgB,WAAW"}
|
package/dist/src/marks/rule.js
CHANGED
|
@@ -165,6 +165,10 @@ export default class RuleMark extends Mark {
|
|
|
165
165
|
|
|
166
166
|
updateGraphicsData() {
|
|
167
167
|
const collector = this.unitView.getCollector();
|
|
168
|
+
if (!collector) {
|
|
169
|
+
console.debug("No collector");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
168
172
|
const itemCount = collector.getItemCount();
|
|
169
173
|
|
|
170
174
|
const builder = new RuleVertexBuilder({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH;IAyDQ,oDAMmD;
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH;IAyDQ,oDAMmD;CA4M1D;iBAtSgB,WAAW"}
|
package/dist/src/marks/text.js
CHANGED
|
@@ -216,11 +216,15 @@ export default class TextMark extends Mark {
|
|
|
216
216
|
|
|
217
217
|
updateGraphicsData() {
|
|
218
218
|
const collector = this.unitView.getCollector();
|
|
219
|
+
if (!collector) {
|
|
220
|
+
console.debug("No collector");
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
219
223
|
const data = collector.getData();
|
|
220
224
|
const encoding = this.encoding;
|
|
221
225
|
|
|
222
226
|
// Count the total number of characters to that we can pre-allocate a typed array
|
|
223
|
-
const accessor = this.encoders.text
|
|
227
|
+
const accessor = this.encoders.text; // accessor or constant value
|
|
224
228
|
let charCount = 0;
|
|
225
229
|
/** @type {function(any):any} */
|
|
226
230
|
const numberFormat =
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scale.test.d.ts","sourceRoot":"","sources":["../../../src/scale/scale.test.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ticks.test.d.ts","sourceRoot":"","sources":["../../../src/scale/ticks.test.js"],"names":[],"mappings":""}
|
|
@@ -16,6 +16,12 @@ import { validTicks } from "./ticks.js";
|
|
|
16
16
|
test("validTicks uses count correctly", function () {
|
|
17
17
|
var data = [0, 1, 2, 3, 4, 5, 6, 7];
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
* @param {T} x
|
|
22
|
+
* @returns {T}
|
|
23
|
+
* @template T
|
|
24
|
+
*/
|
|
19
25
|
var identity = function (x) {
|
|
20
26
|
return x;
|
|
21
27
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {import("../data/flowNode.js").Datum} datum
|
|
3
|
+
* @returns {import("../types/selectionTypes.js").SinglePointSelection}
|
|
4
|
+
*/
|
|
5
|
+
export function createSinglePointSelection(datum: import("../data/flowNode.js").Datum): import("../types/selectionTypes.js").SinglePointSelection;
|
|
6
|
+
/**
|
|
7
|
+
* @param {import("../types/selectionTypes.js").Selection} selection
|
|
8
|
+
* @param {import("../data/flowNode.js").Datum} datum
|
|
9
|
+
* @param {boolean} [empty] evaluate to true if the selection is empty
|
|
10
|
+
*/
|
|
11
|
+
export function selectionTest(selection: import("../types/selectionTypes.js").Selection, datum: import("../data/flowNode.js").Datum, empty?: boolean): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* @param {{param: string, empty?: boolean}} params
|
|
14
|
+
*/
|
|
15
|
+
export function makeSelectionTestExpression(params: {
|
|
16
|
+
param: string;
|
|
17
|
+
empty?: boolean;
|
|
18
|
+
}): string;
|
|
19
|
+
/**
|
|
20
|
+
* @param {import("../types/selectionTypes.js").Selection} selection
|
|
21
|
+
* @returns {selection is import("../types/selectionTypes.js").RangeSelection}
|
|
22
|
+
*/
|
|
23
|
+
export function isRangeSelection(selection: import("../types/selectionTypes.js").Selection): selection is import("../types/selectionTypes.js").RangeSelection;
|
|
24
|
+
/**
|
|
25
|
+
* @param {import("../types/selectionTypes.js").Selection} selection
|
|
26
|
+
* @returns {selection is import("../types/selectionTypes.js").SinglePointSelection}
|
|
27
|
+
*/
|
|
28
|
+
export function isSinglePointSelection(selection: import("../types/selectionTypes.js").Selection): selection is import("../types/selectionTypes.js").SinglePointSelection;
|
|
29
|
+
/**
|
|
30
|
+
* @param {import("../types/selectionTypes.js").Selection} selection
|
|
31
|
+
* @returns {selection is import("../types/selectionTypes.js").MultiPointSelection}
|
|
32
|
+
*/
|
|
33
|
+
export function isMultiPointSelection(selection: import("../types/selectionTypes.js").Selection): selection is import("../types/selectionTypes.js").MultiPointSelection;
|
|
34
|
+
/**
|
|
35
|
+
* @param {import("../types/selectionTypes.js").Selection} selection
|
|
36
|
+
* @returns {selection is import("../types/selectionTypes.js").ProjectedSelection}
|
|
37
|
+
*/
|
|
38
|
+
export function isProjectedSelection(selection: import("../types/selectionTypes.js").Selection): selection is import("../types/selectionTypes.js").ProjectedSelection;
|
|
39
|
+
//# sourceMappingURL=selection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/selection/selection.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH,kDAHW,OAAO,qBAAqB,EAAE,KAAK,GACjC,OAAO,4BAA4B,EAAE,oBAAoB,CAQrE;AAED;;;;GAIG;AACH,yCAJW,OAAO,4BAA4B,EAAE,SAAS,SAC9C,OAAO,qBAAqB,EAAE,KAAK,UACnC,OAAO,WAkBjB;AAED;;GAEG;AACH,oDAFW;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAC,UAM1C;AAED;;;GAGG;AACH,4CAHW,OAAO,4BAA4B,EAAE,SAAS,oEAKxD;AAED;;;GAGG;AACH,kDAHW,OAAO,4BAA4B,EAAE,SAAS,0EAKxD;AAED;;;GAGG;AACH,iDAHW,OAAO,4BAA4B,EAAE,SAAS,yEAKxD;AAED;;;GAGG;AACH,gDAHW,OAAO,4BAA4B,EAAE,SAAS,wEAKxD"}
|