@remotion/svg-3d-engine 4.0.363 → 4.0.365

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.
@@ -0,0 +1,1378 @@
1
+ // src/truthy.ts
2
+ function truthy(value) {
3
+ return Boolean(value);
4
+ }
5
+
6
+ // src/matrix.ts
7
+ var stride = function({
8
+ v,
9
+ m,
10
+ width,
11
+ offset,
12
+ colStride
13
+ }) {
14
+ for (let i = 0;i < v.length; i++) {
15
+ m[i * width + (i * colStride + offset + width) % width] = v[i];
16
+ }
17
+ return m;
18
+ };
19
+ var identity4 = function() {
20
+ const n = 4;
21
+ let size = n * n;
22
+ const m = new Array(size);
23
+ while (size--) {
24
+ m[size] = size % (n + 1) === 0 ? 1 : 0;
25
+ }
26
+ return m;
27
+ };
28
+ var rotated = function(axisVec, radians) {
29
+ return rotatedUnitSinCos(normalize(axisVec), Math.sin(radians), Math.cos(radians));
30
+ };
31
+ var rotateX = (radians) => {
32
+ return rotated([1, 0, 0], radians);
33
+ };
34
+ var rotateY = (radians) => {
35
+ return rotated([0, 1, 0], radians);
36
+ };
37
+ var rotateZ = (radians) => {
38
+ return rotated([0, 0, 1], radians);
39
+ };
40
+ var multiplyMatrices = (matrix1, matrix2) => {
41
+ const result = new Array(16).fill(0);
42
+ for (let i = 0;i < 4; i++) {
43
+ for (let j = 0;j < 4; j++) {
44
+ for (let k = 0;k < 4; k++) {
45
+ result[i * 4 + j] += matrix1[i * 4 + k] * matrix2[k * 4 + j];
46
+ }
47
+ }
48
+ }
49
+ return result;
50
+ };
51
+ var reduceMatrices = (matrices) => {
52
+ return matrices.filter(truthy).slice().reverse().reduce((acc, cur) => {
53
+ return multiplyMatrices(acc, cur);
54
+ }, identity4());
55
+ };
56
+ var aroundCenterPoint = ({
57
+ matrix,
58
+ x,
59
+ y,
60
+ z
61
+ }) => {
62
+ return reduceMatrices([
63
+ translateX(-x),
64
+ translateY(-y),
65
+ translateZ(-z),
66
+ matrix,
67
+ translateX(x),
68
+ translateY(y),
69
+ translateZ(z)
70
+ ]);
71
+ };
72
+ var makeMatrix3dTransform = function(matrix) {
73
+ return `matrix3d(${[
74
+ matrix[0],
75
+ matrix[4],
76
+ matrix[8],
77
+ matrix[12],
78
+ matrix[1],
79
+ matrix[5],
80
+ matrix[9],
81
+ matrix[13],
82
+ matrix[2],
83
+ matrix[6],
84
+ matrix[10],
85
+ matrix[14],
86
+ matrix[3],
87
+ matrix[7],
88
+ matrix[11],
89
+ matrix[15]
90
+ ].join(", ")}`;
91
+ };
92
+ var interpolate = (a, b, t) => {
93
+ return a + (b - a) * t;
94
+ };
95
+ var interpolateMatrix4d = (input, matrix1, matrix2) => {
96
+ return [
97
+ interpolate(matrix1[0], matrix2[0], input),
98
+ interpolate(matrix1[1], matrix2[1], input),
99
+ interpolate(matrix1[2], matrix2[2], input),
100
+ interpolate(matrix1[3], matrix2[3], input),
101
+ interpolate(matrix1[4], matrix2[4], input),
102
+ interpolate(matrix1[5], matrix2[5], input),
103
+ interpolate(matrix1[6], matrix2[6], input),
104
+ interpolate(matrix1[7], matrix2[7], input),
105
+ interpolate(matrix1[8], matrix2[8], input),
106
+ interpolate(matrix1[9], matrix2[9], input),
107
+ interpolate(matrix1[10], matrix2[10], input),
108
+ interpolate(matrix1[11], matrix2[11], input),
109
+ interpolate(matrix1[12], matrix2[12], input),
110
+ interpolate(matrix1[13], matrix2[13], input),
111
+ interpolate(matrix1[14], matrix2[14], input),
112
+ interpolate(matrix1[15], matrix2[15], input)
113
+ ];
114
+ };
115
+ var scaled = function(value) {
116
+ const vec = typeof value === "number" ? [value, value, value] : value;
117
+ return stride({ v: vec, m: identity4(), width: 4, offset: 0, colStride: 1 });
118
+ };
119
+ var scaleX = (x) => {
120
+ return scaled([x, 1, 1]);
121
+ };
122
+ var scaleY = (y) => {
123
+ return scaled([1, y, 1]);
124
+ };
125
+ var rotatedUnitSinCos = function(axisVec, sinAngle, cosAngle) {
126
+ const x = axisVec[0];
127
+ const y = axisVec[1];
128
+ const z = axisVec[2];
129
+ const c = cosAngle;
130
+ const s = sinAngle;
131
+ const t = 1 - c;
132
+ return [
133
+ t * x * x + c,
134
+ t * x * y - s * z,
135
+ t * x * z + s * y,
136
+ 0,
137
+ t * x * y + s * z,
138
+ t * y * y + c,
139
+ t * y * z - s * x,
140
+ 0,
141
+ t * x * z - s * y,
142
+ t * y * z + s * x,
143
+ t * z * z + c,
144
+ 0,
145
+ 0,
146
+ 0,
147
+ 0,
148
+ 1
149
+ ];
150
+ };
151
+ var normalize = function(v) {
152
+ return mulScalar(v, 1 / vectorLength(v));
153
+ };
154
+ var vectorLength = function(v) {
155
+ return Math.sqrt(lengthSquared(v));
156
+ };
157
+ var lengthSquared = function(v) {
158
+ return dot(v, v);
159
+ };
160
+ var dot = function(a, b) {
161
+ if (a.length !== b.length) {
162
+ throw new Error(`Cannot perform dot product on arrays of different length (${a.length} vs ${b.length})`);
163
+ }
164
+ return a.map((v, i) => {
165
+ return v * b[i];
166
+ }).reduce((acc, cur) => {
167
+ return acc + cur;
168
+ });
169
+ };
170
+ var translated = function(vec) {
171
+ return stride({
172
+ v: vec,
173
+ m: identity4(),
174
+ width: 4,
175
+ offset: 3,
176
+ colStride: 0
177
+ });
178
+ };
179
+ var translateX = (x) => {
180
+ return translated([x, 0, 0]);
181
+ };
182
+ var translateY = (y) => {
183
+ return translated([0, y, 0]);
184
+ };
185
+ var translateZ = (z) => {
186
+ return translated([0, 0, z]);
187
+ };
188
+ var mulScalar = function(v, s) {
189
+ return v.map((i) => {
190
+ return i * s;
191
+ });
192
+ };
193
+ function multiplyMatrixAndSvgInstruction(matrix, point) {
194
+ if (point.type === "C") {
195
+ return {
196
+ type: "C",
197
+ cp1: multiplyMatrix(matrix, point.cp1),
198
+ cp2: multiplyMatrix(matrix, point.cp2),
199
+ point: multiplyMatrix(matrix, point.point)
200
+ };
201
+ }
202
+ if (point.type === "Q") {
203
+ return {
204
+ type: "Q",
205
+ cp: multiplyMatrix(matrix, point.cp),
206
+ point: multiplyMatrix(matrix, point.point)
207
+ };
208
+ }
209
+ if (point.type === "M") {
210
+ return {
211
+ type: "M",
212
+ point: multiplyMatrix(matrix, point.point)
213
+ };
214
+ }
215
+ if (point.type === "L") {
216
+ return {
217
+ type: "L",
218
+ point: multiplyMatrix(matrix, point.point)
219
+ };
220
+ }
221
+ if (point.type === "Z") {
222
+ return {
223
+ type: "Z",
224
+ point: multiplyMatrix(matrix, point.point)
225
+ };
226
+ }
227
+ throw new Error("Unknown instruction type: " + JSON.stringify(point));
228
+ }
229
+ var multiplyMatrix = (matrix, point) => {
230
+ if (matrix.length !== 16 || point.length !== 4) {
231
+ throw new Error("Invalid matrix or vector dimension");
232
+ }
233
+ const result = [0, 0, 0, 0];
234
+ for (let i = 0;i < 4; i++) {
235
+ for (let j = 0;j < 4; j++) {
236
+ result[i] += matrix[i * 4 + j] * point[j];
237
+ }
238
+ }
239
+ return result;
240
+ };
241
+ // src/3d-svg.ts
242
+ var serializeThreeDReducedInstruction = (instruction) => {
243
+ if (instruction.type === "M") {
244
+ return `M ${instruction.point[0]} ${instruction.point[1]}`;
245
+ }
246
+ if (instruction.type === "L") {
247
+ return `L ${instruction.point[0]} ${instruction.point[1]}`;
248
+ }
249
+ if (instruction.type === "C") {
250
+ return `C ${instruction.cp1[0]} ${instruction.cp1[1]} ${instruction.cp2[0]} ${instruction.cp2[1]} ${instruction.point[0]} ${instruction.point[1]}`;
251
+ }
252
+ if (instruction.type === "Q") {
253
+ return `Q ${instruction.cp[0]} ${instruction.cp[1]} ${instruction.point[0]} ${instruction.point[1]}`;
254
+ }
255
+ if (instruction.type === "Z") {
256
+ return "Z";
257
+ }
258
+ throw new Error("Unknown instruction type");
259
+ };
260
+ var threeDIntoSvgPath = (instructions) => instructions.map((instruction) => serializeThreeDReducedInstruction(instruction)).join(" ");
261
+ // ../paths/dist/esm/index.mjs
262
+ var length = {
263
+ a: 7,
264
+ A: 7,
265
+ C: 6,
266
+ c: 6,
267
+ H: 1,
268
+ h: 1,
269
+ L: 2,
270
+ l: 2,
271
+ M: 2,
272
+ m: 2,
273
+ Q: 4,
274
+ q: 4,
275
+ S: 4,
276
+ s: 4,
277
+ T: 2,
278
+ t: 2,
279
+ V: 1,
280
+ v: 1,
281
+ Z: 0,
282
+ z: 0
283
+ };
284
+ var chunkExact = (array, instruction) => {
285
+ const chunks = [];
286
+ const expectedSize = length[instruction];
287
+ if (array.length % expectedSize !== 0) {
288
+ throw new Error(`Expected number of arguments of SVG instruction "${instruction} ${array.join(" ")}" to be a multiple of ${expectedSize}`);
289
+ }
290
+ for (let i = 0;i < array.length; i += expectedSize) {
291
+ chunks.push(array.slice(i, i + expectedSize));
292
+ }
293
+ return chunks;
294
+ };
295
+ var makeInstructions = (arr, instruction, cb) => {
296
+ return chunkExact(arr, instruction).map((args) => {
297
+ return cb(args);
298
+ });
299
+ };
300
+ var segmentRegExp = /([astvzqmhlc])([^astvzqmhlc]*)/gi;
301
+ var numberRegExp = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/gi;
302
+ var parseValues = (args, instructionType) => {
303
+ const numbers = args.match(numberRegExp);
304
+ if (!numbers) {
305
+ if (instructionType === "Z" || instructionType === "z") {
306
+ return [];
307
+ }
308
+ throw new Error(`Malformed path data: ${instructionType} was expected to have numbers afterwards`);
309
+ }
310
+ const expectedArguments = length[instructionType];
311
+ if (numbers.length % expectedArguments !== 0) {
312
+ throw new Error(`Malformed path data: ${instructionType} was expected to have a multiple of ${expectedArguments} numbers, but got "${instructionType} ${numbers.join(" ")} instead"`);
313
+ }
314
+ return numbers.map(Number);
315
+ };
316
+ var parsePath = (path) => {
317
+ if (!path) {
318
+ throw new Error("No path provided");
319
+ }
320
+ const segments = path.match(segmentRegExp);
321
+ if (!segments) {
322
+ throw new Error(`No path elements found in string ${path}`);
323
+ }
324
+ return segments.map((segmentString) => {
325
+ const command = segmentString.charAt(0);
326
+ const args = parseValues(segmentString.substring(1), command);
327
+ if (command === "M" && args.length > 2) {
328
+ const segmentsArray = [];
329
+ segmentsArray.push({
330
+ type: command,
331
+ x: args[0],
332
+ y: args[1]
333
+ });
334
+ segmentsArray.push(...makeInstructions(args.slice(2), "L", (numbers) => ({
335
+ type: "L",
336
+ x: numbers[0],
337
+ y: numbers[1]
338
+ })));
339
+ return segmentsArray;
340
+ }
341
+ if (command === "m" && args.length > 2) {
342
+ const segmentsArray = [];
343
+ segmentsArray.push({
344
+ type: command,
345
+ dx: args[0],
346
+ dy: args[1]
347
+ });
348
+ segmentsArray.push(...makeInstructions(args.slice(2), "l", (numbers) => ({
349
+ type: "l",
350
+ dx: numbers[0],
351
+ dy: numbers[1]
352
+ })));
353
+ return segmentsArray;
354
+ }
355
+ if (command === "Z" || command === "z") {
356
+ return [
357
+ {
358
+ type: "Z"
359
+ }
360
+ ];
361
+ }
362
+ if (command === "A") {
363
+ return makeInstructions(args, command, (numbers) => ({
364
+ type: command,
365
+ rx: numbers[0],
366
+ ry: numbers[1],
367
+ xAxisRotation: numbers[2],
368
+ largeArcFlag: numbers[3] === 1,
369
+ sweepFlag: numbers[4] === 1,
370
+ x: numbers[5],
371
+ y: numbers[6]
372
+ }));
373
+ }
374
+ if (command === "a") {
375
+ return makeInstructions(args, command, (numbers) => ({
376
+ type: command,
377
+ rx: numbers[0],
378
+ ry: numbers[1],
379
+ xAxisRotation: numbers[2],
380
+ largeArcFlag: numbers[3] === 1,
381
+ sweepFlag: numbers[4] === 1,
382
+ dx: numbers[5],
383
+ dy: numbers[6]
384
+ }));
385
+ }
386
+ if (command === "C") {
387
+ return makeInstructions(args, command, (numbers) => ({
388
+ type: command,
389
+ cp1x: numbers[0],
390
+ cp1y: numbers[1],
391
+ cp2x: numbers[2],
392
+ cp2y: numbers[3],
393
+ x: numbers[4],
394
+ y: numbers[5]
395
+ }));
396
+ }
397
+ if (command === "c") {
398
+ return makeInstructions(args, command, (numbers) => ({
399
+ type: command,
400
+ cp1dx: numbers[0],
401
+ cp1dy: numbers[1],
402
+ cp2dx: numbers[2],
403
+ cp2dy: numbers[3],
404
+ dx: numbers[4],
405
+ dy: numbers[5]
406
+ }));
407
+ }
408
+ if (command === "S") {
409
+ return makeInstructions(args, command, (numbers) => ({
410
+ type: command,
411
+ cpx: numbers[0],
412
+ cpy: numbers[1],
413
+ x: numbers[2],
414
+ y: numbers[3]
415
+ }));
416
+ }
417
+ if (command === "s") {
418
+ return makeInstructions(args, command, (numbers) => ({
419
+ type: command,
420
+ cpdx: numbers[0],
421
+ cpdy: numbers[1],
422
+ dx: numbers[2],
423
+ dy: numbers[3]
424
+ }));
425
+ }
426
+ if (command === "H") {
427
+ return makeInstructions(args, command, (numbers) => ({
428
+ type: command,
429
+ x: numbers[0]
430
+ }));
431
+ }
432
+ if (command === "h") {
433
+ return makeInstructions(args, command, (numbers) => ({
434
+ type: command,
435
+ dx: numbers[0]
436
+ }));
437
+ }
438
+ if (command === "V") {
439
+ return makeInstructions(args, command, (numbers) => ({
440
+ type: command,
441
+ y: numbers[0]
442
+ }));
443
+ }
444
+ if (command === "v") {
445
+ return makeInstructions(args, command, (numbers) => ({
446
+ type: command,
447
+ dy: numbers[0]
448
+ }));
449
+ }
450
+ if (command === "L") {
451
+ return makeInstructions(args, command, (numbers) => ({
452
+ type: command,
453
+ x: numbers[0],
454
+ y: numbers[1]
455
+ }));
456
+ }
457
+ if (command === "M") {
458
+ return makeInstructions(args, command, (numbers) => ({
459
+ type: command,
460
+ x: numbers[0],
461
+ y: numbers[1]
462
+ }));
463
+ }
464
+ if (command === "m") {
465
+ return makeInstructions(args, command, (numbers) => ({
466
+ type: command,
467
+ dx: numbers[0],
468
+ dy: numbers[1]
469
+ }));
470
+ }
471
+ if (command === "l") {
472
+ return makeInstructions(args, command, (numbers) => ({
473
+ type: command,
474
+ dx: numbers[0],
475
+ dy: numbers[1]
476
+ }));
477
+ }
478
+ if (command === "Q") {
479
+ return makeInstructions(args, command, (numbers) => ({
480
+ type: command,
481
+ cpx: numbers[0],
482
+ cpy: numbers[1],
483
+ x: numbers[2],
484
+ y: numbers[3]
485
+ }));
486
+ }
487
+ if (command === "q") {
488
+ return makeInstructions(args, command, (numbers) => ({
489
+ type: command,
490
+ cpdx: numbers[0],
491
+ cpdy: numbers[1],
492
+ dx: numbers[2],
493
+ dy: numbers[3]
494
+ }));
495
+ }
496
+ if (command === "T") {
497
+ return makeInstructions(args, command, (numbers) => ({
498
+ type: command,
499
+ x: numbers[0],
500
+ y: numbers[1]
501
+ }));
502
+ }
503
+ if (command === "t") {
504
+ return makeInstructions(args, command, (numbers) => ({
505
+ type: command,
506
+ dx: numbers[0],
507
+ dy: numbers[1]
508
+ }));
509
+ }
510
+ throw new Error(`Invalid path element ${segmentString}`);
511
+ }, []).flat(1);
512
+ };
513
+ var convertQToCInstruction = (instruction, startPoint) => {
514
+ const cp1x = startPoint.x + 2 / 3 * (instruction.cpx - startPoint.x);
515
+ const cp1y = startPoint.y + 2 / 3 * (instruction.cpy - startPoint.y);
516
+ const cp2x = instruction.x + 2 / 3 * (instruction.cpx - instruction.x);
517
+ const cp2y = instruction.y + 2 / 3 * (instruction.cpy - instruction.y);
518
+ return {
519
+ type: "C",
520
+ cp1x,
521
+ cp1y,
522
+ cp2x,
523
+ cp2y,
524
+ x: instruction.x,
525
+ y: instruction.y
526
+ };
527
+ };
528
+ var iterateOverSegments = ({
529
+ segments,
530
+ iterate
531
+ }) => {
532
+ let x = 0;
533
+ let y = 0;
534
+ let initialX = 0;
535
+ let initialY = 0;
536
+ let cpX = null;
537
+ let cpY = null;
538
+ const newSegments = segments.map((s, i) => {
539
+ const newSeg = iterate({
540
+ segment: s,
541
+ x,
542
+ y,
543
+ prevSegment: segments[i - 1] ?? null,
544
+ initialX,
545
+ initialY,
546
+ cpX,
547
+ cpY
548
+ });
549
+ switch (s.type) {
550
+ case "M":
551
+ initialX = s.x;
552
+ initialY = s.y;
553
+ x = s.x;
554
+ y = s.y;
555
+ cpX = null;
556
+ cpY = null;
557
+ break;
558
+ case "Q":
559
+ x = s.x;
560
+ y = s.y;
561
+ cpX = s.cpx;
562
+ cpY = s.cpy;
563
+ break;
564
+ case "A":
565
+ x = s.x;
566
+ y = s.y;
567
+ cpX = null;
568
+ cpY = null;
569
+ break;
570
+ case "C":
571
+ x = s.x;
572
+ y = s.y;
573
+ cpX = s.cp2x;
574
+ cpY = s.cp2y;
575
+ break;
576
+ case "S":
577
+ x = s.x;
578
+ y = s.y;
579
+ cpX = s.cpx;
580
+ cpY = s.cpy;
581
+ break;
582
+ case "T":
583
+ if (cpX !== null && cpY !== null) {
584
+ cpX = x - (cpX - x);
585
+ cpY = y - (cpY - y);
586
+ }
587
+ x = s.x;
588
+ y = s.y;
589
+ break;
590
+ case "L":
591
+ x = s.x;
592
+ y = s.y;
593
+ cpX = null;
594
+ cpY = null;
595
+ break;
596
+ case "V":
597
+ y = s.y;
598
+ cpX = null;
599
+ cpY = null;
600
+ break;
601
+ case "H":
602
+ x = s.x;
603
+ cpX = null;
604
+ cpY = null;
605
+ break;
606
+ case "Z":
607
+ x = initialX;
608
+ y = initialY;
609
+ cpX = null;
610
+ cpY = null;
611
+ break;
612
+ default:
613
+ throw new Error(`Unexpected instruction ${s.type}`);
614
+ }
615
+ return newSeg;
616
+ });
617
+ return newSegments.flat(1);
618
+ };
619
+ var TAU = Math.PI * 2;
620
+ function approximate_unit_arc(theta1, delta_theta) {
621
+ const alpha = 4 / 3 * Math.tan(delta_theta / 4);
622
+ const x1 = Math.cos(theta1);
623
+ const y1 = Math.sin(theta1);
624
+ const x2 = Math.cos(theta1 + delta_theta);
625
+ const y2 = Math.sin(theta1 + delta_theta);
626
+ return [
627
+ x1,
628
+ y1,
629
+ x1 - y1 * alpha,
630
+ y1 + x1 * alpha,
631
+ x2 + y2 * alpha,
632
+ y2 - x2 * alpha,
633
+ x2,
634
+ y2
635
+ ];
636
+ }
637
+ function unit_vector_angle(ux, uy, vx, vy) {
638
+ const sign = ux * vy - uy * vx < 0 ? -1 : 1;
639
+ let dot2 = ux * vx + uy * vy;
640
+ if (dot2 > 1) {
641
+ dot2 = 1;
642
+ }
643
+ if (dot2 < -1) {
644
+ dot2 = -1;
645
+ }
646
+ return sign * Math.acos(dot2);
647
+ }
648
+ function get_arc_center({
649
+ x1,
650
+ y1,
651
+ x2,
652
+ y2,
653
+ largeArcFlag,
654
+ sweepFlag,
655
+ rx,
656
+ ry,
657
+ sin_phi,
658
+ cos_phi
659
+ }) {
660
+ const x1p = cos_phi * (x1 - x2) / 2 + sin_phi * (y1 - y2) / 2;
661
+ const y1p = -sin_phi * (x1 - x2) / 2 + cos_phi * (y1 - y2) / 2;
662
+ const rx_sq = rx * rx;
663
+ const ry_sq = ry * ry;
664
+ const x1p_sq = x1p * x1p;
665
+ const y1p_sq = y1p * y1p;
666
+ let radicant = rx_sq * ry_sq - rx_sq * y1p_sq - ry_sq * x1p_sq;
667
+ if (radicant < 0) {
668
+ radicant = 0;
669
+ }
670
+ radicant /= rx_sq * y1p_sq + ry_sq * x1p_sq;
671
+ radicant = Math.sqrt(radicant) * (largeArcFlag === sweepFlag ? -1 : 1);
672
+ const cxp = radicant * rx / ry * y1p;
673
+ const cyp = radicant * -ry / rx * x1p;
674
+ const cx = cos_phi * cxp - sin_phi * cyp + (x1 + x2) / 2;
675
+ const cy = sin_phi * cxp + cos_phi * cyp + (y1 + y2) / 2;
676
+ const v1x = (x1p - cxp) / rx;
677
+ const v1y = (y1p - cyp) / ry;
678
+ const v2x = (-x1p - cxp) / rx;
679
+ const v2y = (-y1p - cyp) / ry;
680
+ const theta1 = unit_vector_angle(1, 0, v1x, v1y);
681
+ let delta_theta = unit_vector_angle(v1x, v1y, v2x, v2y);
682
+ if (sweepFlag === false && delta_theta > 0) {
683
+ delta_theta -= TAU;
684
+ }
685
+ if (sweepFlag === true && delta_theta < 0) {
686
+ delta_theta += TAU;
687
+ }
688
+ return [cx, cy, theta1, delta_theta];
689
+ }
690
+ function arcToCircle({
691
+ x1,
692
+ y1,
693
+ x2,
694
+ y2,
695
+ largeArcFlag,
696
+ sweepFlag,
697
+ rx,
698
+ ry,
699
+ phi
700
+ }) {
701
+ const sin_phi = Math.sin(phi * TAU / 360);
702
+ const cos_phi = Math.cos(phi * TAU / 360);
703
+ const x1p = cos_phi * (x1 - x2) / 2 + sin_phi * (y1 - y2) / 2;
704
+ const y1p = -sin_phi * (x1 - x2) / 2 + cos_phi * (y1 - y2) / 2;
705
+ if (x1p === 0 && y1p === 0) {
706
+ return [];
707
+ }
708
+ if (rx === 0 || ry === 0) {
709
+ return [];
710
+ }
711
+ rx = Math.abs(rx);
712
+ ry = Math.abs(ry);
713
+ const lambda = x1p * x1p / (rx * rx) + y1p * y1p / (ry * ry);
714
+ if (lambda > 1) {
715
+ rx *= Math.sqrt(lambda);
716
+ ry *= Math.sqrt(lambda);
717
+ }
718
+ const cc = get_arc_center({
719
+ x1,
720
+ y1,
721
+ x2,
722
+ y2,
723
+ largeArcFlag,
724
+ sweepFlag,
725
+ rx,
726
+ ry,
727
+ sin_phi,
728
+ cos_phi
729
+ });
730
+ const result = [];
731
+ let theta1 = cc[2];
732
+ let delta_theta = cc[3];
733
+ const segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1);
734
+ delta_theta /= segments;
735
+ for (let i = 0;i < segments; i++) {
736
+ result.push(approximate_unit_arc(theta1, delta_theta));
737
+ theta1 += delta_theta;
738
+ }
739
+ return result.map((curve) => {
740
+ for (let i = 0;i < curve.length; i += 2) {
741
+ let x = curve[i + 0];
742
+ let y = curve[i + 1];
743
+ x *= rx;
744
+ y *= ry;
745
+ const xp = cos_phi * x - sin_phi * y;
746
+ const yp = sin_phi * x + cos_phi * y;
747
+ curve[i + 0] = xp + cc[0];
748
+ curve[i + 1] = yp + cc[1];
749
+ }
750
+ return curve;
751
+ });
752
+ }
753
+ var removeATSHVQInstructions = (segments) => {
754
+ return iterateOverSegments({
755
+ segments,
756
+ iterate: ({ segment, prevSegment, x, y, cpX, cpY }) => {
757
+ if (segment.type === "H") {
758
+ return [{ type: "L", x: segment.x, y }];
759
+ }
760
+ if (segment.type === "V") {
761
+ return [{ type: "L", x, y: segment.y }];
762
+ }
763
+ if (segment.type === "A") {
764
+ const nextX = segment.x;
765
+ const nextY = segment.y;
766
+ const new_segments = arcToCircle({
767
+ x1: x,
768
+ y1: y,
769
+ x2: nextX,
770
+ y2: nextY,
771
+ largeArcFlag: segment.largeArcFlag,
772
+ sweepFlag: segment.sweepFlag,
773
+ rx: segment.rx,
774
+ ry: segment.ry,
775
+ phi: segment.xAxisRotation
776
+ });
777
+ if (new_segments.length === 0) {
778
+ return [
779
+ {
780
+ type: "L",
781
+ x: segment.x,
782
+ y: segment.y
783
+ }
784
+ ];
785
+ }
786
+ const result = new_segments.map((_s) => {
787
+ return {
788
+ type: "C",
789
+ cp1x: _s[2],
790
+ cp1y: _s[3],
791
+ cp2x: _s[4],
792
+ cp2y: _s[5],
793
+ x: _s[6],
794
+ y: _s[7]
795
+ };
796
+ });
797
+ return result;
798
+ }
799
+ if (segment.type === "T") {
800
+ let prevControlX = 0;
801
+ let prevControlY = 0;
802
+ if (prevSegment && (prevSegment.type === "Q" || prevSegment.type === "T")) {
803
+ prevControlX = cpX;
804
+ prevControlY = cpY;
805
+ } else {
806
+ prevControlX = x;
807
+ prevControlY = y;
808
+ }
809
+ const vectorX = prevControlX - x;
810
+ const vectorY = prevControlY - y;
811
+ const newControlX = x - vectorX;
812
+ const newControlY = y - vectorY;
813
+ return [
814
+ convertQToCInstruction({
815
+ type: "Q",
816
+ cpx: newControlX,
817
+ cpy: newControlY,
818
+ x: segment.x,
819
+ y: segment.y
820
+ }, { x, y })
821
+ ];
822
+ }
823
+ if (segment.type === "S") {
824
+ let prevControlX = 0;
825
+ let prevControlY = 0;
826
+ if (prevSegment && prevSegment.type === "C") {
827
+ prevControlX = prevSegment.cp2x;
828
+ prevControlY = prevSegment.cp2y;
829
+ } else if (prevSegment && prevSegment.type === "S") {
830
+ prevControlX = prevSegment.cpx;
831
+ prevControlY = prevSegment.cpy;
832
+ } else {
833
+ prevControlX = x;
834
+ prevControlY = y;
835
+ }
836
+ const vectorX = prevControlX - x;
837
+ const vectorY = prevControlY - y;
838
+ const newControlX = x - vectorX;
839
+ const newControlY = y - vectorY;
840
+ return [
841
+ {
842
+ type: "C",
843
+ cp1x: newControlX,
844
+ cp1y: newControlY,
845
+ cp2x: segment.cpx,
846
+ cp2y: segment.cpy,
847
+ x: segment.x,
848
+ y: segment.y
849
+ }
850
+ ];
851
+ }
852
+ if (segment.type === "Q") {
853
+ return [convertQToCInstruction(segment, { x, y })];
854
+ }
855
+ return [segment];
856
+ }
857
+ });
858
+ };
859
+ var normalizeInstructions = (instructions) => {
860
+ const normalized = [];
861
+ let x = 0;
862
+ let y = 0;
863
+ let moveX = 0;
864
+ let moveY = 0;
865
+ for (let i = 0;i < instructions.length; i++) {
866
+ const instruction = instructions[i];
867
+ if (instruction.type === "M") {
868
+ moveX = instruction.x;
869
+ moveY = instruction.y;
870
+ } else if (instruction.type === "m") {
871
+ moveX += instruction.dx;
872
+ moveY += instruction.dy;
873
+ }
874
+ if (instruction.type === "A" || instruction.type === "C" || instruction.type === "L" || instruction.type === "M" || instruction.type === "Q" || instruction.type === "S" || instruction.type === "T") {
875
+ normalized.push(instruction);
876
+ x = instruction.x;
877
+ y = instruction.y;
878
+ continue;
879
+ }
880
+ if (instruction.type === "a" || instruction.type === "c" || instruction.type === "l" || instruction.type === "m" || instruction.type === "q" || instruction.type === "s" || instruction.type === "t") {
881
+ const currentX = x;
882
+ const currentY = y;
883
+ x += instruction.dx;
884
+ y += instruction.dy;
885
+ if (instruction.type === "a") {
886
+ normalized.push({
887
+ type: "A",
888
+ largeArcFlag: instruction.largeArcFlag,
889
+ rx: instruction.rx,
890
+ ry: instruction.ry,
891
+ sweepFlag: instruction.sweepFlag,
892
+ xAxisRotation: instruction.xAxisRotation,
893
+ x,
894
+ y
895
+ });
896
+ continue;
897
+ }
898
+ if (instruction.type === "c") {
899
+ normalized.push({
900
+ type: "C",
901
+ cp1x: instruction.cp1dx + currentX,
902
+ cp1y: instruction.cp1dy + currentY,
903
+ cp2x: instruction.cp2dx + currentX,
904
+ cp2y: instruction.cp2dy + currentY,
905
+ x,
906
+ y
907
+ });
908
+ continue;
909
+ }
910
+ if (instruction.type === "l") {
911
+ normalized.push({
912
+ type: "L",
913
+ x,
914
+ y
915
+ });
916
+ continue;
917
+ }
918
+ if (instruction.type === "m") {
919
+ normalized.push({
920
+ type: "M",
921
+ x,
922
+ y
923
+ });
924
+ continue;
925
+ }
926
+ if (instruction.type === "q") {
927
+ normalized.push({
928
+ type: "Q",
929
+ cpx: instruction.cpdx + currentX,
930
+ cpy: instruction.cpdy + currentY,
931
+ x,
932
+ y
933
+ });
934
+ continue;
935
+ }
936
+ if (instruction.type === "s") {
937
+ normalized.push({
938
+ type: "S",
939
+ cpx: instruction.cpdx + currentX,
940
+ cpy: instruction.cpdy + currentY,
941
+ x,
942
+ y
943
+ });
944
+ continue;
945
+ }
946
+ if (instruction.type === "t") {
947
+ normalized.push({
948
+ type: "T",
949
+ x,
950
+ y
951
+ });
952
+ continue;
953
+ }
954
+ }
955
+ if (instruction.type === "H") {
956
+ normalized.push(instruction);
957
+ x = instruction.x;
958
+ continue;
959
+ }
960
+ if (instruction.type === "V") {
961
+ normalized.push(instruction);
962
+ y = instruction.y;
963
+ continue;
964
+ }
965
+ if (instruction.type === "Z") {
966
+ normalized.push(instruction);
967
+ x = moveX;
968
+ y = moveY;
969
+ continue;
970
+ }
971
+ if (instruction.type === "h") {
972
+ x += instruction.dx;
973
+ normalized.push({
974
+ type: "H",
975
+ x
976
+ });
977
+ continue;
978
+ }
979
+ if (instruction.type === "v") {
980
+ y += instruction.dy;
981
+ normalized.push({
982
+ type: "V",
983
+ y
984
+ });
985
+ continue;
986
+ }
987
+ throw new Error("Unknown instruction type: " + instruction.type);
988
+ }
989
+ return normalized;
990
+ };
991
+ var reduceInstructions = (instruction) => {
992
+ const simplified = normalizeInstructions(instruction);
993
+ return removeATSHVQInstructions(simplified);
994
+ };
995
+
996
+ // src/fix-z.ts
997
+ var turnInto3D = (instructions) => {
998
+ let lastMove = [0, 0, 0, 1];
999
+ const newInstructions = [];
1000
+ const reduced = reduceInstructions(instructions);
1001
+ for (let i = 0;i < reduced.length; i++) {
1002
+ const instruction = reduced[i];
1003
+ if (instruction.type === "Z") {
1004
+ newInstructions.push({
1005
+ type: "Z",
1006
+ point: lastMove
1007
+ });
1008
+ } else if (instruction.type === "M") {
1009
+ lastMove = [instruction.x, instruction.y, 0, 1];
1010
+ newInstructions.push({
1011
+ point: [instruction.x, instruction.y, 0, 1],
1012
+ type: "M"
1013
+ });
1014
+ } else if (instruction.type === "L") {
1015
+ newInstructions.push({
1016
+ type: "L",
1017
+ point: [instruction.x, instruction.y, 0, 1]
1018
+ });
1019
+ } else if (instruction.type === "C") {
1020
+ newInstructions.push({
1021
+ type: "C",
1022
+ point: [instruction.x, instruction.y, 0, 1],
1023
+ cp1: [instruction.cp1x, instruction.cp1y, 0, 1],
1024
+ cp2: [instruction.cp2x, instruction.cp2y, 0, 1]
1025
+ });
1026
+ } else {
1027
+ throw new Error("unknown");
1028
+ }
1029
+ }
1030
+ return newInstructions;
1031
+ };
1032
+
1033
+ // src/map-face.ts
1034
+ var translateSvgInstruction = (instruction, x, y, z) => {
1035
+ if (instruction.type === "M") {
1036
+ return {
1037
+ type: "M",
1038
+ point: [
1039
+ instruction.point[0] + x,
1040
+ instruction.point[1] + y,
1041
+ instruction.point[2] + z,
1042
+ instruction.point[3]
1043
+ ]
1044
+ };
1045
+ }
1046
+ if (instruction.type === "L") {
1047
+ return {
1048
+ type: "L",
1049
+ point: [
1050
+ instruction.point[0] + x,
1051
+ instruction.point[1] + y,
1052
+ instruction.point[2] + z,
1053
+ instruction.point[3]
1054
+ ]
1055
+ };
1056
+ }
1057
+ if (instruction.type === "C") {
1058
+ return {
1059
+ type: "C",
1060
+ point: [
1061
+ instruction.point[0] + x,
1062
+ instruction.point[1] + y,
1063
+ instruction.point[2] + z,
1064
+ instruction.point[3]
1065
+ ],
1066
+ cp1: [
1067
+ instruction.cp1[0] + x,
1068
+ instruction.cp1[1] + y,
1069
+ instruction.cp1[2] + z,
1070
+ instruction.cp1[3]
1071
+ ],
1072
+ cp2: [
1073
+ instruction.cp2[0] + x,
1074
+ instruction.cp2[1] + y,
1075
+ instruction.cp2[2] + z,
1076
+ instruction.cp2[3]
1077
+ ]
1078
+ };
1079
+ }
1080
+ if (instruction.type === "Q") {
1081
+ return {
1082
+ type: "Q",
1083
+ point: [
1084
+ instruction.point[0] + x,
1085
+ instruction.point[1] + y,
1086
+ instruction.point[2] + z,
1087
+ instruction.point[3]
1088
+ ],
1089
+ cp: [
1090
+ instruction.cp[0] + x,
1091
+ instruction.cp[1] + y,
1092
+ instruction.cp[2] + z,
1093
+ instruction.cp[3]
1094
+ ]
1095
+ };
1096
+ }
1097
+ if (instruction.type === "Z") {
1098
+ return {
1099
+ type: "Z",
1100
+ point: [
1101
+ instruction.point[0] + x,
1102
+ instruction.point[1] + y,
1103
+ instruction.point[2] + z,
1104
+ instruction.point[3]
1105
+ ]
1106
+ };
1107
+ }
1108
+ throw new Error("Unknown instruction type: " + JSON.stringify(instruction));
1109
+ };
1110
+ var transformPath = ({
1111
+ path,
1112
+ transformation
1113
+ }) => {
1114
+ const parsed = parsePath(path);
1115
+ const reduced = reduceInstructions(parsed);
1116
+ const threeD = turnInto3D(reduced);
1117
+ return threeDIntoSvgPath(threeD.map((p) => {
1118
+ return multiplyMatrixAndSvgInstruction(transformation, p);
1119
+ }));
1120
+ };
1121
+ var transformFace = (face, transformations) => {
1122
+ return {
1123
+ ...face,
1124
+ points: face.points.map((p) => {
1125
+ return transformations.reduce((acc, t) => {
1126
+ return multiplyMatrixAndSvgInstruction(t, acc);
1127
+ }, p);
1128
+ }),
1129
+ centerPoint: transformations.reduce((acc, t) => {
1130
+ const result = multiplyMatrix(t, acc);
1131
+ return result;
1132
+ }, face.centerPoint)
1133
+ };
1134
+ };
1135
+
1136
+ // src/subdivide-instructions.ts
1137
+ var subdivideLOrMInstruction = (from, instruction) => {
1138
+ if (instruction.type !== "L" && instruction.type !== "M") {
1139
+ throw new Error("Expected L or M instruction");
1140
+ }
1141
+ const t = 0.5;
1142
+ const q0 = [
1143
+ (1 - t) * from[0] + t * instruction.point[0],
1144
+ (1 - t) * from[1] + t * instruction.point[1],
1145
+ (1 - t) * from[2] + t * instruction.point[2],
1146
+ (1 - t) * from[3] + t * instruction.point[3]
1147
+ ];
1148
+ const curves = [
1149
+ { type: instruction.type, point: q0 },
1150
+ { type: instruction.type, point: instruction.point }
1151
+ ];
1152
+ return curves;
1153
+ };
1154
+ var subdivide3DCInstruction = (from, instruction) => {
1155
+ if (instruction.type !== "C") {
1156
+ throw new Error("Expected C instruction");
1157
+ }
1158
+ const t = 0.5;
1159
+ const q0 = [
1160
+ (1 - t) * from[0] + t * instruction.cp1[0],
1161
+ (1 - t) * from[1] + t * instruction.cp1[1],
1162
+ (1 - t) * from[2] + t * instruction.cp1[2],
1163
+ (1 - t) * from[3] + t * instruction.cp1[3]
1164
+ ];
1165
+ const q1 = [
1166
+ (1 - t) * instruction.cp1[0] + t * instruction.cp2[0],
1167
+ (1 - t) * instruction.cp1[1] + t * instruction.cp2[1],
1168
+ (1 - t) * instruction.cp1[2] + t * instruction.cp2[2],
1169
+ (1 - t) * instruction.cp1[3] + t * instruction.cp2[3]
1170
+ ];
1171
+ const q2 = [
1172
+ (1 - t) * instruction.cp2[0] + t * instruction.point[0],
1173
+ (1 - t) * instruction.cp2[1] + t * instruction.point[1],
1174
+ (1 - t) * instruction.cp2[2] + t * instruction.point[2],
1175
+ (1 - t) * instruction.cp2[3] + t * instruction.point[3]
1176
+ ];
1177
+ const r0 = [
1178
+ (1 - t) * q0[0] + t * q1[0],
1179
+ (1 - t) * q0[1] + t * q1[1],
1180
+ (1 - t) * q0[2] + t * q1[2],
1181
+ (1 - t) * q0[3] + t * q1[3]
1182
+ ];
1183
+ const r1 = [
1184
+ (1 - t) * q1[0] + t * q2[0],
1185
+ (1 - t) * q1[1] + t * q2[1],
1186
+ (1 - t) * q1[2] + t * q2[2],
1187
+ (1 - t) * q1[3] + t * q2[3]
1188
+ ];
1189
+ const s0 = [
1190
+ (1 - t) * r0[0] + t * r1[0],
1191
+ (1 - t) * r0[1] + t * r1[1],
1192
+ (1 - t) * r0[2] + t * r1[2],
1193
+ (1 - t) * r0[3] + t * r1[3]
1194
+ ];
1195
+ const curves = [
1196
+ { type: "C", point: s0, cp1: q0, cp2: r0 },
1197
+ { type: "C", point: instruction.point, cp1: r1, cp2: q2 }
1198
+ ];
1199
+ return curves;
1200
+ };
1201
+ var subdivideQInstruction = (from, instruction) => {
1202
+ if (instruction.type !== "Q") {
1203
+ throw new Error("Expected Q instruction");
1204
+ }
1205
+ const t = 0.5;
1206
+ const q0 = [
1207
+ (1 - t) * from[0] + t * instruction.cp[0],
1208
+ (1 - t) * from[1] + t * instruction.cp[1],
1209
+ (1 - t) * from[2] + t * instruction.cp[2],
1210
+ (1 - t) * from[3] + t * instruction.cp[3]
1211
+ ];
1212
+ const q1 = [
1213
+ (1 - t) * instruction.cp[0] + t * instruction.point[0],
1214
+ (1 - t) * instruction.cp[1] + t * instruction.point[1],
1215
+ (1 - t) * instruction.cp[2] + t * instruction.point[2],
1216
+ (1 - t) * instruction.cp[3] + t * instruction.point[3]
1217
+ ];
1218
+ const r0 = [
1219
+ (1 - t) * q0[0] + t * q1[0],
1220
+ (1 - t) * q0[1] + t * q1[1],
1221
+ (1 - t) * q0[2] + t * q1[2],
1222
+ (1 - t) * q0[3] + t * q1[3]
1223
+ ];
1224
+ const newInstructions = [
1225
+ { type: "Q", point: r0, cp: q0 },
1226
+ { type: "Q", point: instruction.point, cp: q1 }
1227
+ ];
1228
+ return newInstructions;
1229
+ };
1230
+ var subdivideInstruction = (from, instruction) => {
1231
+ if (instruction.type === "C") {
1232
+ return subdivide3DCInstruction(from, instruction);
1233
+ }
1234
+ if (instruction.type === "L" || instruction.type === "M") {
1235
+ return subdivideLOrMInstruction(from, instruction);
1236
+ }
1237
+ if (instruction.type === "Q") {
1238
+ return subdivideQInstruction(from, instruction);
1239
+ }
1240
+ if (instruction.type === "Z") {
1241
+ return [instruction];
1242
+ }
1243
+ throw new Error("Cannot subdivide instruction");
1244
+ };
1245
+ var subdivideInstructions = (instructions) => {
1246
+ const newInstructions = [];
1247
+ instructions.forEach((instruction, i) => {
1248
+ if (instruction.type === "M") {
1249
+ newInstructions.push(instruction);
1250
+ return;
1251
+ }
1252
+ if (instruction.type === "Z") {
1253
+ newInstructions.push(instruction);
1254
+ return;
1255
+ }
1256
+ const previousInstruction = instructions[i - 1];
1257
+ const subdivided = subdivideInstruction(previousInstruction.point, instruction);
1258
+ newInstructions.push(...subdivided);
1259
+ });
1260
+ return newInstructions;
1261
+ };
1262
+
1263
+ // src/extrude-element.ts
1264
+ var inverseInstruction = (instruction, comingFrom) => {
1265
+ if (instruction.type === "M") {
1266
+ return {
1267
+ type: "M",
1268
+ point: comingFrom
1269
+ };
1270
+ }
1271
+ if (instruction.type === "L") {
1272
+ return {
1273
+ type: "L",
1274
+ point: comingFrom
1275
+ };
1276
+ }
1277
+ if (instruction.type === "C") {
1278
+ return {
1279
+ type: "C",
1280
+ point: comingFrom,
1281
+ cp1: instruction.cp2,
1282
+ cp2: instruction.cp1
1283
+ };
1284
+ }
1285
+ if (instruction.type === "Q") {
1286
+ return {
1287
+ type: "Q",
1288
+ point: comingFrom,
1289
+ cp: instruction.cp
1290
+ };
1291
+ }
1292
+ if (instruction.type === "Z") {
1293
+ return {
1294
+ type: "L",
1295
+ point: comingFrom
1296
+ };
1297
+ }
1298
+ throw new Error("Unknown instruction type");
1299
+ };
1300
+ var extrudeElement = ({
1301
+ depth,
1302
+ sideColor,
1303
+ points,
1304
+ crispEdges
1305
+ }) => {
1306
+ const threeD = turnInto3D(points);
1307
+ const instructions = {
1308
+ centerPoint: [0, 0, 0, 1],
1309
+ points: subdivideInstructions(subdivideInstructions(subdivideInstructions(threeD))),
1310
+ color: "black",
1311
+ crispEdges
1312
+ };
1313
+ const unscaledBackFace = transformFace(instructions, [translateZ(depth / 2)]);
1314
+ const inbetween = unscaledBackFace.points.map((t, i) => {
1315
+ const nextInstruction = i === unscaledBackFace.points.length - 1 ? unscaledBackFace.points[0] : unscaledBackFace.points[i + 1];
1316
+ const currentPoint = t.point;
1317
+ const nextPoint = nextInstruction.point;
1318
+ const movingOver = [
1319
+ nextPoint[0],
1320
+ nextPoint[1],
1321
+ nextPoint[2] - depth,
1322
+ nextPoint[3]
1323
+ ];
1324
+ const translatedInstruction = translateSvgInstruction(inverseInstruction(nextInstruction, currentPoint), 0, 0, -depth);
1325
+ const newInstructions = [
1326
+ {
1327
+ type: "M",
1328
+ point: currentPoint
1329
+ },
1330
+ nextInstruction,
1331
+ nextInstruction.type === "Z" ? {
1332
+ type: "M",
1333
+ point: nextInstruction.point
1334
+ } : null,
1335
+ {
1336
+ type: "L",
1337
+ point: movingOver
1338
+ },
1339
+ translatedInstruction,
1340
+ {
1341
+ type: "L",
1342
+ point: currentPoint
1343
+ }
1344
+ ].filter(truthy);
1345
+ return {
1346
+ points: newInstructions,
1347
+ color: sideColor,
1348
+ centerPoint: [0, 0, 0, 1],
1349
+ crispEdges: true
1350
+ };
1351
+ });
1352
+ return inbetween;
1353
+ };
1354
+ var extrudeAndTransformElement = (options) => {
1355
+ const inbetween = extrudeElement(options);
1356
+ return inbetween.map((face) => ({
1357
+ ...transformFace(face, [options.transformations])
1358
+ }));
1359
+ };
1360
+ export {
1361
+ translateZ,
1362
+ translateY,
1363
+ translateX,
1364
+ transformPath,
1365
+ threeDIntoSvgPath,
1366
+ scaled,
1367
+ scaleY,
1368
+ scaleX,
1369
+ rotateZ,
1370
+ rotateY,
1371
+ rotateX,
1372
+ reduceMatrices,
1373
+ makeMatrix3dTransform,
1374
+ interpolateMatrix4d,
1375
+ extrudeElement,
1376
+ extrudeAndTransformElement,
1377
+ aroundCenterPoint
1378
+ };