circuit-to-canvas 0.0.34 → 0.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +102 -75
- package/lib/drawer/shapes/arrow.ts +3 -6
- package/lib/drawer/shapes/dimension-line.ts +115 -58
- package/package.json +1 -1
- package/tests/elements/__snapshots__/pcb-fabrication-note-dimension.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-dimension-angled-and-vertical.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-dimension-basic.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-dimension-vertical.snap.png +0 -0
- package/tests/elements/__snapshots__/pcb-note-dimension-with-offset.snap.png +0 -0
- package/tests/shapes/__snapshots__/dimension-line.snap.png +0 -0
package/dist/index.js
CHANGED
|
@@ -1620,27 +1620,6 @@ function drawPcbNoteText(params) {
|
|
|
1620
1620
|
|
|
1621
1621
|
// lib/drawer/shapes/dimension-line.ts
|
|
1622
1622
|
import { applyToPoint as applyToPoint13 } from "transformation-matrix";
|
|
1623
|
-
|
|
1624
|
-
// lib/drawer/shapes/arrow.ts
|
|
1625
|
-
function drawArrow(params) {
|
|
1626
|
-
const { ctx, x, y, angle, arrowSize, color, strokeWidth } = params;
|
|
1627
|
-
ctx.save();
|
|
1628
|
-
ctx.translate(x, y);
|
|
1629
|
-
ctx.rotate(angle);
|
|
1630
|
-
ctx.beginPath();
|
|
1631
|
-
ctx.moveTo(0, 0);
|
|
1632
|
-
ctx.lineTo(-arrowSize, -arrowSize / 2);
|
|
1633
|
-
ctx.moveTo(0, 0);
|
|
1634
|
-
ctx.lineTo(-arrowSize, arrowSize / 2);
|
|
1635
|
-
ctx.lineWidth = strokeWidth;
|
|
1636
|
-
ctx.strokeStyle = color;
|
|
1637
|
-
ctx.lineCap = "round";
|
|
1638
|
-
ctx.lineJoin = "round";
|
|
1639
|
-
ctx.stroke();
|
|
1640
|
-
ctx.restore();
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
|
-
// lib/drawer/shapes/dimension-line.ts
|
|
1644
1623
|
var TEXT_OFFSET_MULTIPLIER = 1.5;
|
|
1645
1624
|
var CHARACTER_WIDTH_MULTIPLIER = 0.6;
|
|
1646
1625
|
var TEXT_INTERSECTION_PADDING_MULTIPLIER = 0.3;
|
|
@@ -1673,71 +1652,103 @@ function drawDimensionLine(params) {
|
|
|
1673
1652
|
};
|
|
1674
1653
|
const fromOffset = { x: from.x + offsetVector.x, y: from.y + offsetVector.y };
|
|
1675
1654
|
const toOffset = { x: to.x + offsetVector.x, y: to.y + offsetVector.y };
|
|
1676
|
-
const fromBase =
|
|
1677
|
-
|
|
1655
|
+
const fromBase = {
|
|
1656
|
+
x: fromOffset.x + direction.x * arrowSize,
|
|
1657
|
+
y: fromOffset.y + direction.y * arrowSize
|
|
1658
|
+
};
|
|
1659
|
+
const toBase = {
|
|
1660
|
+
x: toOffset.x - direction.x * arrowSize,
|
|
1661
|
+
y: toOffset.y - direction.y * arrowSize
|
|
1662
|
+
};
|
|
1678
1663
|
const scaleValue = Math.abs(realToCanvasMat.a);
|
|
1679
1664
|
const strokeWidth = manualStrokeWidth ?? arrowSize / 5;
|
|
1680
1665
|
const lineColor = color || "rgba(255,255,255,0.5)";
|
|
1681
1666
|
const extensionDirection = hasOffsetDirection && (Math.abs(normalizedOffsetDirection.x) > Number.EPSILON || Math.abs(normalizedOffsetDirection.y) > Number.EPSILON) ? normalizedOffsetDirection : perpendicular;
|
|
1682
1667
|
const extensionLength = offsetMagnitude + 0.5;
|
|
1683
|
-
const
|
|
1668
|
+
const allPoints = [];
|
|
1669
|
+
const getExtensionPoints = (anchor) => {
|
|
1684
1670
|
const endPoint = {
|
|
1685
1671
|
x: anchor.x + extensionDirection.x * extensionLength,
|
|
1686
1672
|
y: anchor.y + extensionDirection.y * extensionLength
|
|
1687
1673
|
};
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1674
|
+
const halfWidth2 = strokeWidth / 2;
|
|
1675
|
+
const extPerpendicular = {
|
|
1676
|
+
x: -extensionDirection.y,
|
|
1677
|
+
y: extensionDirection.x
|
|
1678
|
+
};
|
|
1679
|
+
return [
|
|
1680
|
+
{
|
|
1681
|
+
x: anchor.x + extPerpendicular.x * halfWidth2,
|
|
1682
|
+
y: anchor.y + extPerpendicular.y * halfWidth2
|
|
1683
|
+
},
|
|
1684
|
+
{
|
|
1685
|
+
x: anchor.x - extPerpendicular.x * halfWidth2,
|
|
1686
|
+
y: anchor.y - extPerpendicular.y * halfWidth2
|
|
1687
|
+
},
|
|
1688
|
+
{
|
|
1689
|
+
x: endPoint.x - extPerpendicular.x * halfWidth2,
|
|
1690
|
+
y: endPoint.y - extPerpendicular.y * halfWidth2
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
x: endPoint.x + extPerpendicular.x * halfWidth2,
|
|
1694
|
+
y: endPoint.y + extPerpendicular.y * halfWidth2
|
|
1695
|
+
}
|
|
1696
|
+
];
|
|
1696
1697
|
};
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1698
|
+
const ext1 = getExtensionPoints(from);
|
|
1699
|
+
allPoints.push(...ext1, ext1[0]);
|
|
1700
|
+
const ext2 = getExtensionPoints(to);
|
|
1701
|
+
allPoints.push(...ext2, ext2[0]);
|
|
1702
|
+
const halfWidth = strokeWidth / 2;
|
|
1703
|
+
const mainLine = [
|
|
1704
|
+
{
|
|
1705
|
+
x: fromBase.x + perpendicular.x * halfWidth,
|
|
1706
|
+
y: fromBase.y + perpendicular.y * halfWidth
|
|
1707
|
+
},
|
|
1708
|
+
{
|
|
1709
|
+
x: fromBase.x - perpendicular.x * halfWidth,
|
|
1710
|
+
y: fromBase.y - perpendicular.y * halfWidth
|
|
1711
|
+
},
|
|
1712
|
+
{
|
|
1713
|
+
x: toBase.x - perpendicular.x * halfWidth,
|
|
1714
|
+
y: toBase.y - perpendicular.y * halfWidth
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
x: toBase.x + perpendicular.x * halfWidth,
|
|
1718
|
+
y: toBase.y + perpendicular.y * halfWidth
|
|
1719
|
+
}
|
|
1720
|
+
];
|
|
1721
|
+
allPoints.push(...mainLine, mainLine[0]);
|
|
1722
|
+
const arrow1 = [
|
|
1723
|
+
fromOffset,
|
|
1724
|
+
{
|
|
1725
|
+
x: fromOffset.x + direction.x * arrowSize + perpendicular.x * (arrowSize / 2),
|
|
1726
|
+
y: fromOffset.y + direction.y * arrowSize + perpendicular.y * (arrowSize / 2)
|
|
1727
|
+
},
|
|
1728
|
+
{
|
|
1729
|
+
x: fromOffset.x + direction.x * arrowSize - perpendicular.x * (arrowSize / 2),
|
|
1730
|
+
y: fromOffset.y + direction.y * arrowSize - perpendicular.y * (arrowSize / 2)
|
|
1731
|
+
}
|
|
1732
|
+
];
|
|
1733
|
+
allPoints.push(...arrow1, arrow1[0]);
|
|
1734
|
+
const arrow2 = [
|
|
1735
|
+
toOffset,
|
|
1736
|
+
{
|
|
1737
|
+
x: toOffset.x - direction.x * arrowSize + perpendicular.x * (arrowSize / 2),
|
|
1738
|
+
y: toOffset.y - direction.y * arrowSize + perpendicular.y * (arrowSize / 2)
|
|
1739
|
+
},
|
|
1740
|
+
{
|
|
1741
|
+
x: toOffset.x - direction.x * arrowSize - perpendicular.x * (arrowSize / 2),
|
|
1742
|
+
y: toOffset.y - direction.y * arrowSize - perpendicular.y * (arrowSize / 2)
|
|
1743
|
+
}
|
|
1744
|
+
];
|
|
1745
|
+
allPoints.push(...arrow2, arrow2[0]);
|
|
1746
|
+
drawPolygon({
|
|
1700
1747
|
ctx,
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
strokeWidth,
|
|
1704
|
-
stroke: lineColor,
|
|
1748
|
+
points: allPoints,
|
|
1749
|
+
fill: lineColor,
|
|
1705
1750
|
realToCanvasMat
|
|
1706
1751
|
});
|
|
1707
|
-
const [canvasFromX, canvasFromY] = applyToPoint13(realToCanvasMat, [
|
|
1708
|
-
fromOffset.x,
|
|
1709
|
-
fromOffset.y
|
|
1710
|
-
]);
|
|
1711
|
-
const [canvasToX, canvasToY] = applyToPoint13(realToCanvasMat, [
|
|
1712
|
-
toOffset.x,
|
|
1713
|
-
toOffset.y
|
|
1714
|
-
]);
|
|
1715
|
-
const [canvasToDirX, canvasToDirY] = applyToPoint13(realToCanvasMat, [
|
|
1716
|
-
toOffset.x + direction.x,
|
|
1717
|
-
toOffset.y + direction.y
|
|
1718
|
-
]);
|
|
1719
|
-
const canvasLineAngle = Math.atan2(
|
|
1720
|
-
canvasToDirY - canvasToY,
|
|
1721
|
-
canvasToDirX - canvasToX
|
|
1722
|
-
);
|
|
1723
|
-
drawArrow({
|
|
1724
|
-
ctx,
|
|
1725
|
-
x: canvasFromX,
|
|
1726
|
-
y: canvasFromY,
|
|
1727
|
-
angle: canvasLineAngle + Math.PI,
|
|
1728
|
-
arrowSize: arrowSize * scaleValue,
|
|
1729
|
-
color: lineColor,
|
|
1730
|
-
strokeWidth: strokeWidth * scaleValue
|
|
1731
|
-
});
|
|
1732
|
-
drawArrow({
|
|
1733
|
-
ctx,
|
|
1734
|
-
x: canvasToX,
|
|
1735
|
-
y: canvasToY,
|
|
1736
|
-
angle: canvasLineAngle,
|
|
1737
|
-
arrowSize: arrowSize * scaleValue,
|
|
1738
|
-
color: lineColor,
|
|
1739
|
-
strokeWidth: strokeWidth * scaleValue
|
|
1740
|
-
});
|
|
1741
1752
|
if (text) {
|
|
1742
1753
|
const midPoint = {
|
|
1743
1754
|
x: (from.x + to.x) / 2 + offsetVector.x,
|
|
@@ -1767,9 +1778,9 @@ function drawDimensionLine(params) {
|
|
|
1767
1778
|
const rotationRad = textRotation * Math.PI / 180;
|
|
1768
1779
|
const sinRot = Math.abs(Math.sin(rotationRad));
|
|
1769
1780
|
const cosRot = Math.abs(Math.cos(rotationRad));
|
|
1770
|
-
const
|
|
1781
|
+
const halfWidth2 = textWidth / 2;
|
|
1771
1782
|
const halfHeight = textHeight / 2;
|
|
1772
|
-
const maxExtension =
|
|
1783
|
+
const maxExtension = halfWidth2 * sinRot + halfHeight * cosRot;
|
|
1773
1784
|
additionalOffset = maxExtension + fontSize * TEXT_INTERSECTION_PADDING_MULTIPLIER;
|
|
1774
1785
|
}
|
|
1775
1786
|
const textOffset = arrowSize * TEXT_OFFSET_MULTIPLIER + additionalOffset;
|
|
@@ -2205,6 +2216,22 @@ var CircuitToCanvasDrawer = class {
|
|
|
2205
2216
|
}
|
|
2206
2217
|
}
|
|
2207
2218
|
};
|
|
2219
|
+
|
|
2220
|
+
// lib/drawer/shapes/arrow.ts
|
|
2221
|
+
function drawArrow(params) {
|
|
2222
|
+
const { ctx, x, y, angle, arrowSize, color, strokeWidth } = params;
|
|
2223
|
+
ctx.save();
|
|
2224
|
+
ctx.translate(x, y);
|
|
2225
|
+
ctx.rotate(angle);
|
|
2226
|
+
ctx.beginPath();
|
|
2227
|
+
ctx.moveTo(0, 0);
|
|
2228
|
+
ctx.lineTo(-arrowSize, -arrowSize / 2);
|
|
2229
|
+
ctx.lineTo(-arrowSize, arrowSize / 2);
|
|
2230
|
+
ctx.closePath();
|
|
2231
|
+
ctx.fillStyle = color;
|
|
2232
|
+
ctx.fill();
|
|
2233
|
+
ctx.restore();
|
|
2234
|
+
}
|
|
2208
2235
|
export {
|
|
2209
2236
|
CircuitToCanvasDrawer,
|
|
2210
2237
|
DEFAULT_PCB_COLOR_MAP,
|
|
@@ -23,14 +23,11 @@ export function drawArrow(params: DrawArrowParams): void {
|
|
|
23
23
|
ctx.beginPath()
|
|
24
24
|
ctx.moveTo(0, 0)
|
|
25
25
|
ctx.lineTo(-arrowSize, -arrowSize / 2)
|
|
26
|
-
ctx.moveTo(0, 0)
|
|
27
26
|
ctx.lineTo(-arrowSize, arrowSize / 2)
|
|
27
|
+
ctx.closePath()
|
|
28
28
|
|
|
29
|
-
ctx.
|
|
30
|
-
ctx.
|
|
31
|
-
ctx.lineCap = "round"
|
|
32
|
-
ctx.lineJoin = "round"
|
|
33
|
-
ctx.stroke()
|
|
29
|
+
ctx.fillStyle = color
|
|
30
|
+
ctx.fill()
|
|
34
31
|
|
|
35
32
|
ctx.restore()
|
|
36
33
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { Matrix } from "transformation-matrix"
|
|
2
2
|
import { applyToPoint } from "transformation-matrix"
|
|
3
3
|
import type { CanvasContext } from "../types"
|
|
4
|
-
import {
|
|
4
|
+
import { drawPolygon } from "./polygon"
|
|
5
5
|
import { drawText } from "./text"
|
|
6
|
-
import { drawArrow } from "./arrow"
|
|
7
6
|
|
|
8
7
|
export interface DrawDimensionLineParams {
|
|
9
8
|
ctx: CanvasContext
|
|
@@ -67,8 +66,14 @@ export function drawDimensionLine(params: DrawDimensionLineParams): void {
|
|
|
67
66
|
const fromOffset = { x: from.x + offsetVector.x, y: from.y + offsetVector.y }
|
|
68
67
|
const toOffset = { x: to.x + offsetVector.x, y: to.y + offsetVector.y }
|
|
69
68
|
|
|
70
|
-
const fromBase =
|
|
71
|
-
|
|
69
|
+
const fromBase = {
|
|
70
|
+
x: fromOffset.x + direction.x * arrowSize,
|
|
71
|
+
y: fromOffset.y + direction.y * arrowSize,
|
|
72
|
+
}
|
|
73
|
+
const toBase = {
|
|
74
|
+
x: toOffset.x - direction.x * arrowSize,
|
|
75
|
+
y: toOffset.y - direction.y * arrowSize,
|
|
76
|
+
}
|
|
72
77
|
|
|
73
78
|
const scaleValue = Math.abs(realToCanvasMat.a)
|
|
74
79
|
const strokeWidth = manualStrokeWidth ?? arrowSize / 5
|
|
@@ -84,71 +89,123 @@ export function drawDimensionLine(params: DrawDimensionLineParams): void {
|
|
|
84
89
|
|
|
85
90
|
const extensionLength = offsetMagnitude + 0.5
|
|
86
91
|
|
|
87
|
-
const
|
|
92
|
+
const allPoints: Array<{ x: number; y: number }> = []
|
|
93
|
+
|
|
94
|
+
const getExtensionPoints = (anchor: { x: number; y: number }) => {
|
|
88
95
|
const endPoint = {
|
|
89
96
|
x: anchor.x + extensionDirection.x * extensionLength,
|
|
90
97
|
y: anchor.y + extensionDirection.y * extensionLength,
|
|
91
98
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
const halfWidth = strokeWidth / 2
|
|
100
|
+
const extPerpendicular = {
|
|
101
|
+
x: -extensionDirection.y,
|
|
102
|
+
y: extensionDirection.x,
|
|
103
|
+
}
|
|
104
|
+
return [
|
|
105
|
+
{
|
|
106
|
+
x: anchor.x + extPerpendicular.x * halfWidth,
|
|
107
|
+
y: anchor.y + extPerpendicular.y * halfWidth,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
x: anchor.x - extPerpendicular.x * halfWidth,
|
|
111
|
+
y: anchor.y - extPerpendicular.y * halfWidth,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
x: endPoint.x - extPerpendicular.x * halfWidth,
|
|
115
|
+
y: endPoint.y - extPerpendicular.y * halfWidth,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
x: endPoint.x + extPerpendicular.x * halfWidth,
|
|
119
|
+
y: endPoint.y + extPerpendicular.y * halfWidth,
|
|
120
|
+
},
|
|
121
|
+
]
|
|
100
122
|
}
|
|
101
123
|
|
|
102
|
-
|
|
103
|
-
|
|
124
|
+
// Extension lines (ticks)
|
|
125
|
+
const ext1 = getExtensionPoints(from)
|
|
126
|
+
allPoints.push(...ext1, ext1[0]!)
|
|
127
|
+
|
|
128
|
+
const ext2 = getExtensionPoints(to)
|
|
129
|
+
allPoints.push(...ext2, ext2[0]!)
|
|
104
130
|
|
|
105
131
|
// Main dimension line
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
132
|
+
const halfWidth = strokeWidth / 2
|
|
133
|
+
const mainLine = [
|
|
134
|
+
{
|
|
135
|
+
x: fromBase.x + perpendicular.x * halfWidth,
|
|
136
|
+
y: fromBase.y + perpendicular.y * halfWidth,
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
x: fromBase.x - perpendicular.x * halfWidth,
|
|
140
|
+
y: fromBase.y - perpendicular.y * halfWidth,
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
x: toBase.x - perpendicular.x * halfWidth,
|
|
144
|
+
y: toBase.y - perpendicular.y * halfWidth,
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
x: toBase.x + perpendicular.x * halfWidth,
|
|
148
|
+
y: toBase.y + perpendicular.y * halfWidth,
|
|
149
|
+
},
|
|
150
|
+
]
|
|
151
|
+
allPoints.push(...mainLine, mainLine[0]!)
|
|
114
152
|
|
|
115
|
-
// Arrows
|
|
116
|
-
const
|
|
117
|
-
fromOffset
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
color: lineColor,
|
|
141
|
-
strokeWidth: strokeWidth * scaleValue,
|
|
142
|
-
})
|
|
153
|
+
// Arrows
|
|
154
|
+
const arrow1 = [
|
|
155
|
+
fromOffset,
|
|
156
|
+
{
|
|
157
|
+
x:
|
|
158
|
+
fromOffset.x +
|
|
159
|
+
direction.x * arrowSize +
|
|
160
|
+
perpendicular.x * (arrowSize / 2),
|
|
161
|
+
y:
|
|
162
|
+
fromOffset.y +
|
|
163
|
+
direction.y * arrowSize +
|
|
164
|
+
perpendicular.y * (arrowSize / 2),
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
x:
|
|
168
|
+
fromOffset.x +
|
|
169
|
+
direction.x * arrowSize -
|
|
170
|
+
perpendicular.x * (arrowSize / 2),
|
|
171
|
+
y:
|
|
172
|
+
fromOffset.y +
|
|
173
|
+
direction.y * arrowSize -
|
|
174
|
+
perpendicular.y * (arrowSize / 2),
|
|
175
|
+
},
|
|
176
|
+
]
|
|
177
|
+
allPoints.push(...arrow1, arrow1[0]!)
|
|
143
178
|
|
|
144
|
-
|
|
179
|
+
const arrow2 = [
|
|
180
|
+
toOffset,
|
|
181
|
+
{
|
|
182
|
+
x:
|
|
183
|
+
toOffset.x -
|
|
184
|
+
direction.x * arrowSize +
|
|
185
|
+
perpendicular.x * (arrowSize / 2),
|
|
186
|
+
y:
|
|
187
|
+
toOffset.y -
|
|
188
|
+
direction.y * arrowSize +
|
|
189
|
+
perpendicular.y * (arrowSize / 2),
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
x:
|
|
193
|
+
toOffset.x -
|
|
194
|
+
direction.x * arrowSize -
|
|
195
|
+
perpendicular.x * (arrowSize / 2),
|
|
196
|
+
y:
|
|
197
|
+
toOffset.y -
|
|
198
|
+
direction.y * arrowSize -
|
|
199
|
+
perpendicular.y * (arrowSize / 2),
|
|
200
|
+
},
|
|
201
|
+
]
|
|
202
|
+
allPoints.push(...arrow2, arrow2[0]!)
|
|
203
|
+
|
|
204
|
+
drawPolygon({
|
|
145
205
|
ctx,
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
arrowSize: arrowSize * scaleValue,
|
|
150
|
-
color: lineColor,
|
|
151
|
-
strokeWidth: strokeWidth * scaleValue,
|
|
206
|
+
points: allPoints,
|
|
207
|
+
fill: lineColor,
|
|
208
|
+
realToCanvasMat,
|
|
152
209
|
})
|
|
153
210
|
|
|
154
211
|
// Text
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|