try
This commit is contained in:
parent
adf3c651e2
commit
d594af3f4a
5 changed files with 242 additions and 236 deletions
|
|
@ -14,7 +14,7 @@ import (
|
||||||
const (
|
const (
|
||||||
MIN_RADIUS = 200
|
MIN_RADIUS = 200
|
||||||
PADDING = 20
|
PADDING = 20
|
||||||
MIN_SEGMENT_LEN = 10
|
MIN_SEGMENT_LEN = 10.0 // Changed to float64
|
||||||
ARC_STEPS = 100
|
ARC_STEPS = 100
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -41,22 +41,12 @@ func Layout(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) e
|
||||||
|
|
||||||
func calculateRadius(objects []*d2graph.Object) float64 {
|
func calculateRadius(objects []*d2graph.Object) float64 {
|
||||||
numObjects := float64(len(objects))
|
numObjects := float64(len(objects))
|
||||||
if numObjects == 0 {
|
maxSize := 0.0
|
||||||
return MIN_RADIUS
|
|
||||||
}
|
|
||||||
|
|
||||||
maxDiagonal := 0.0
|
|
||||||
for _, obj := range objects {
|
for _, obj := range objects {
|
||||||
// Calculate the diagonal of the object's bounding box
|
size := math.Max(obj.Box.Width, obj.Box.Height)
|
||||||
diagonal := math.Sqrt(obj.Box.Width*obj.Box.Width + obj.Box.Height*obj.Box.Height)
|
maxSize = math.Max(maxSize, size)
|
||||||
if diagonal > maxDiagonal {
|
|
||||||
maxDiagonal = diagonal
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
minRadius := (maxSize/2.0 + PADDING) / math.Sin(math.Pi/numObjects)
|
||||||
// Required chord length: sum of two radii (maxDiagonal/2) + padding
|
|
||||||
requiredChordLength := maxDiagonal + PADDING
|
|
||||||
minRadius := requiredChordLength / (2 * math.Sin(math.Pi/numObjects))
|
|
||||||
return math.Max(minRadius, MIN_RADIUS)
|
return math.Max(minRadius, MIN_RADIUS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,14 +73,27 @@ func createCircularArc(edge *d2graph.Edge) {
|
||||||
srcCenter := edge.Src.Center()
|
srcCenter := edge.Src.Center()
|
||||||
dstCenter := edge.Dst.Center()
|
dstCenter := edge.Dst.Center()
|
||||||
|
|
||||||
|
// Calculate the angle of each object from the origin (0,0)
|
||||||
srcAngle := math.Atan2(srcCenter.Y, srcCenter.X)
|
srcAngle := math.Atan2(srcCenter.Y, srcCenter.X)
|
||||||
dstAngle := math.Atan2(dstCenter.Y, dstCenter.X)
|
dstAngle := math.Atan2(dstCenter.Y, dstCenter.X)
|
||||||
|
|
||||||
|
// Determine the shortest arc direction
|
||||||
if dstAngle < srcAngle {
|
if dstAngle < srcAngle {
|
||||||
dstAngle += 2 * math.Pi
|
if srcAngle - dstAngle > math.Pi {
|
||||||
|
dstAngle += 2 * math.Pi
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if dstAngle - srcAngle > math.Pi {
|
||||||
|
srcAngle += 2 * math.Pi
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
arcRadius := math.Hypot(srcCenter.X, srcCenter.Y)
|
// Use the average radius for a smooth circular arc
|
||||||
|
srcRadius := math.Hypot(srcCenter.X, srcCenter.Y)
|
||||||
|
dstRadius := math.Hypot(dstCenter.X, dstCenter.Y)
|
||||||
|
arcRadius := (srcRadius + dstRadius) / 2
|
||||||
|
|
||||||
|
// Create a perfectly circular arc with more points for smoothness
|
||||||
path := make([]*geo.Point, 0, ARC_STEPS+1)
|
path := make([]*geo.Point, 0, ARC_STEPS+1)
|
||||||
for i := 0; i <= ARC_STEPS; i++ {
|
for i := 0; i <= ARC_STEPS; i++ {
|
||||||
t := float64(i) / float64(ARC_STEPS)
|
t := float64(i) / float64(ARC_STEPS)
|
||||||
|
|
@ -99,27 +102,31 @@ func createCircularArc(edge *d2graph.Edge) {
|
||||||
y := arcRadius * math.Sin(angle)
|
y := arcRadius * math.Sin(angle)
|
||||||
path = append(path, geo.NewPoint(x, y))
|
path = append(path, geo.NewPoint(x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure the path starts and ends at the centers
|
||||||
path[0] = srcCenter
|
path[0] = srcCenter
|
||||||
path[len(path)-1] = dstCenter
|
path[len(path)-1] = dstCenter
|
||||||
|
|
||||||
// Clamp endpoints to the boundaries of the source and destination boxes.
|
// Find precise intersection points with object boundaries
|
||||||
_, newSrc := clampPointOutsideBox(edge.Src.Box, path, 0)
|
_, newSrc := clampPointOutsideBox(edge.Src.Box, path, 0)
|
||||||
_, newDst := clampPointOutsideBoxReverse(edge.Dst.Box, path, len(path)-1)
|
_, newDst := clampPointOutsideBoxReverse(edge.Dst.Box, path, len(path)-1)
|
||||||
path[0] = newSrc
|
path[0] = newSrc
|
||||||
path[len(path)-1] = newDst
|
path[len(path)-1] = newDst
|
||||||
|
|
||||||
// Trim redundant path points that fall inside node boundaries.
|
// Trim points that are inside the objects' boxes
|
||||||
path = trimPathPoints(path, edge.Src.Box)
|
path = trimPathPoints(path, edge.Src.Box)
|
||||||
path = trimPathPoints(path, edge.Dst.Box)
|
path = trimPathPoints(path, edge.Dst.Box)
|
||||||
|
|
||||||
edge.Route = path
|
edge.Route = path
|
||||||
edge.IsCurve = true
|
edge.IsCurve = true
|
||||||
|
|
||||||
|
// Adjust the final segment for proper arrow rendering
|
||||||
if len(edge.Route) >= 2 {
|
if len(edge.Route) >= 2 {
|
||||||
lastIndex := len(edge.Route) - 1
|
lastIndex := len(edge.Route) - 1
|
||||||
lastPoint := edge.Route[lastIndex]
|
lastPoint := edge.Route[lastIndex]
|
||||||
secondLastPoint := edge.Route[lastIndex-1]
|
secondLastPoint := edge.Route[lastIndex-1]
|
||||||
|
|
||||||
|
// Calculate tangent at the intersection point (perpendicular to radius)
|
||||||
tangentX := -lastPoint.Y
|
tangentX := -lastPoint.Y
|
||||||
tangentY := lastPoint.X
|
tangentY := lastPoint.X
|
||||||
mag := math.Hypot(tangentX, tangentY)
|
mag := math.Hypot(tangentX, tangentY)
|
||||||
|
|
@ -127,8 +134,8 @@ func createCircularArc(edge *d2graph.Edge) {
|
||||||
tangentX /= mag
|
tangentX /= mag
|
||||||
tangentY /= mag
|
tangentY /= mag
|
||||||
}
|
}
|
||||||
const MIN_SEGMENT_LEN = 4.159
|
|
||||||
|
|
||||||
|
// Check if final segment needs adjustment
|
||||||
dx := lastPoint.X - secondLastPoint.X
|
dx := lastPoint.X - secondLastPoint.X
|
||||||
dy := lastPoint.Y - secondLastPoint.Y
|
dy := lastPoint.Y - secondLastPoint.Y
|
||||||
segLength := math.Hypot(dx, dy)
|
segLength := math.Hypot(dx, dy)
|
||||||
|
|
@ -136,9 +143,8 @@ func createCircularArc(edge *d2graph.Edge) {
|
||||||
currentDirX := dx / segLength
|
currentDirX := dx / segLength
|
||||||
currentDirY := dy / segLength
|
currentDirY := dy / segLength
|
||||||
|
|
||||||
// Check if we need to adjust the direction
|
// If segment is too short or not aligned with the tangent
|
||||||
if segLength < MIN_SEGMENT_LEN || (currentDirX*tangentX+currentDirY*tangentY) < 0.999 {
|
if segLength < MIN_SEGMENT_LEN || (currentDirX*tangentX+currentDirY*tangentY) < 0.99 {
|
||||||
// Create new point along tangent direction
|
|
||||||
adjustLength := MIN_SEGMENT_LEN // Now float64
|
adjustLength := MIN_SEGMENT_LEN // Now float64
|
||||||
if segLength >= MIN_SEGMENT_LEN {
|
if segLength >= MIN_SEGMENT_LEN {
|
||||||
adjustLength = segLength // Both are float64 now
|
adjustLength = segLength // Both are float64 now
|
||||||
|
|
|
||||||
60
e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json
generated
vendored
60
e2etests/testdata/txtar/cycle-diagram/dagre/board.exp.json
generated
vendored
|
|
@ -1408,8 +1408,8 @@
|
||||||
"y": -37.47600173950195
|
"y": -37.47600173950195
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 196.5659942626953,
|
"x": 195.6020050048828,
|
||||||
"y": -37.10100173950195
|
"y": -42.86199951171875
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 197.2519989013672,
|
"x": 197.2519989013672,
|
||||||
|
|
@ -1772,8 +1772,8 @@
|
||||||
"y": 197.53700256347656
|
"y": 197.53700256347656
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 30.621999740600586,
|
"x": 36.4109992980957,
|
||||||
"y": 197.6790008544922
|
"y": 196.90499877929688
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 26.5,
|
"x": 26.5,
|
||||||
|
|
@ -2136,8 +2136,8 @@
|
||||||
"y": 37.47600173950195
|
"y": 37.47600173950195
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": -196.5659942626953,
|
"x": -195.6020050048828,
|
||||||
"y": 37.10100173950195
|
"y": 42.86199951171875
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": -197.2519989013672,
|
"x": -197.2519989013672,
|
||||||
|
|
@ -2516,8 +2516,8 @@
|
||||||
"y": 111.8030014038086
|
"y": 111.8030014038086
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 702.8259887695312,
|
"x": 704.7830200195312,
|
||||||
"y": 113.08100128173828
|
"y": 107.5770034790039
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 701.4329833984375,
|
"x": 701.4329833984375,
|
||||||
|
|
@ -2880,8 +2880,8 @@
|
||||||
"y": 186.90899658203125
|
"y": 186.90899658203125
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 366.4079895019531,
|
"x": 370.2919921875,
|
||||||
"y": 186.1060028076172
|
"y": 190.46800231933594
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 363.6419982910156,
|
"x": 363.6419982910156,
|
||||||
|
|
@ -3284,8 +3284,8 @@
|
||||||
"y": 196.45700073242188
|
"y": 196.45700073242188
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1003.2860107421875,
|
"x": 1008.4110107421875,
|
||||||
"y": 197.53700256347656
|
"y": 196.89300537109375
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 998.5,
|
"x": 998.5,
|
||||||
|
|
@ -3596,8 +3596,8 @@
|
||||||
"y": -135.375
|
"y": -135.375
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1231.5989990234375,
|
"x": 1227.7139892578125,
|
||||||
"y": -136.1060028076172
|
"y": -140.46800231933594
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1234.364990234375,
|
"x": 1234.364990234375,
|
||||||
|
|
@ -3896,8 +3896,8 @@
|
||||||
"y": 63.79100036621094
|
"y": 63.79100036621094
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1274.833984375,
|
"x": 1276.7900390625,
|
||||||
"y": 63.08100128173828
|
"y": 57.57699966430664
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1273.43994140625,
|
"x": 1273.43994140625,
|
||||||
|
|
@ -4208,8 +4208,8 @@
|
||||||
"y": 197.85400390625
|
"y": 197.85400390625
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1116.1199951171875,
|
"x": 1121.907958984375,
|
||||||
"y": 197.6060028076172
|
"y": 196.8179931640625
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1112,
|
"x": 1112,
|
||||||
|
|
@ -4520,8 +4520,8 @@
|
||||||
"y": 135.375
|
"y": 135.375
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 938.4000244140625,
|
"x": 942.2849731445312,
|
||||||
"y": 136.1060028076172
|
"y": 140.46800231933594
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 935.6339721679688,
|
"x": 935.6339721679688,
|
||||||
|
|
@ -4820,8 +4820,8 @@
|
||||||
"y": -63.79100036621094
|
"y": -63.79100036621094
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 895.1649780273438,
|
"x": 893.208984375,
|
||||||
"y": -63.08100128173828
|
"y": -57.57699966430664
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 896.5590209960938,
|
"x": 896.5590209960938,
|
||||||
|
|
@ -5160,8 +5160,8 @@
|
||||||
"y": -78.54499816894531
|
"y": -78.54499816894531
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1718.126953125,
|
"x": 1715.3590087890625,
|
||||||
"y": -78.46499633789062
|
"y": -83.60800170898438
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1720.0989990234375,
|
"x": 1720.0989990234375,
|
||||||
|
|
@ -5492,8 +5492,8 @@
|
||||||
"y": 156.90899658203125
|
"y": 156.90899658203125
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1690.9420166015625,
|
"x": 1694.9930419921875,
|
||||||
"y": 155.73899841308594
|
"y": 151.53199768066406
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1688.0570068359375,
|
"x": 1688.0570068359375,
|
||||||
|
|
@ -5832,8 +5832,8 @@
|
||||||
"y": 199.88099670410156
|
"y": 199.88099670410156
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1457.1510009765625,
|
"x": 1462.3590087890625,
|
||||||
"y": 200.20199584960938
|
"y": 202.8470001220703
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1453.4420166015625,
|
"x": 1453.4420166015625,
|
||||||
|
|
@ -6160,8 +6160,8 @@
|
||||||
"y": -5.065999984741211
|
"y": -5.065999984741211
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1345.489013671875,
|
"x": 1344.64794921875,
|
||||||
"y": -4.686999797821045
|
"y": 1.0920000076293945
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1346.0880126953125,
|
"x": 1346.0880126953125,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
60
e2etests/testdata/txtar/cycle-diagram/elk/board.exp.json
generated
vendored
60
e2etests/testdata/txtar/cycle-diagram/elk/board.exp.json
generated
vendored
|
|
@ -1408,8 +1408,8 @@
|
||||||
"y": -25.47599983215332
|
"y": -25.47599983215332
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 208.5659942626953,
|
"x": 207.6020050048828,
|
||||||
"y": -25.10099983215332
|
"y": -30.86199951171875
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 209.2519989013672,
|
"x": 209.2519989013672,
|
||||||
|
|
@ -1772,8 +1772,8 @@
|
||||||
"y": 209.53700256347656
|
"y": 209.53700256347656
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 42.62200164794922,
|
"x": 48.4109992980957,
|
||||||
"y": 209.6790008544922
|
"y": 208.90499877929688
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 38.5,
|
"x": 38.5,
|
||||||
|
|
@ -2136,8 +2136,8 @@
|
||||||
"y": 49.47600173950195
|
"y": 49.47600173950195
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": -184.5659942626953,
|
"x": -183.6020050048828,
|
||||||
"y": 49.10100173950195
|
"y": 54.86199951171875
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": -185.2519989013672,
|
"x": -185.2519989013672,
|
||||||
|
|
@ -2516,8 +2516,8 @@
|
||||||
"y": 123.8030014038086
|
"y": 123.8030014038086
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 675.3259887695312,
|
"x": 677.2830200195312,
|
||||||
"y": 125.08100128173828
|
"y": 119.5770034790039
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 673.9329833984375,
|
"x": 673.9329833984375,
|
||||||
|
|
@ -2880,8 +2880,8 @@
|
||||||
"y": 198.90899658203125
|
"y": 198.90899658203125
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 338.9079895019531,
|
"x": 342.7919921875,
|
||||||
"y": 198.1060028076172
|
"y": 202.46800231933594
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 336.1419982910156,
|
"x": 336.1419982910156,
|
||||||
|
|
@ -3284,8 +3284,8 @@
|
||||||
"y": 208.45700073242188
|
"y": 208.45700073242188
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 936.197021484375,
|
"x": 941.3209838867188,
|
||||||
"y": 209.53700256347656
|
"y": 208.89300537109375
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 931.4099731445312,
|
"x": 931.4099731445312,
|
||||||
|
|
@ -3596,8 +3596,8 @@
|
||||||
"y": -123.375
|
"y": -123.375
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1124.509033203125,
|
"x": 1120.625,
|
||||||
"y": -124.10600280761719
|
"y": -128.46800231933594
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1127.2750244140625,
|
"x": 1127.2750244140625,
|
||||||
|
|
@ -3896,8 +3896,8 @@
|
||||||
"y": 75.79100036621094
|
"y": 75.79100036621094
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1167.7440185546875,
|
"x": 1169.7010498046875,
|
||||||
"y": 75.08100128173828
|
"y": 69.5770034790039
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1166.3509521484375,
|
"x": 1166.3509521484375,
|
||||||
|
|
@ -4208,8 +4208,8 @@
|
||||||
"y": 209.85400390625
|
"y": 209.85400390625
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1009.031005859375,
|
"x": 1014.8179931640625,
|
||||||
"y": 209.6060028076172
|
"y": 208.8179931640625
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1004.9099731445312,
|
"x": 1004.9099731445312,
|
||||||
|
|
@ -4520,8 +4520,8 @@
|
||||||
"y": 147.375
|
"y": 147.375
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 831.3099975585938,
|
"x": 835.1950073242188,
|
||||||
"y": 148.1060028076172
|
"y": 152.46800231933594
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 828.5449829101562,
|
"x": 828.5449829101562,
|
||||||
|
|
@ -4820,8 +4820,8 @@
|
||||||
"y": -51.79100036621094
|
"y": -51.79100036621094
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 788.0750122070312,
|
"x": 786.1190185546875,
|
||||||
"y": -51.08100128173828
|
"y": -45.57699966430664
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 789.468994140625,
|
"x": 789.468994140625,
|
||||||
|
|
@ -5160,8 +5160,8 @@
|
||||||
"y": -67.4469985961914
|
"y": -67.4469985961914
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1571.447998046875,
|
"x": 1568.678955078125,
|
||||||
"y": -67.36699676513672
|
"y": -72.51000213623047
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1573.4189453125,
|
"x": 1573.4189453125,
|
||||||
|
|
@ -5492,8 +5492,8 @@
|
||||||
"y": 168.0070037841797
|
"y": 168.0070037841797
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1544.261962890625,
|
"x": 1548.31396484375,
|
||||||
"y": 166.83799743652344
|
"y": 162.6300048828125
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1541.376953125,
|
"x": 1541.376953125,
|
||||||
|
|
@ -5832,8 +5832,8 @@
|
||||||
"y": 210.97900390625
|
"y": 210.97900390625
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1310.470947265625,
|
"x": 1315.678955078125,
|
||||||
"y": 211.30099487304688
|
"y": 213.94500732421875
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1306.762939453125,
|
"x": 1306.762939453125,
|
||||||
|
|
@ -6160,8 +6160,8 @@
|
||||||
"y": 6.031000137329102
|
"y": 6.031000137329102
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1198.81005859375,
|
"x": 1197.968994140625,
|
||||||
"y": 6.409999847412109
|
"y": 12.1899995803833
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x": 1199.4090576171875,
|
"x": 1199.4090576171875,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Loading…
Reference in a new issue