postcss-minify-gradients 9.0.4 → 9.0.6
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/package.json +2 -2
- package/src/index.js +24 -103
- package/src/lib/positions.js +99 -0
- package/types/index.d.ts +0 -9
- package/types/index.d.ts.map +1 -1
- package/types/lib/positions.d.ts +45 -0
- package/types/lib/positions.d.ts.map +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postcss-minify-gradients",
|
|
3
|
-
"version": "9.0.
|
|
3
|
+
"version": "9.0.6",
|
|
4
4
|
"description": "Minify gradient parameters with PostCSS.",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@colordx/core": "^7.2.0",
|
|
37
37
|
"@csstools/css-tokenizer": "^4.0.2",
|
|
38
|
-
"cssnano-utils": "^8.0.
|
|
38
|
+
"cssnano-utils": "^8.0.2"
|
|
39
39
|
},
|
|
40
40
|
"bugs": {
|
|
41
41
|
"url": "https://github.com/cssnano/cssnano/issues"
|
package/src/index.js
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
/** @import {CSSToken} from '@csstools/css-tokenizer' */
|
|
2
|
+
/** @import {SourceEdit, PositionValue} from './lib/positions.js' */
|
|
2
3
|
import cssnanoUtils from 'cssnano-utils';
|
|
3
4
|
import isKnownColor from './isKnownColor.js';
|
|
5
|
+
import { isPositionZeroUnit, zeroPositionEdits } from './lib/positions.js';
|
|
4
6
|
|
|
5
|
-
const {
|
|
6
|
-
|
|
7
|
-
applyEdits,
|
|
8
|
-
asciiLowerCase,
|
|
9
|
-
decoded,
|
|
10
|
-
lengthUnits,
|
|
11
|
-
numeric,
|
|
12
|
-
tokenEnd,
|
|
13
|
-
} = cssnanoUtils;
|
|
7
|
+
const { TokenType, applyEdits, asciiLowerCase, decoded, numeric, tokenEnd } =
|
|
8
|
+
cssnanoUtils;
|
|
14
9
|
/** @type {typeof cssnanoUtils.balancedTokens} */
|
|
15
10
|
const balancedTokens = cssnanoUtils.balancedTokens;
|
|
16
11
|
|
|
@@ -57,7 +52,6 @@ const lineKeywords = new Set([
|
|
|
57
52
|
'top',
|
|
58
53
|
]);
|
|
59
54
|
|
|
60
|
-
/** @typedef {{start: number, end: number, text: string}} SourceEdit */
|
|
61
55
|
/**
|
|
62
56
|
* A gradient stop before fixup: the argument it came from, the extent of its
|
|
63
57
|
* colour, and the position tokens following that colour.
|
|
@@ -67,11 +61,6 @@ const lineKeywords = new Set([
|
|
|
67
61
|
* @property {number} colorEnd Offset just past the colour in the declaration value.
|
|
68
62
|
* @property {readonly number[]} position Positions following the colour.
|
|
69
63
|
*/
|
|
70
|
-
/**
|
|
71
|
-
* A position as a number and its unit, as reported by `numeric()`.
|
|
72
|
-
*
|
|
73
|
-
* @typedef {{number: number, unit: string}} PositionValue
|
|
74
|
-
*/
|
|
75
64
|
|
|
76
65
|
/**
|
|
77
66
|
* Significant tokens of a range, skipping whitespace, comments and the contents
|
|
@@ -120,38 +109,6 @@ function startsLineSpecification(input, parts) {
|
|
|
120
109
|
);
|
|
121
110
|
}
|
|
122
111
|
|
|
123
|
-
/**
|
|
124
|
-
* A zero length and a zero percentage name the same gradient position, which is
|
|
125
|
-
* also what the unitless zero this plugin emits denotes. Angles and other
|
|
126
|
-
* dimensions only share a spelling with it.
|
|
127
|
-
*
|
|
128
|
-
* @param {string} unit
|
|
129
|
-
* @return {boolean}
|
|
130
|
-
*/
|
|
131
|
-
function isPositionZeroUnit(unit) {
|
|
132
|
-
const lowered = asciiLowerCase(unit);
|
|
133
|
-
return lowered === '' || lowered === '%' || lengthUnits.has(lowered);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Whether two positions are on the same scale, so their numbers can be ordered.
|
|
138
|
-
* Only a length and a percentage naming zero are interchangeable.
|
|
139
|
-
*
|
|
140
|
-
* @param {PositionValue} current
|
|
141
|
-
* @param {PositionValue} largest
|
|
142
|
-
* @return {boolean}
|
|
143
|
-
*/
|
|
144
|
-
function positionsComparable(current, largest) {
|
|
145
|
-
const unit = asciiLowerCase(current.unit);
|
|
146
|
-
const largestUnit = asciiLowerCase(largest.unit);
|
|
147
|
-
if (unit === largestUnit) return true;
|
|
148
|
-
return (
|
|
149
|
-
(current.number === 0 || largest.number === 0) &&
|
|
150
|
-
isPositionZeroUnit(unit) &&
|
|
151
|
-
isPositionZeroUnit(largestUnit)
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
112
|
/**
|
|
156
113
|
* Offset just past the leading colour of an argument, so a functional colour
|
|
157
114
|
* such as `rgb(0 0 0 / 50%)` ends at its closing parenthesis.
|
|
@@ -191,50 +148,6 @@ function lineDirectionEdit(input, parts) {
|
|
|
191
148
|
return { start: from[2], end: tokenEnd(side), text: direction };
|
|
192
149
|
}
|
|
193
150
|
|
|
194
|
-
/**
|
|
195
|
-
* Colour stop fixup raises a position to the largest position before it, so a
|
|
196
|
-
* position at or below that non-negative maximum can be written as a zero.
|
|
197
|
-
*
|
|
198
|
-
* @param {readonly CSSToken[]} input
|
|
199
|
-
* @param {readonly number[]} position Offsets of the position tokens.
|
|
200
|
-
* @param {PositionValue | undefined} maximum Running maximum of the preceding positions.
|
|
201
|
-
* @param {Map<number, SourceEdit>} edits Collects the positions reduced to a zero.
|
|
202
|
-
* @return {PositionValue | undefined} The maximum the following stops clamp to.
|
|
203
|
-
*/
|
|
204
|
-
function zeroPositionEdits(input, position, maximum, edits) {
|
|
205
|
-
let largest = maximum;
|
|
206
|
-
for (const index of position) {
|
|
207
|
-
const token = input[index];
|
|
208
|
-
const current = numeric(token);
|
|
209
|
-
if (!current) {
|
|
210
|
-
largest = undefined;
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
// A zero clamps to any non-negative maximum whatever units name them, so
|
|
214
|
-
// the maximum survives the rewritten spelling instead of resetting on the
|
|
215
|
-
// next pass.
|
|
216
|
-
if (
|
|
217
|
-
largest &&
|
|
218
|
-
largest.number >= 0 &&
|
|
219
|
-
current.number === 0 &&
|
|
220
|
-
isPositionZeroUnit(current.unit)
|
|
221
|
-
) {
|
|
222
|
-
edits.set(index, { start: token[2], end: tokenEnd(token), text: '0' });
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
if (largest && !positionsComparable(current, largest)) {
|
|
226
|
-
largest = undefined;
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
if (largest && largest.number >= 0 && largest.number >= current.number) {
|
|
230
|
-
edits.set(index, { start: token[2], end: tokenEnd(token), text: '0' });
|
|
231
|
-
} else {
|
|
232
|
-
largest = current;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
return largest;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
151
|
/**
|
|
239
152
|
* Collect the colour stops of one gradient argument list, the count of leading
|
|
240
153
|
* arguments naming the line or shape instead of a stop, and the positions that
|
|
@@ -245,9 +158,10 @@ function zeroPositionEdits(input, position, maximum, edits) {
|
|
|
245
158
|
* @param {NonNullable<ReturnType<typeof balancedTokens>>} structure
|
|
246
159
|
* @param {{startIndex: number, endIndex: number}[]} args
|
|
247
160
|
* @param {boolean} linear Whether the line specification may hold an angle.
|
|
161
|
+
* @param {boolean} conic Whether the stop positions are angles.
|
|
248
162
|
* @return {{stops: ColorStop[], lineSpecifications: number, zeroEdits: Map<number, SourceEdit>, directionEdit: SourceEdit | undefined}}
|
|
249
163
|
*/
|
|
250
|
-
function collectColorStops(source, input, structure, args, linear) {
|
|
164
|
+
function collectColorStops(source, input, structure, args, linear, conic) {
|
|
251
165
|
/** @type {ColorStop[]} */
|
|
252
166
|
const stops = [];
|
|
253
167
|
/** @type {Map<number, SourceEdit>} */
|
|
@@ -285,7 +199,7 @@ function collectColorStops(source, input, structure, args, linear) {
|
|
|
285
199
|
}
|
|
286
200
|
// Positions before the first stop belong to the line specification.
|
|
287
201
|
if (!stops.length) continue;
|
|
288
|
-
largest = zeroPositionEdits(input, position, largest, zeroEdits);
|
|
202
|
+
largest = zeroPositionEdits(input, position, largest, zeroEdits, conic);
|
|
289
203
|
}
|
|
290
204
|
return { stops, lineSpecifications, zeroEdits, directionEdit };
|
|
291
205
|
}
|
|
@@ -301,9 +215,17 @@ function collectColorStops(source, input, structure, args, linear) {
|
|
|
301
215
|
* @param {number} lineSpecifications
|
|
302
216
|
* @param {number} args
|
|
303
217
|
* @param {Map<number, SourceEdit>} zeroEdits
|
|
218
|
+
* @param {boolean} conic
|
|
304
219
|
* @return {SourceEdit[]}
|
|
305
220
|
*/
|
|
306
|
-
function boundaryStopEdits(
|
|
221
|
+
function boundaryStopEdits(
|
|
222
|
+
input,
|
|
223
|
+
stops,
|
|
224
|
+
lineSpecifications,
|
|
225
|
+
args,
|
|
226
|
+
zeroEdits,
|
|
227
|
+
conic
|
|
228
|
+
) {
|
|
307
229
|
/** @type {SourceEdit[]} */
|
|
308
230
|
const edits = [];
|
|
309
231
|
for (const slot of new Set([0, stops.length - 1])) {
|
|
@@ -315,7 +237,7 @@ function boundaryStopEdits(input, stops, lineSpecifications, args, zeroEdits) {
|
|
|
315
237
|
if (!value) continue;
|
|
316
238
|
let removable = false;
|
|
317
239
|
if (slot === 0 && stop.argIndex === lineSpecifications) {
|
|
318
|
-
removable = value.number === 0 && isPositionZeroUnit(value.unit);
|
|
240
|
+
removable = value.number === 0 && isPositionZeroUnit(value.unit, conic);
|
|
319
241
|
}
|
|
320
242
|
if (
|
|
321
243
|
slot === stops.length - 1 &&
|
|
@@ -367,14 +289,12 @@ function optimise(decl) {
|
|
|
367
289
|
const end = structure.endForOpening(index);
|
|
368
290
|
if (end === undefined) continue;
|
|
369
291
|
const args = structure.topLevelSegments(index + 1, end);
|
|
292
|
+
// The legacy prefixed syntax has no `to <side>` form, where an angle
|
|
293
|
+
// would also point in the opposite sense.
|
|
294
|
+
const linear = name.includes('linear') && !name.startsWith('-webkit-');
|
|
295
|
+
const conic = name.includes('conic');
|
|
370
296
|
const { stops, lineSpecifications, zeroEdits, directionEdit } =
|
|
371
|
-
collectColorStops(
|
|
372
|
-
source,
|
|
373
|
-
input,
|
|
374
|
-
structure,
|
|
375
|
-
args,
|
|
376
|
-
name.includes('linear')
|
|
377
|
-
);
|
|
297
|
+
collectColorStops(source, input, structure, args, linear, conic);
|
|
378
298
|
if (directionEdit) replacements.push(directionEdit);
|
|
379
299
|
replacements.push(
|
|
380
300
|
...boundaryStopEdits(
|
|
@@ -382,7 +302,8 @@ function optimise(decl) {
|
|
|
382
302
|
stops,
|
|
383
303
|
lineSpecifications,
|
|
384
304
|
args.length,
|
|
385
|
-
zeroEdits
|
|
305
|
+
zeroEdits,
|
|
306
|
+
conic
|
|
386
307
|
),
|
|
387
308
|
...zeroEdits.values()
|
|
388
309
|
);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/** @import {CSSToken} from '@csstools/css-tokenizer' */
|
|
2
|
+
import cssnanoUtils from 'cssnano-utils';
|
|
3
|
+
|
|
4
|
+
const { asciiLowerCase, lengthUnits, numeric, tokenEnd } = cssnanoUtils;
|
|
5
|
+
|
|
6
|
+
/** @typedef {{start: number, end: number, text: string}} SourceEdit */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A position as a number and its unit, as reported by `numeric()`.
|
|
10
|
+
*
|
|
11
|
+
* @typedef {{number: number, unit: string}} PositionValue
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const angleUnits = new Set(['deg', 'grad', 'rad', 'turn']);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A zero in the position's own dimension and a zero percentage name the same
|
|
18
|
+
* gradient position, which is also what the unitless zero this plugin emits
|
|
19
|
+
* denotes. Conic positions are angles and the other gradients' are lengths; a
|
|
20
|
+
* zero of the other dimension is invalid there, so it must not be rewritten
|
|
21
|
+
* into a valid one.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} unit
|
|
24
|
+
* @param {boolean} conic Whether the positions are `<angle-percentage>`.
|
|
25
|
+
* @return {boolean}
|
|
26
|
+
*/
|
|
27
|
+
export function isPositionZeroUnit(unit, conic) {
|
|
28
|
+
const lowered = asciiLowerCase(unit);
|
|
29
|
+
return (
|
|
30
|
+
lowered === '' ||
|
|
31
|
+
lowered === '%' ||
|
|
32
|
+
(conic ? angleUnits : lengthUnits).has(lowered)
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Whether two positions are on the same scale, so their numbers can be ordered.
|
|
38
|
+
* Only a length and a percentage naming zero are interchangeable.
|
|
39
|
+
*
|
|
40
|
+
* @param {PositionValue} current
|
|
41
|
+
* @param {PositionValue} largest
|
|
42
|
+
* @param {boolean} conic
|
|
43
|
+
* @return {boolean}
|
|
44
|
+
*/
|
|
45
|
+
export function positionsComparable(current, largest, conic) {
|
|
46
|
+
const unit = asciiLowerCase(current.unit);
|
|
47
|
+
const largestUnit = asciiLowerCase(largest.unit);
|
|
48
|
+
if (unit === largestUnit) return true;
|
|
49
|
+
return (
|
|
50
|
+
(current.number === 0 || largest.number === 0) &&
|
|
51
|
+
isPositionZeroUnit(unit, conic) &&
|
|
52
|
+
isPositionZeroUnit(largestUnit, conic)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Colour stop fixup raises a position to the largest position before it, so a
|
|
58
|
+
* position at or below that non-negative maximum can be written as a zero.
|
|
59
|
+
*
|
|
60
|
+
* @param {readonly CSSToken[]} input
|
|
61
|
+
* @param {readonly number[]} position Offsets of the position tokens.
|
|
62
|
+
* @param {PositionValue | undefined} maximum Running maximum of the preceding positions.
|
|
63
|
+
* @param {Map<number, SourceEdit>} edits Collects the positions reduced to a zero.
|
|
64
|
+
* @param {boolean} conic
|
|
65
|
+
* @return {PositionValue | undefined} The maximum the following stops clamp to.
|
|
66
|
+
*/
|
|
67
|
+
export function zeroPositionEdits(input, position, maximum, edits, conic) {
|
|
68
|
+
let largest = maximum;
|
|
69
|
+
for (const index of position) {
|
|
70
|
+
const token = input[index];
|
|
71
|
+
const current = numeric(token);
|
|
72
|
+
if (!current) {
|
|
73
|
+
largest = undefined;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// A zero clamps to any non-negative maximum whatever units name them, so
|
|
77
|
+
// the maximum survives the rewritten spelling instead of resetting on the
|
|
78
|
+
// next pass.
|
|
79
|
+
if (
|
|
80
|
+
largest &&
|
|
81
|
+
largest.number >= 0 &&
|
|
82
|
+
current.number === 0 &&
|
|
83
|
+
isPositionZeroUnit(current.unit, conic)
|
|
84
|
+
) {
|
|
85
|
+
edits.set(index, { start: token[2], end: tokenEnd(token), text: '0' });
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (largest && !positionsComparable(current, largest, conic)) {
|
|
89
|
+
largest = undefined;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (largest && largest.number >= 0 && largest.number >= current.number) {
|
|
93
|
+
edits.set(index, { start: token[2], end: tokenEnd(token), text: '0' });
|
|
94
|
+
} else {
|
|
95
|
+
largest = current;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return largest;
|
|
99
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
export type SourceEdit = {
|
|
2
|
-
start: number;
|
|
3
|
-
end: number;
|
|
4
|
-
text: string;
|
|
5
|
-
};
|
|
6
1
|
export type ColorStop = {
|
|
7
2
|
/**
|
|
8
3
|
* Comma-separated argument the stop came from.
|
|
@@ -17,10 +12,6 @@ export type ColorStop = {
|
|
|
17
12
|
*/
|
|
18
13
|
position: readonly number[];
|
|
19
14
|
};
|
|
20
|
-
export type PositionValue = {
|
|
21
|
-
number: number;
|
|
22
|
-
unit: string;
|
|
23
|
-
};
|
|
24
15
|
/** @return {import('postcss').Plugin} */
|
|
25
16
|
declare function pluginCreator(): import('postcss').Plugin;
|
|
26
17
|
declare namespace pluginCreator {
|
package/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AA0DG,YAAkB,SAAS,GAC3B;;;;IAAmB,QAAQ,EAAhB,MAAM,CACjB;;;;IAAmB,QAAQ,EAAhB,MAAM,CACjB;;;;IAA8B,QAAQ,EAA3B,SAAS,MAAM,EAAE,CAC9B;CAAA,CAAA;AA6PD,yCAAyC;AACzC,iBAAS,aAAa,IADT,OAAO,SAAS,EAAE,MAAM,CAQpC;kBAPQ,aAAa;iBAQX,IAAI;;AAEf,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,aAAa,IAAI,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { CSSToken } from '@csstools/css-tokenizer';
|
|
2
|
+
export type SourceEdit = {
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
text: string;
|
|
6
|
+
};
|
|
7
|
+
export type PositionValue = {
|
|
8
|
+
number: number;
|
|
9
|
+
unit: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* A zero in the position's own dimension and a zero percentage name the same
|
|
13
|
+
* gradient position, which is also what the unitless zero this plugin emits
|
|
14
|
+
* denotes. Conic positions are angles and the other gradients' are lengths; a
|
|
15
|
+
* zero of the other dimension is invalid there, so it must not be rewritten
|
|
16
|
+
* into a valid one.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} unit
|
|
19
|
+
* @param {boolean} conic Whether the positions are `<angle-percentage>`.
|
|
20
|
+
* @return {boolean}
|
|
21
|
+
*/
|
|
22
|
+
export declare function isPositionZeroUnit(unit: string, conic: boolean): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Whether two positions are on the same scale, so their numbers can be ordered.
|
|
25
|
+
* Only a length and a percentage naming zero are interchangeable.
|
|
26
|
+
*
|
|
27
|
+
* @param {PositionValue} current
|
|
28
|
+
* @param {PositionValue} largest
|
|
29
|
+
* @param {boolean} conic
|
|
30
|
+
* @return {boolean}
|
|
31
|
+
*/
|
|
32
|
+
export declare function positionsComparable(current: PositionValue, largest: PositionValue, conic: boolean): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Colour stop fixup raises a position to the largest position before it, so a
|
|
35
|
+
* position at or below that non-negative maximum can be written as a zero.
|
|
36
|
+
*
|
|
37
|
+
* @param {readonly CSSToken[]} input
|
|
38
|
+
* @param {readonly number[]} position Offsets of the position tokens.
|
|
39
|
+
* @param {PositionValue | undefined} maximum Running maximum of the preceding positions.
|
|
40
|
+
* @param {Map<number, SourceEdit>} edits Collects the positions reduced to a zero.
|
|
41
|
+
* @param {boolean} conic
|
|
42
|
+
* @return {PositionValue | undefined} The maximum the following stops clamp to.
|
|
43
|
+
*/
|
|
44
|
+
export declare function zeroPositionEdits(input: readonly CSSToken[], position: readonly number[], maximum: PositionValue | undefined, edits: Map<number, SourceEdit>, conic: boolean): PositionValue | undefined;
|
|
45
|
+
//# sourceMappingURL=positions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"positions.d.ts","sourceRoot":"","sources":["../../src/lib/positions.js"],"names":[],"mappings":"AAAI,OAAQ,KAAA,EAAC,QAAQ,EAAC,MAAM,yBAAyB,CAAA;AAKjD,YAAsD,UAAU,GAAtD;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAY;AAKjE,YAA0C,aAAa,GAA7C;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAe;AAK1D;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAJ5B,MAI4B,EAAE,KAAK,EAHnC,OAGmC,GAFlC,OAAO,CASlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EALhC,aAKgC,EAAE,OAAO,EAJzC,aAIyC,EAAE,KAAK,EAHhD,OAGgD,GAF/C,OAAO,CAWlB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAP5B,SAAS,QAAQ,EAOW,EAAE,QAAQ,EANtC,SAAS,MAAM,EAMuB,EAAE,OAAO,EAL/C,aAAa,GAAG,SAK+B,EAAE,KAAK,EAJtD,GAAG,CAAC,MAAM,EAAE,UAAU,CAIgC,EAAE,KAAK,EAH7D,OAG6D,GAF5D,aAAa,GAAG,SAAS,CAkCpC"}
|