Merge branch 'terrastruct:master' into master

This commit is contained in:
Alexander Wang 2023-02-03 22:36:26 -08:00 committed by GitHub
commit 50e7d2f9ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
893 changed files with 64257 additions and 34356 deletions

1
.gitignore vendored
View file

@ -5,3 +5,4 @@
*.got.svg *.got.svg
e2e_report.html e2e_report.html
bin bin
out

View file

@ -222,7 +222,7 @@ let us know and we'll be happy to include it here!
- **Python D2 diagram builder**: [https://github.com/MrBlenny/py-d2](https://github.com/MrBlenny/py-d2) - **Python D2 diagram builder**: [https://github.com/MrBlenny/py-d2](https://github.com/MrBlenny/py-d2)
- **Clojure D2 transpiler**: [https://github.com/judepayne/dictim](https://github.com/judepayne/dictim) - **Clojure D2 transpiler**: [https://github.com/judepayne/dictim](https://github.com/judepayne/dictim)
- **JavaScript D2 diagram builder**: [https://github.com/Kreshnik/d2lang-js](https://github.com/Kreshnik/d2lang-js) - **JavaScript D2 diagram builder**: [https://github.com/Kreshnik/d2lang-js](https://github.com/Kreshnik/d2lang-js)
- **Maven plugin**: [https://github.com/andrinmeier/unofficial-d2lang-confluence-plugin](https://github.com/andrinmeier/unofficial-d2lang-confluence-plugin) - **Maven plugin**: [https://github.com/andrinmeier/unofficial-d2lang-maven-plugin](https://github.com/andrinmeier/unofficial-d2lang-maven-plugin)
- **Confluence plugin**: [https://github.com/andrinmeier/unofficial-d2lang-confluence-plugin](https://github.com/andrinmeier/unofficial-d2lang-confluence-plugin) - **Confluence plugin**: [https://github.com/andrinmeier/unofficial-d2lang-confluence-plugin](https://github.com/andrinmeier/unofficial-d2lang-confluence-plugin)
- **CIL (C#, Visual Basic, F#, C++ CLR) to D2**: [https://github.com/HugoVG/AppDiagram](https://github.com/HugoVG/AppDiagram) - **CIL (C#, Visual Basic, F#, C++ CLR) to D2**: [https://github.com/HugoVG/AppDiagram](https://github.com/HugoVG/AppDiagram)

19
ci/cov.sh Executable file
View file

@ -0,0 +1,19 @@
#!/bin/sh
set -eu
cd -- "$(dirname "$0")/.."
. ./ci/sub/lib.sh
main() {
if [ "$*" = "" ]; then
set ./...
fi
mkdir -p out
capcode ./ci/test.sh -covermode=atomic -coverprofile=out/cov.prof "$@"
go tool cover -html=out/cov.prof -o=out/cov.html
go tool cover -func=out/cov.prof | grep '^total:' \
| sed 's#^total:.*(statements)[[:space:]]*\([0-9.%]*\)#TOTAL:\t\1#'
return "$code"
}
main "$@"

View file

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
set -eu set -eu
export REPORT_OUTPUT="out/e2e_report.html" export REPORT_OUTPUT="./e2etests/out/e2e_report.html"
rm -f $REPORT_OUTPUT rm -f $REPORT_OUTPUT
export E2E_REPORT=1 export E2E_REPORT=1

View file

@ -7,7 +7,9 @@ RUN apt-get update && apt-get install -y ca-certificates curl dumb-init sudo
RUN curl -fsSL https://deb.nodesource.com/setup_19.x | bash -s - && \ RUN curl -fsSL https://deb.nodesource.com/setup_19.x | bash -s - && \
apt-get install -y nodejs apt-get install -y nodejs
RUN npx playwright install-deps # https://github.com/microsoft/playwright/issues/18319
# Hopefully soon.
RUN if [ "$TARGETARCH" = amd64 ]; then npx playwright install-deps; fi
RUN adduser --gecos '' --disabled-password debian \ RUN adduser --gecos '' --disabled-password debian \
&& echo "debian ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd && echo "debian ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
@ -26,7 +28,7 @@ RUN mkdir -p /usr/local/lib/d2 \
&& rm -Rf /tmp/d2-*-linux-"$TARGETARCH".tar.gz && rm -Rf /tmp/d2-*-linux-"$TARGETARCH".tar.gz
USER debian:debian USER debian:debian
RUN d2 init-playwright RUN if [ "$TARGETARCH" = amd64 ]; then d2 init-playwright; fi
WORKDIR /home/debian/src WORKDIR /home/debian/src
EXPOSE 8080 EXPOSE 8080

View file

@ -33,11 +33,11 @@ main() {
done done
shift "$FLAGSHIFT" shift "$FLAGSHIFT"
REMOTE_HOST=$CI_HOST_D2_LINUX_AMD64 && runjob linux-amd64 ssh "$REMOTE_HOST" "$@" REMOTE_HOST=$CI_D2_LINUX_AMD64 && runjob linux-amd64 ssh "$REMOTE_HOST" "$@"
REMOTE_HOST=$CI_HOST_D2_LINUX_ARM64 && runjob linux-arm64 ssh "$REMOTE_HOST" "$@" REMOTE_HOST=$CI_D2_LINUX_ARM64 && runjob linux-arm64 ssh "$REMOTE_HOST" "$@"
REMOTE_HOST=$CI_HOST_D2_MACOS_AMD64 && runjob macos-amd64 ssh "$REMOTE_HOST" "$@" REMOTE_HOST=$CI_D2_MACOS_AMD64 && runjob macos-amd64 ssh "$REMOTE_HOST" "$@"
REMOTE_HOST=$CI_HOST_D2_MACOS_ARM64 && runjob macos-arm64 ssh "$REMOTE_HOST" "$@" REMOTE_HOST=$CI_D2_MACOS_ARM64 && runjob macos-arm64 ssh "$REMOTE_HOST" "$@"
REMOTE_HOST=$CI_HOST_D2_WINDOWS_AMD64 && runjob macos-arm64 ssh "$REMOTE_HOST" "$@" REMOTE_HOST=$CI_D2_WINDOWS_AMD64 && runjob windows-amd64 ssh "$REMOTE_HOST" "$@"
} }
main "$@" main "$@"

View file

@ -2,14 +2,33 @@
- `double-border` keyword implemented. [#565](https://github.com/terrastruct/d2/pull/565) - `double-border` keyword implemented. [#565](https://github.com/terrastruct/d2/pull/565)
- The [Dockerfile](./docs/INSTALL.md#docker) now supports rendering PNGs [#594](https://github.com/terrastruct/d2/issues/594) - The [Dockerfile](./docs/INSTALL.md#docker) now supports rendering PNGs [#594](https://github.com/terrastruct/d2/issues/594)
- There was a minor breaking change as part of this where the default working directory of the Dockerfile is now `/home/debian/src` instead of `/root/src` to allow UID remapping with [`fixuid`](https://github.com/boxboat/fixuid). - There was a minor breaking change as part of this where the default working directory of the Dockerfile is now `/home/debian/src` instead of `/root/src` to allow UID remapping with [`fixuid`](https://github.com/boxboat/fixuid).
- `d2 fmt` accepts multiple files to be formatted [#718](https://github.com/terrastruct/d2/issues/718) - `d2 fmt` accepts multiple files to be formatted [#718](https://github.com/terrastruct/d2/issues/718)
- You can now use the reserved keywords `layers`/`scenarios`/`steps` to define diagrams
with multiple levels of abstractions. [#714](https://github.com/terrastruct/d2/pull/714)
Docs to come soon
- [#416](https://github.com/terrastruct/d2/issues/416) was also fixed so you can no
longer use keywords intended for use under `style` outside and vice versa. e.g.
`obj.style.shape` and `obj.double-border` are now illegal. The correct uses are
`obj.shape` and `obj.style.double-border`.
- Many other minor compiler bugs were fixed.
#### Improvements 🧹 #### Improvements 🧹
- Code snippets use bold and italic font styles as determined by highlighter [#710](https://github.com/terrastruct/d2/issues/710), [#741](https://github.com/terrastruct/d2/issues/741) - Code snippets use bold and italic font styles as determined by highlighter [#710](https://github.com/terrastruct/d2/issues/710), [#741](https://github.com/terrastruct/d2/issues/741)
- Reduces default padding of shapes. [#702](https://github.com/terrastruct/d2/pull/702)
- Ensures labels fit inside shapes with shape-specific inner bounding boxes. [#702](https://github.com/terrastruct/d2/pull/702)
- Improves package shape dimensions with short height. [#702](https://github.com/terrastruct/d2/pull/702)
- Keeps person shape from becoming too distorted. [#702](https://github.com/terrastruct/d2/pull/702)
- Ensures shapes with icons have enough padding for their labels. [#702](https://github.com/terrastruct/d2/pull/702)
#### Bugfixes ⛑️ #### Bugfixes ⛑️
- Fixes groups overlapping in sequence diagrams when they end in a self loop. [#728](https://github.com/terrastruct/d2/pull/728) - Fixes groups overlapping in sequence diagrams when they end in a self loop. [#728](https://github.com/terrastruct/d2/pull/728)
- Fixes dimensions of unlabeled squares or circles with only a set width or height. [#702](https://github.com/terrastruct/d2/pull/702)
- Fixes scaling of actor shapes in sequence diagrams. [#702](https://github.com/terrastruct/d2/pull/702)
- Images can now be set to sizes smaller than 128x128. [#702](https://github.com/terrastruct/d2/pull/702)
- Fixes class height when there are no rows. [#756](https://github.com/terrastruct/d2/pull/756)

2
ci/sub

@ -1 +1 @@
Subproject commit 8ac704818b5d7ab519e4b87caf5eb79716493709 Subproject commit 2009cdd523e00cc2e9b8ba804095f71ca70d5671

View file

@ -1,3 +1,5 @@
// TODO: Remove boxes and cleanup like d2ir
//
// d2ast implements the d2 language's abstract syntax tree. // d2ast implements the d2 language's abstract syntax tree.
// //
// Special characters to think about in parser: // Special characters to think about in parser:
@ -149,6 +151,10 @@ func (r *Range) UnmarshalText(b []byte) (err error) {
return r.End.UnmarshalText(end) return r.End.UnmarshalText(end)
} }
func (r Range) Before(r2 Range) bool {
return r.Start.Before(r2.Start)
}
// Position represents a line:column and byte position in a file. // Position represents a line:column and byte position in a file.
// //
// note: Line and Column are zero indexed. // note: Line and Column are zero indexed.
@ -257,6 +263,10 @@ func (p Position) SubtractString(s string, byUTF16 bool) Position {
return p return p
} }
func (p Position) Before(p2 Position) bool {
return p.Byte < p2.Byte
}
// MapNode is implemented by nodes that may be children of Maps. // MapNode is implemented by nodes that may be children of Maps.
type MapNode interface { type MapNode interface {
Node Node
@ -402,7 +412,7 @@ func (s *SingleQuotedString) scalar() {}
func (s *BlockString) scalar() {} func (s *BlockString) scalar() {}
// TODO: mistake, move into parse.go // TODO: mistake, move into parse.go
func (n *Null) ScalarString() string { return n.Type() } func (n *Null) ScalarString() string { return "" }
func (b *Boolean) ScalarString() string { return strconv.FormatBool(b.Value) } func (b *Boolean) ScalarString() string { return strconv.FormatBool(b.Value) }
func (n *Number) ScalarString() string { return n.Raw } func (n *Number) ScalarString() string { return n.Raw }
func (s *UnquotedString) ScalarString() string { func (s *UnquotedString) ScalarString() string {
@ -648,6 +658,21 @@ type KeyPath struct {
Path []*StringBox `json:"path"` Path []*StringBox `json:"path"`
} }
func MakeKeyPath(a []string) *KeyPath {
kp := &KeyPath{}
for _, el := range a {
kp.Path = append(kp.Path, MakeValueBox(RawString(el, true)).StringBox())
}
return kp
}
func (kp *KeyPath) IDA() (ida []string) {
for _, el := range kp.Path {
ida = append(ida, el.Unbox().ScalarString())
}
return ida
}
type Edge struct { type Edge struct {
Range Range `json:"range"` Range Range `json:"range"`
@ -729,6 +754,37 @@ type ArrayNodeBox struct {
Map *Map `json:"map,omitempty"` Map *Map `json:"map,omitempty"`
} }
func MakeArrayNodeBox(an ArrayNode) ArrayNodeBox {
var ab ArrayNodeBox
switch an := an.(type) {
case *Comment:
ab.Comment = an
case *BlockComment:
ab.BlockComment = an
case *Substitution:
ab.Substitution = an
case *Null:
ab.Null = an
case *Boolean:
ab.Boolean = an
case *Number:
ab.Number = an
case *UnquotedString:
ab.UnquotedString = an
case *DoubleQuotedString:
ab.DoubleQuotedString = an
case *SingleQuotedString:
ab.SingleQuotedString = an
case *BlockString:
ab.BlockString = an
case *Array:
ab.Array = an
case *Map:
ab.Map = an
}
return ab
}
func (ab ArrayNodeBox) Unbox() ArrayNode { func (ab ArrayNodeBox) Unbox() ArrayNode {
switch { switch {
case ab.Comment != nil: case ab.Comment != nil:

View file

@ -18,10 +18,11 @@ import (
func GenDSL(maxi int) (_ string, err error) { func GenDSL(maxi int) (_ string, err error) {
gs := &dslGenState{ gs := &dslGenState{
rand: mathrand.New(mathrand.NewSource(time.Now().UnixNano())), rand: mathrand.New(mathrand.NewSource(time.Now().UnixNano())),
g: d2graph.NewGraph(&d2ast.Map{}), g: d2graph.NewGraph(),
nodeShapes: make(map[string]string), nodeShapes: make(map[string]string),
nodeContainer: make(map[string]string), nodeContainer: make(map[string]string),
} }
gs.g.AST = &d2ast.Map{}
err = gs.gen(maxi) err = gs.gen(maxi)
if err != nil { if err != nil {
return "", err return "", err

File diff suppressed because it is too large Load diff

View file

@ -8,12 +8,13 @@ import (
tassert "github.com/stretchr/testify/assert" tassert "github.com/stretchr/testify/assert"
"oss.terrastruct.com/util-go/assert"
"oss.terrastruct.com/util-go/diff"
"oss.terrastruct.com/d2/d2compiler" "oss.terrastruct.com/d2/d2compiler"
"oss.terrastruct.com/d2/d2format" "oss.terrastruct.com/d2/d2format"
"oss.terrastruct.com/d2/d2graph" "oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2target" "oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/util-go/assert"
"oss.terrastruct.com/util-go/diff"
) )
func TestCompile(t *testing.T) { func TestCompile(t *testing.T) {
@ -123,8 +124,7 @@ x: {
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/equal_dimensions_on_circle.d2:3:2: width and height must be equal for circle shapes expErr: `d2/testdata/d2compiler/TestCompile/equal_dimensions_on_circle.d2:3:2: width and height must be equal for circle shapes
d2/testdata/d2compiler/TestCompile/equal_dimensions_on_circle.d2:4:2: width and height must be equal for circle shapes d2/testdata/d2compiler/TestCompile/equal_dimensions_on_circle.d2:4:2: width and height must be equal for circle shapes`,
`,
}, },
{ {
name: "single_dimension_on_circle", name: "single_dimension_on_circle",
@ -207,8 +207,7 @@ d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:16:3: height c
d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:25:3: width cannot be used on container: containers.oval container d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:25:3: width cannot be used on container: containers.oval container
d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:26:3: height cannot be used on container: containers.oval container d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:26:3: height cannot be used on container: containers.oval container
d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:36:3: width cannot be used on container: containers.hexagon container d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:36:3: width cannot be used on container: containers.hexagon container
d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:37:3: height cannot be used on container: containers.hexagon container d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:37:3: height cannot be used on container: containers.hexagon container`,
`,
}, },
{ {
name: "dimension_with_style", name: "dimension_with_style",
@ -241,8 +240,7 @@ d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:37:3: height c
} }
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/shape_unquoted_hex.d2:3:10: missing value after colon expErr: `d2/testdata/d2compiler/TestCompile/shape_unquoted_hex.d2:3:10: missing value after colon`,
`,
}, },
{ {
name: "edge_unquoted_hex", name: "edge_unquoted_hex",
@ -253,8 +251,7 @@ d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:37:3: height c
} }
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/edge_unquoted_hex.d2:3:10: missing value after colon expErr: `d2/testdata/d2compiler/TestCompile/edge_unquoted_hex.d2:3:10: missing value after colon`,
`,
}, },
{ {
name: "blank_underscore", name: "blank_underscore",
@ -264,8 +261,7 @@ d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:37:3: height c
_ _
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/blank_underscore.d2:3:3: invalid use of parent "_" expErr: `d2/testdata/d2compiler/TestCompile/blank_underscore.d2:3:3: field key must contain more than underscores`,
`,
}, },
{ {
name: "image_non_style", name: "image_non_style",
@ -276,8 +272,7 @@ d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:37:3: height c
name: y name: y
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/image_non_style.d2:4:3: image shapes cannot have children. expErr: `d2/testdata/d2compiler/TestCompile/image_non_style.d2:4:3: image shapes cannot have children.`,
`,
}, },
{ {
name: "stroke-width", name: "stroke-width",
@ -302,8 +297,7 @@ d2/testdata/d2compiler/TestCompile/no_dimensions_on_containers.d2:37:3: height c
style.stroke-width: -1 style.stroke-width: -1
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/illegal-stroke-width.d2:2:23: expected "stroke-width" to be a number between 0 and 15 expErr: `d2/testdata/d2compiler/TestCompile/illegal-stroke-width.d2:2:23: expected "stroke-width" to be a number between 0 and 15`,
`,
}, },
{ {
name: "underscore_parent_create", name: "underscore_parent_create",
@ -340,8 +334,7 @@ x: {
`, `,
assertions: func(t *testing.T, g *d2graph.Graph) { assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, "y", g.Objects[1].ID) tassert.Equal(t, "y", g.Objects[1].ID)
tassert.Equal(t, g.Root.AbsID(), g.Objects[1].References[0].ScopeObj.AbsID()) tassert.Equal(t, g.Objects[0].AbsID(), g.Objects[1].References[0].ScopeObj.AbsID())
tassert.Equal(t, g.Objects[0].AbsID(), g.Objects[1].References[0].UnresolvedScopeObj.AbsID())
}, },
}, },
{ {
@ -456,8 +449,7 @@ x: {
text: ` text: `
_.x _.x
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/underscore_parent_root.d2:2:1: parent "_" cannot be used in the root scope expErr: `d2/testdata/d2compiler/TestCompile/underscore_parent_root.d2:2:1: invalid underscore: no parent`,
`,
}, },
{ {
name: "underscore_parent_middle_path", name: "underscore_parent_middle_path",
@ -467,8 +459,7 @@ x: {
y._.z y._.z
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/underscore_parent_middle_path.d2:3:3: parent "_" can only be used in the beginning of paths, e.g. "_.x" expErr: `d2/testdata/d2compiler/TestCompile/underscore_parent_middle_path.d2:3:5: parent "_" can only be used in the beginning of paths, e.g. "_.x"`,
`,
}, },
{ {
name: "underscore_parent_sandwich_path", name: "underscore_parent_sandwich_path",
@ -478,8 +469,7 @@ x: {
_.z._ _.z._
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/underscore_parent_sandwich_path.d2:3:3: parent "_" can only be used in the beginning of paths, e.g. "_.x" expErr: `d2/testdata/d2compiler/TestCompile/underscore_parent_sandwich_path.d2:3:7: parent "_" can only be used in the beginning of paths, e.g. "_.x"`,
`,
}, },
{ {
name: "underscore_edge", name: "underscore_edge",
@ -996,8 +986,7 @@ x -> y: {
text: `x: {shape: triangle} text: `x: {shape: triangle}
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/object_arrowhead_shape.d2:1:5: invalid shape, can only set "triangle" for arrowheads expErr: `d2/testdata/d2compiler/TestCompile/object_arrowhead_shape.d2:1:5: invalid shape, can only set "triangle" for arrowheads`,
`,
}, },
{ {
name: "edge_flat_label_arrowhead", name: "edge_flat_label_arrowhead",
@ -1083,8 +1072,7 @@ x -> y: {
space -> stars space -> stars
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/nested_edge.d2:1:1: edges cannot be nested within another edge expErr: `d2/testdata/d2compiler/TestCompile/nested_edge.d2:2:3: cannot create edge inside edge`,
`,
}, },
{ {
name: "shape_edge_style", name: "shape_edge_style",
@ -1094,8 +1082,7 @@ x: {
style.animated: true style.animated: true
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/shape_edge_style.d2:3:2: key "animated" can only be applied to edges expErr: `d2/testdata/d2compiler/TestCompile/shape_edge_style.d2:3:2: key "animated" can only be applied to edges`,
`,
}, },
{ {
name: "edge_chain_map", name: "edge_chain_map",
@ -1351,8 +1338,7 @@ x -> y: {
z z
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/edge_map_non_reserved.d2:2:1: edge map keys must be reserved keywords expErr: `d2/testdata/d2compiler/TestCompile/edge_map_non_reserved.d2:3:3: edge map keys must be reserved keywords`,
`,
}, },
{ {
name: "url_link", name: "url_link",
@ -1397,8 +1383,7 @@ x -> y: {
text: `x.near: txop-center text: `x.near: txop-center
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/near_bad_constant.d2:1:1: near key "txop-center" must be the absolute path to a shape or one of the following constants: top-left, top-center, top-right, center-left, center-right, bottom-left, bottom-center, bottom-right expErr: `d2/testdata/d2compiler/TestCompile/near_bad_constant.d2:1:9: near key "txop-center" must be the absolute path to a shape or one of the following constants: top-left, top-center, top-right, center-left, center-right, bottom-left, bottom-center, bottom-right`,
`,
}, },
{ {
name: "near_bad_container", name: "near_bad_container",
@ -1408,8 +1393,7 @@ x -> y: {
y y
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/near_bad_container.d2:1:1: constant near keys cannot be set on shapes with children expErr: `d2/testdata/d2compiler/TestCompile/near_bad_container.d2:2:9: constant near keys cannot be set on shapes with children`,
`,
}, },
{ {
name: "near_bad_connected", name: "near_bad_connected",
@ -1419,16 +1403,14 @@ x -> y: {
} }
x -> y x -> y
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/near_bad_connected.d2:1:1: constant near keys cannot be set on connected shapes expErr: `d2/testdata/d2compiler/TestCompile/near_bad_connected.d2:2:9: constant near keys cannot be set on connected shapes`,
`,
}, },
{ {
name: "nested_near_constant", name: "nested_near_constant",
text: `x.y.near: top-center text: `x.y.near: top-center
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/nested_near_constant.d2:1:1: constant near keys can only be set on root level shapes expErr: `d2/testdata/d2compiler/TestCompile/nested_near_constant.d2:1:11: constant near keys can only be set on root level shapes`,
`,
}, },
{ {
name: "reserved_icon_near_style", name: "reserved_icon_near_style",
@ -1474,17 +1456,14 @@ y
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:3:9: bad icon url "::????:::%%orange": parse "::????:::%%orange": missing protocol scheme expErr: `d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:3:9: bad icon url "::????:::%%orange": parse "::????:::%%orange": missing protocol scheme
d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:4:18: expected "opacity" to be a number between 0.0 and 1.0
d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:5:18: expected "opacity" to be a number between 0.0 and 1.0 d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:5:18: expected "opacity" to be a number between 0.0 and 1.0
d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:1:1: near key "y" must be the absolute path to a shape or one of the following constants: top-left, top-center, top-right, center-left, center-right, bottom-left, bottom-center, bottom-right d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:2:9: near key "y" must be the absolute path to a shape or one of the following constants: top-left, top-center, top-right, center-left, center-right, bottom-left, bottom-center, bottom-right`,
`,
}, },
{ {
name: "errors/missing_shape_icon", name: "errors/missing_shape_icon",
text: `x.shape: image`, text: `x.shape: image`,
expErr: `d2/testdata/d2compiler/TestCompile/errors/missing_shape_icon.d2:1:1: image shape must include an "icon" field expErr: `d2/testdata/d2compiler/TestCompile/errors/missing_shape_icon.d2:1:1: image shape must include an "icon" field`,
`,
}, },
{ {
name: "edge_in_column", name: "edge_in_column",
@ -1500,8 +1479,7 @@ d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:1:1: near key "
text: `x: {style.opacity: 0.4} text: `x: {style.opacity: 0.4}
y -> x.style y -> x.style
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/edge_to_style.d2:2:1: cannot connect to reserved keyword expErr: `d2/testdata/d2compiler/TestCompile/edge_to_style.d2:2:8: reserved keywords are prohibited in edges`,
`,
}, },
{ {
name: "escaped_id", name: "escaped_id",
@ -1581,7 +1559,7 @@ b`, g.Objects[0].Attributes.Label.Value)
GetType(): string GetType(): string
style: { style: {
opacity: 0.4 opacity: 0.4
color: blue font-color: blue
} }
} }
`, `,
@ -1680,10 +1658,9 @@ x.y -> a.b: {
{ {
name: "3d_oval", name: "3d_oval",
text: `SVP1.style.shape: oval text: `SVP1.shape: oval
SVP1.style.3d: true`, SVP1.style.3d: true`,
expErr: `d2/testdata/d2compiler/TestCompile/3d_oval.d2:2:1: key "3d" can only be applied to squares and rectangles expErr: `d2/testdata/d2compiler/TestCompile/3d_oval.d2:2:1: key "3d" can only be applied to squares and rectangles`,
`,
}, { }, {
name: "edge_column_index", name: "edge_column_index",
text: `src: { text: `src: {
@ -1740,8 +1717,7 @@ dst.id <-> src.dst_id
} }
b -> x.a b -> x.a
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/leaky_sequence.d2:5:1: connections within sequence diagrams can connect only to other objects within the same sequence diagram expErr: `d2/testdata/d2compiler/TestCompile/leaky_sequence.d2:5:1: connections within sequence diagrams can connect only to other objects within the same sequence diagram`,
`,
}, },
{ {
name: "sequence_scoping", name: "sequence_scoping",
@ -1775,6 +1751,35 @@ choo: {
tassert.Equal(t, 3, len(g.Root.ChildrenArray)) tassert.Equal(t, 3, len(g.Root.ChildrenArray))
}, },
}, },
{
name: "sequence_container",
text: `shape: sequence_diagram
x.y.q -> j.y.p
ok: {
x.y.q -> j.y.p
}
`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, 7, len(g.Objects))
tassert.Equal(t, 3, len(g.Root.ChildrenArray))
},
},
{
name: "sequence_container_2",
text: `shape: sequence_diagram
x.y.q
ok: {
x.y.q -> j.y.p
meow
}
`,
assertions: func(t *testing.T, g *d2graph.Graph) {
tassert.Equal(t, 8, len(g.Objects))
tassert.Equal(t, 2, len(g.Root.ChildrenArray))
},
},
{ {
name: "root_direction", name: "root_direction",
@ -1818,8 +1823,7 @@ choo: {
text: `x: { text: `x: {
direction: diagonal direction: diagonal
}`, }`,
expErr: `d2/testdata/d2compiler/TestCompile/invalid_direction.d2:2:14: direction must be one of up, down, right, left, got "diagonal" expErr: `d2/testdata/d2compiler/TestCompile/invalid_direction.d2:2:14: direction must be one of up, down, right, left, got "diagonal"`,
`,
}, },
{ {
name: "self-referencing", name: "self-referencing",
@ -1868,8 +1872,7 @@ choo: {
test_id: varchar(64) {constraint: [primary_key, foreign_key]} test_id: varchar(64) {constraint: [primary_key, foreign_key]}
} }
`, `,
expErr: `d2/testdata/d2compiler/TestCompile/sql-panic.d2:3:27: constraint value must be a string expErr: `d2/testdata/d2compiler/TestCompile/sql-panic.d2:3:27: reserved field constraint does not accept composite`,
`,
}, },
{ {
name: "wrong_column_index", name: "wrong_column_index",
@ -1939,3 +1942,167 @@ Chinchillas_Collectibles.chinchilla -> Chinchillas.id`,
}) })
} }
} }
func TestCompile2(t *testing.T) {
t.Parallel()
t.Run("boards", testBoards)
t.Run("seqdiagrams", testSeqDiagrams)
}
func testBoards(t *testing.T) {
t.Parallel()
tca := []struct {
name string
run func(t *testing.T)
}{
{
name: "root",
run: func(t *testing.T) {
g := assertCompile(t, `base
layers: {
one: {
santa
}
two: {
clause
}
}
`, "")
assert.JSON(t, 2, len(g.Layers))
assert.JSON(t, "one", g.Layers[0].Name)
assert.JSON(t, "two", g.Layers[1].Name)
},
},
{
name: "recursive",
run: func(t *testing.T) {
g := assertCompile(t, `base
layers: {
one: {
santa
}
two: {
clause
steps: {
seinfeld: {
reindeer
}
missoula: {
montana
}
}
}
}
`, "")
assert.Equal(t, 2, len(g.Layers))
assert.Equal(t, "one", g.Layers[0].Name)
assert.Equal(t, "two", g.Layers[1].Name)
assert.Equal(t, 2, len(g.Layers[1].Steps))
},
},
{
name: "errs/duplicate_board",
run: func(t *testing.T) {
assertCompile(t, `base
layers: {
one: {
santa
}
}
steps: {
one: {
clause
}
}
`, `d2/testdata/d2compiler/TestCompile2/boards/errs/duplicate_board.d2:9:2: board name one already used by another board`)
},
},
}
for _, tc := range tca {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
tc.run(t)
})
}
}
func testSeqDiagrams(t *testing.T) {
t.Parallel()
t.Run("errs", func(t *testing.T) {
t.Parallel()
tca := []struct {
name string
skip bool
run func(t *testing.T)
}{
{
name: "sequence_diagram_edge_between_edge_groups",
// New sequence diagram scoping implementation is disabled.
skip: true,
run: func(t *testing.T) {
assertCompile(t, `
Office chatter: {
shape: sequence_diagram
alice: Alice
bob: Bobby
awkward small talk: {
alice -> bob: uhm, hi
bob -> alice: oh, hello
icebreaker attempt: {
alice -> bob: what did you have for lunch?
}
unfortunate outcome: {
bob -> alice: that's personal
}
}
awkward small talk.icebreaker attempt.alice -> awkward small talk.unfortunate outcome.bob
}
`, "d2/testdata/d2compiler/TestCompile2/seqdiagrams/errs/sequence_diagram_edge_between_edge_groups.d2:16:3: edges between edge groups are not allowed")
},
},
}
for _, tc := range tca {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
if tc.skip {
t.SkipNow()
}
tc.run(t)
})
}
})
}
func assertCompile(t *testing.T, text string, expErr string) *d2graph.Graph {
d2Path := fmt.Sprintf("d2/testdata/d2compiler/%v.d2", t.Name())
g, err := d2compiler.Compile(d2Path, strings.NewReader(text), nil)
if expErr != "" {
assert.Error(t, err)
assert.ErrorString(t, err, expErr)
} else {
assert.Success(t, err)
}
got := struct {
Graph *d2graph.Graph `json:"graph"`
Err error `json:"err"`
}{
Graph: g,
Err: err,
}
err = diff.TestdataJSON(filepath.Join("..", "testdata", "d2compiler", t.Name()), got)
assert.Success(t, err)
return g
}

View file

@ -4,18 +4,20 @@ import (
"context" "context"
"strconv" "strconv"
"oss.terrastruct.com/util-go/go2"
"oss.terrastruct.com/d2/d2graph" "oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2renderers/d2fonts" "oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2target" "oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes" "oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/d2themes/d2themescatalog" "oss.terrastruct.com/d2/d2themes/d2themescatalog"
"oss.terrastruct.com/util-go/go2"
) )
func Export(ctx context.Context, g *d2graph.Graph, themeID int64, fontFamily *d2fonts.FontFamily) (*d2target.Diagram, error) { func Export(ctx context.Context, g *d2graph.Graph, themeID int64, fontFamily *d2fonts.FontFamily) (*d2target.Diagram, error) {
theme := d2themescatalog.Find(themeID) theme := d2themescatalog.Find(themeID)
diagram := d2target.NewDiagram() diagram := d2target.NewDiagram()
diagram.Name = g.Name
if fontFamily == nil { if fontFamily == nil {
fontFamily = go2.Pointer(d2fonts.SourceSansPro) fontFamily = go2.Pointer(d2fonts.SourceSansPro)
} }
@ -141,6 +143,7 @@ func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
} }
shape.Label = text.Text shape.Label = text.Text
shape.LabelWidth = text.Dimensions.Width shape.LabelWidth = text.Dimensions.Width
shape.LabelHeight = text.Dimensions.Height shape.LabelHeight = text.Dimensions.Height
if obj.LabelPosition != nil { if obj.LabelPosition != nil {
shape.LabelPosition = *obj.LabelPosition shape.LabelPosition = *obj.LabelPosition

View file

@ -397,3 +397,15 @@ func (p *printer) edgeIndex(ei *d2ast.EdgeIndex) {
} }
p.sb.WriteByte(']') p.sb.WriteByte(']')
} }
func KeyPath(kp *d2ast.KeyPath) (ida []string) {
for _, s := range kp.Path {
// We format each string of the key to ensure the resulting strings can be parsed
// correctly.
n := &d2ast.KeyPath{
Path: []*d2ast.StringBox{d2ast.MakeValueBox(d2ast.RawString(s.Unbox().ScalarString(), true)).StringBox()},
}
ida = append(ida, Format(n))
}
return ida
}

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"math" "math"
"net/url" "net/url"
"sort"
"strconv" "strconv"
"strings" "strings"
@ -18,31 +19,34 @@ import (
"oss.terrastruct.com/d2/d2target" "oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes" "oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/lib/geo" "oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/shape"
"oss.terrastruct.com/d2/lib/textmeasure" "oss.terrastruct.com/d2/lib/textmeasure"
) )
const INNER_LABEL_PADDING int = 5 const INNER_LABEL_PADDING int = 5
const DEFAULT_SHAPE_PADDING = 100. const DEFAULT_SHAPE_SIZE = 100.
const MIN_SHAPE_SIZE = 5
// TODO: Refactor with a light abstract layer on top of AST implementing scenarios,
// variables, imports, substitutions and then a final set of structures representing
// a final graph.
type Graph struct { type Graph struct {
Name string `json:"name"`
AST *d2ast.Map `json:"ast"` AST *d2ast.Map `json:"ast"`
Root *Object `json:"root"` Root *Object `json:"root"`
Edges []*Edge `json:"edges"` Edges []*Edge `json:"edges"`
Objects []*Object `json:"objects"` Objects []*Object `json:"objects"`
Layers []*Graph `json:"layers,omitempty"`
Scenarios []*Graph `json:"scenarios,omitempty"`
Steps []*Graph `json:"steps,omitempty"`
} }
func NewGraph(ast *d2ast.Map) *Graph { func NewGraph() *Graph {
d := &Graph{ d := &Graph{}
AST: ast,
}
d.Root = &Object{ d.Root = &Object{
Graph: d, Graph: d,
Parent: nil, Parent: nil,
Children: make(map[string]*Object), Children: make(map[string]*Object),
Attributes: &Attributes{},
} }
return d return d
} }
@ -82,7 +86,7 @@ type Object struct {
Children map[string]*Object `json:"-"` Children map[string]*Object `json:"-"`
ChildrenArray []*Object `json:"-"` ChildrenArray []*Object `json:"-"`
Attributes Attributes `json:"attributes"` Attributes *Attributes `json:"attributes,omitempty"`
ZIndex int `json:"zIndex"` ZIndex int `json:"zIndex"`
} }
@ -106,6 +110,7 @@ type Attributes struct {
Shape Scalar `json:"shape"` Shape Scalar `json:"shape"`
Direction Scalar `json:"direction"` Direction Scalar `json:"direction"`
Constraint Scalar `json:"constraint"`
} }
// TODO references at the root scope should have their Scope set to root graph AST // TODO references at the root scope should have their Scope set to root graph AST
@ -116,9 +121,7 @@ type Reference struct {
MapKey *d2ast.Key `json:"-"` MapKey *d2ast.Key `json:"-"`
MapKeyEdgeIndex int `json:"map_key_edge_index"` MapKeyEdgeIndex int `json:"map_key_edge_index"`
Scope *d2ast.Map `json:"-"` Scope *d2ast.Map `json:"-"`
// The ScopeObj and UnresolvedScopeObj are the same except when the key contains underscores
ScopeObj *Object `json:"-"` ScopeObj *Object `json:"-"`
UnresolvedScopeObj *Object `json:"-"`
} }
func (r Reference) MapKeyEdgeDest() bool { func (r Reference) MapKeyEdgeDest() bool {
@ -500,10 +503,13 @@ func (obj *Object) newObject(id string) *Object {
child := &Object{ child := &Object{
ID: id, ID: id,
IDVal: idval, IDVal: idval,
Attributes: Attributes{ Attributes: &Attributes{
Label: Scalar{ Label: Scalar{
Value: idval, Value: idval,
}, },
Shape: Scalar{
Value: d2target.ShapeRectangle,
},
}, },
Graph: obj.Graph, Graph: obj.Graph,
@ -523,6 +529,9 @@ func (obj *Object) newObject(id string) *Object {
} }
func (obj *Object) HasChild(ids []string) (*Object, bool) { func (obj *Object) HasChild(ids []string) (*Object, bool) {
if len(ids) == 0 {
return obj, true
}
if len(ids) == 1 && ids[0] != "style" { if len(ids) == 1 && ids[0] != "style" {
_, ok := ReservedKeywords[ids[0]] _, ok := ReservedKeywords[ids[0]]
if ok { if ok {
@ -557,6 +566,7 @@ func (obj *Object) HasEdge(mk *d2ast.Key) (*Edge, bool) {
return nil, false return nil, false
} }
// TODO: remove once not used anywhere
func ResolveUnderscoreKey(ida []string, obj *Object) (resolvedObj *Object, resolvedIDA []string, _ error) { func ResolveUnderscoreKey(ida []string, obj *Object) (resolvedObj *Object, resolvedIDA []string, _ error) {
if len(ida) > 0 && !obj.IsSequenceDiagram() { if len(ida) > 0 && !obj.IsSequenceDiagram() {
objSD := obj.OuterSequenceDiagram() objSD := obj.OuterSequenceDiagram()
@ -637,34 +647,71 @@ func (obj *Object) FindEdges(mk *d2ast.Key) ([]*Edge, bool) {
return ea, true return ea, true
} }
func (obj *Object) ensureChildEdge(ida []string) *Object {
for i := range ida {
switch obj.Attributes.Shape.Value {
case d2target.ShapeClass, d2target.ShapeSQLTable:
// This will only be called for connecting edges where we want to truncate to the
// container.
return obj
default:
obj = obj.EnsureChild(ida[i : i+1])
}
}
return obj
}
// EnsureChild grabs the child by ids or creates it if it does not exist including all // EnsureChild grabs the child by ids or creates it if it does not exist including all
// intermediate nodes. // intermediate nodes.
func (obj *Object) EnsureChild(ids []string) *Object { func (obj *Object) EnsureChild(ida []string) *Object {
_, is := ReservedKeywordHolders[ids[0]] seq := obj.OuterSequenceDiagram()
if len(ids) == 1 && !is { if seq != nil {
_, ok := ReservedKeywords[ids[0]] for _, c := range seq.ChildrenArray {
if c.ID == ida[0] {
if obj.ID == ida[0] {
// In cases of a.a where EnsureChild is called on the parent a, the second a should
// be created as a child of a and not as a child of the diagram. This is super
// unfortunate code but alas.
break
}
obj = seq
break
}
}
}
if len(ida) == 0 {
return obj
}
_, is := ReservedKeywordHolders[ida[0]]
if len(ida) == 1 && !is {
_, ok := ReservedKeywords[ida[0]]
if ok { if ok {
return obj return obj
} }
} }
id := ids[0] id := ida[0]
ids = ids[1:] ida = ida[1:]
if id == "_" {
return obj.Parent.EnsureChild(ida)
}
child, ok := obj.Children[strings.ToLower(id)] child, ok := obj.Children[strings.ToLower(id)]
if !ok { if !ok {
child = obj.newObject(id) child = obj.newObject(id)
} }
if len(ids) >= 1 { if len(ida) >= 1 {
return child.EnsureChild(ids) return child.EnsureChild(ida)
} }
return child return child
} }
func (obj *Object) AppendReferences(ida []string, ref Reference, unresolvedObj *Object) { func (obj *Object) AppendReferences(ida []string, ref Reference, unresolvedObj *Object) {
ref.ScopeObj = obj ref.ScopeObj = unresolvedObj
ref.UnresolvedScopeObj = unresolvedObj
numUnderscores := 0 numUnderscores := 0
for i := range ida { for i := range ida {
if ida[i] == "_" { if ida[i] == "_" {
@ -730,9 +777,14 @@ func (obj *Object) GetLabelSize(mtexts []*d2target.MText, ruler *textmeasure.Rul
return dims, nil return dims, nil
} }
func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily, labelDims d2target.TextDimensions) (*d2target.TextDimensions, error) { func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily, labelDims d2target.TextDimensions, withLabelPadding bool) (*d2target.TextDimensions, error) {
dims := d2target.TextDimensions{} dims := d2target.TextDimensions{}
if withLabelPadding {
labelDims.Width += INNER_LABEL_PADDING
labelDims.Height += INNER_LABEL_PADDING
}
switch strings.ToLower(obj.Attributes.Shape.Value) { switch strings.ToLower(obj.Attributes.Shape.Value) {
default: default:
return d2target.NewTextDimensions(labelDims.Width, labelDims.Height), nil return d2target.NewTextDimensions(labelDims.Width, labelDims.Height), nil
@ -748,22 +800,22 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
if fdims == nil { if fdims == nil {
return nil, fmt.Errorf("dimensions for class field %#v not found", f.Text()) return nil, fmt.Errorf("dimensions for class field %#v not found", f.Text())
} }
lineWidth := fdims.Width maxWidth = go2.Max(maxWidth, fdims.Width)
if maxWidth < lineWidth {
maxWidth = lineWidth
}
} }
for _, m := range obj.Class.Methods { for _, m := range obj.Class.Methods {
mdims := GetTextDimensions(mtexts, ruler, m.Text(), go2.Pointer(d2fonts.SourceCodePro)) mdims := GetTextDimensions(mtexts, ruler, m.Text(), go2.Pointer(d2fonts.SourceCodePro))
if mdims == nil { if mdims == nil {
return nil, fmt.Errorf("dimensions for class method %#v not found", m.Text()) return nil, fmt.Errorf("dimensions for class method %#v not found", m.Text())
} }
lineWidth := mdims.Width maxWidth = go2.Max(maxWidth, mdims.Width)
if maxWidth < lineWidth {
maxWidth = lineWidth
} }
} // ┌─PrefixWidth ┌─CenterPadding
dims.Width = maxWidth // ┌─┬─┬───────┬──────┬───┬──┐
// │ + getJobs() Job[] │
// └─┴─┴───────┴──────┴───┴──┘
// └─PrefixPadding └──TypePadding
// ├───────┤ + ├───┤ = maxWidth
dims.Width = d2target.PrefixPadding + d2target.PrefixWidth + maxWidth + d2target.CenterPadding + d2target.TypePadding
// All rows should be the same height // All rows should be the same height
var anyRowText *d2target.MText var anyRowText *d2target.MText
@ -773,11 +825,10 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
anyRowText = obj.Class.Methods[0].Text() anyRowText = obj.Class.Methods[0].Text()
} }
if anyRowText != nil { if anyRowText != nil {
// 10px of padding top and bottom so text doesn't look squished rowHeight := GetTextDimensions(mtexts, ruler, anyRowText, go2.Pointer(d2fonts.SourceCodePro)).Height + d2target.VerticalPadding
rowHeight := GetTextDimensions(mtexts, ruler, anyRowText, go2.Pointer(d2fonts.SourceCodePro)).Height + 20
dims.Height = rowHeight * (len(obj.Class.Fields) + len(obj.Class.Methods) + 2) dims.Height = rowHeight * (len(obj.Class.Fields) + len(obj.Class.Methods) + 2)
} else { } else {
dims.Height = go2.Max(12, labelDims.Height) dims.Height = 2*go2.Max(12, labelDims.Height) + d2target.VerticalPadding
} }
case d2target.ShapeSQLTable: case d2target.ShapeSQLTable:
@ -796,9 +847,7 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
} }
c.Name.LabelWidth = nameDims.Width c.Name.LabelWidth = nameDims.Width
c.Name.LabelHeight = nameDims.Height c.Name.LabelHeight = nameDims.Height
if maxNameWidth < nameDims.Width { maxNameWidth = go2.Max(maxNameWidth, nameDims.Width)
maxNameWidth = nameDims.Width
}
typeDims := GetTextDimensions(mtexts, ruler, ctexts[1], fontFamily) typeDims := GetTextDimensions(mtexts, ruler, ctexts[1], fontFamily)
if typeDims == nil { if typeDims == nil {
@ -809,6 +858,7 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
if maxTypeWidth < typeDims.Width { if maxTypeWidth < typeDims.Width {
maxTypeWidth = typeDims.Width maxTypeWidth = typeDims.Width
} }
maxTypeWidth = go2.Max(maxTypeWidth, typeDims.Width)
if c.Constraint != "" { if c.Constraint != "" {
// covers UNQ constraint with padding // covers UNQ constraint with padding
@ -826,21 +876,6 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
return &dims, nil return &dims, nil
} }
func (obj *Object) GetPadding() (x, y float64) {
switch strings.ToLower(obj.Attributes.Shape.Value) {
case d2target.ShapeImage,
d2target.ShapeSQLTable,
d2target.ShapeText,
d2target.ShapeCode:
return 0., 0.
case d2target.ShapeClass:
// TODO fix class row width measurements (see SQL table)
return 100., 0.
default:
return DEFAULT_SHAPE_PADDING, DEFAULT_SHAPE_PADDING
}
}
type Edge struct { type Edge struct {
Index int `json:"index"` Index int `json:"index"`
@ -866,7 +901,7 @@ type Edge struct {
DstArrowhead *Attributes `json:"dstArrowhead,omitempty"` DstArrowhead *Attributes `json:"dstArrowhead,omitempty"`
References []EdgeReference `json:"references,omitempty"` References []EdgeReference `json:"references,omitempty"`
Attributes Attributes `json:"attributes"` Attributes *Attributes `json:"attributes,omitempty"`
ZIndex int `json:"zIndex"` ZIndex int `json:"zIndex"`
} }
@ -938,15 +973,6 @@ func (e *Edge) AbsID() string {
} }
func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label string) (*Edge, error) { func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label string) (*Edge, error) {
srcObj, srcID, err := ResolveUnderscoreKey(srcID, obj)
if err != nil {
return nil, err
}
dstObj, dstID, err := ResolveUnderscoreKey(dstID, obj)
if err != nil {
return nil, err
}
for _, id := range [][]string{srcID, dstID} { for _, id := range [][]string{srcID, dstID} {
for _, p := range id { for _, p := range id {
if _, ok := ReservedKeywords[p]; ok { if _, ok := ReservedKeywords[p]; ok {
@ -955,15 +981,15 @@ func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label
} }
} }
src := srcObj.EnsureChild(srcID) src := obj.ensureChildEdge(srcID)
dst := dstObj.EnsureChild(dstID) dst := obj.ensureChildEdge(dstID)
if src.OuterSequenceDiagram() != dst.OuterSequenceDiagram() { if src.OuterSequenceDiagram() != dst.OuterSequenceDiagram() {
return nil, errors.New("connections within sequence diagrams can connect only to other objects within the same sequence diagram") return nil, errors.New("connections within sequence diagrams can connect only to other objects within the same sequence diagram")
} }
edge := &Edge{ e := &Edge{
Attributes: Attributes{ Attributes: &Attributes{
Label: Scalar{ Label: Scalar{
Value: label, Value: label,
}, },
@ -973,10 +999,47 @@ func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label
Dst: dst, Dst: dst,
DstArrow: dstArrow, DstArrow: dstArrow,
} }
edge.initIndex() e.initIndex()
obj.Graph.Edges = append(obj.Graph.Edges, edge) addSQLTableColumnIndices(e, srcID, dstID, obj, src, dst)
return edge, nil
obj.Graph.Edges = append(obj.Graph.Edges, e)
return e, nil
}
func addSQLTableColumnIndices(e *Edge, srcID, dstID []string, obj, src, dst *Object) {
if src.Attributes.Shape.Value == d2target.ShapeSQLTable {
if src == dst {
// Ignore edge to column inside table.
return
}
objAbsID := obj.AbsIDArray()
srcAbsID := src.AbsIDArray()
if len(objAbsID)+len(srcID) > len(srcAbsID) {
for i, d2col := range src.SQLTable.Columns {
if d2col.Name.Label == srcID[len(srcID)-1] {
d2col.Reference = dst.AbsID()
e.SrcTableColumnIndex = new(int)
*e.SrcTableColumnIndex = i
break
}
}
}
}
if dst.Attributes.Shape.Value == d2target.ShapeSQLTable {
objAbsID := obj.AbsIDArray()
dstAbsID := dst.AbsIDArray()
if len(objAbsID)+len(dstID) > len(dstAbsID) {
for i, d2col := range dst.SQLTable.Columns {
if d2col.Name.Label == dstID[len(dstID)-1] {
d2col.Reference = dst.AbsID()
e.DstTableColumnIndex = new(int)
*e.DstTableColumnIndex = i
break
}
}
}
}
} }
// TODO: Treat undirectional/bidirectional edge here and in HasEdge flipped. Same with // TODO: Treat undirectional/bidirectional edge here and in HasEdge flipped. Same with
@ -1108,29 +1171,41 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
desiredHeight, _ = strconv.Atoi(obj.Attributes.Height.Value) desiredHeight, _ = strconv.Atoi(obj.Attributes.Height.Value)
} }
dslShape := strings.ToLower(obj.Attributes.Shape.Value)
if obj.Attributes.Label.Value == "" && if obj.Attributes.Label.Value == "" &&
obj.Attributes.Shape.Value != d2target.ShapeImage && dslShape != d2target.ShapeImage &&
obj.Attributes.Shape.Value != d2target.ShapeSQLTable && dslShape != d2target.ShapeSQLTable &&
obj.Attributes.Shape.Value != d2target.ShapeClass { dslShape != d2target.ShapeClass {
obj.Width = DEFAULT_SHAPE_PADDING
obj.Height = DEFAULT_SHAPE_PADDING if dslShape == d2target.ShapeCircle || dslShape == d2target.ShapeSquare {
sideLength := DEFAULT_SHAPE_SIZE
if desiredWidth != 0 || desiredHeight != 0 {
sideLength = float64(go2.Max(desiredWidth, desiredHeight))
}
obj.Width = sideLength
obj.Height = sideLength
} else {
obj.Width = DEFAULT_SHAPE_SIZE
obj.Height = DEFAULT_SHAPE_SIZE
if desiredWidth != 0 { if desiredWidth != 0 {
obj.Width = float64(desiredWidth) obj.Width = float64(desiredWidth)
} }
if desiredHeight != 0 { if desiredHeight != 0 {
obj.Height = float64(desiredHeight) obj.Height = float64(desiredHeight)
} }
continue
} }
shapeType := strings.ToLower(obj.Attributes.Shape.Value) continue
}
labelDims, err := obj.GetLabelSize(mtexts, ruler, fontFamily) labelDims, err := obj.GetLabelSize(mtexts, ruler, fontFamily)
if err != nil { if err != nil {
return err return err
} }
obj.LabelDimensions = *labelDims
switch shapeType { switch dslShape {
case d2target.ShapeText, d2target.ShapeClass, d2target.ShapeSQLTable, d2target.ShapeCode: case d2target.ShapeText, d2target.ShapeClass, d2target.ShapeSQLTable, d2target.ShapeCode:
// no labels // no labels
default: default:
@ -1140,39 +1215,65 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
} }
} }
if shapeType != d2target.ShapeText && obj.Attributes.Label.Value != "" { // if there is a desired width or height, fit to content box without inner label padding for smallest minimum size
labelDims.Width += INNER_LABEL_PADDING withInnerLabelPadding := desiredWidth == 0 && desiredHeight == 0 &&
labelDims.Height += INNER_LABEL_PADDING dslShape != d2target.ShapeText && obj.Attributes.Label.Value != ""
} defaultDims, err := obj.GetDefaultSize(mtexts, ruler, fontFamily, *labelDims, withInnerLabelPadding)
obj.LabelDimensions = *labelDims
defaultDims, err := obj.GetDefaultSize(mtexts, ruler, fontFamily, *labelDims)
if err != nil { if err != nil {
return err return err
} }
obj.Width = float64(go2.Max(defaultDims.Width, desiredWidth)) if dslShape == d2target.ShapeImage {
obj.Height = float64(go2.Max(defaultDims.Height, desiredHeight)) if desiredWidth == 0 {
desiredWidth = defaultDims.Width
}
if desiredHeight == 0 {
desiredHeight = defaultDims.Height
}
obj.Width = float64(go2.Max(MIN_SHAPE_SIZE, desiredWidth))
obj.Height = float64(go2.Max(MIN_SHAPE_SIZE, desiredHeight))
// images don't need further processing
continue
}
paddingX, paddingY := obj.GetPadding() contentBox := geo.NewBox(geo.NewPoint(0, 0), float64(defaultDims.Width), float64(defaultDims.Height))
shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[dslShape]
s := shape.NewShape(shapeType, contentBox)
switch shapeType { paddingX, paddingY := s.GetDefaultPadding()
case d2target.ShapeSquare, d2target.ShapeCircle:
if desiredWidth != 0 || desiredHeight != 0 { if desiredWidth != 0 || desiredHeight != 0 {
paddingX = 0. paddingX = 0.
paddingY = 0. paddingY = 0.
} else {
// give shapes with icons extra padding to fit their label
if obj.Attributes.Icon != nil {
labelHeight := float64(labelDims.Height + INNER_LABEL_PADDING)
// Evenly pad enough to fit label above icon
paddingX += labelHeight
paddingY += labelHeight
}
switch shapeType {
case shape.TABLE_TYPE, shape.CLASS_TYPE, shape.CODE_TYPE, shape.IMAGE_TYPE:
default:
if obj.Attributes.Link != "" {
paddingX += 32
}
if obj.Attributes.Tooltip != "" {
paddingX += 32
}
}
} }
sideLength := math.Max(obj.Width+paddingX, obj.Height+paddingY) fitWidth, fitHeight := s.GetDimensionsToFit(contentBox.Width, contentBox.Height, paddingX, paddingY)
obj.Width = math.Max(float64(desiredWidth), fitWidth)
obj.Height = math.Max(float64(desiredHeight), fitHeight)
if s.AspectRatio1() {
sideLength := math.Max(obj.Width, obj.Height)
obj.Width = sideLength obj.Width = sideLength
obj.Height = sideLength obj.Height = sideLength
} else if desiredHeight == 0 || desiredWidth == 0 {
default: if s.GetType() == shape.PERSON_TYPE {
if desiredWidth == 0 { obj.Width, obj.Height = shape.LimitAR(obj.Width, obj.Height, shape.PERSON_AR_LIMIT)
obj.Width += float64(paddingX)
}
if desiredHeight == 0 {
obj.Height += float64(paddingY)
} }
} }
} }
@ -1252,19 +1353,17 @@ func (g *Graph) Texts() []*d2target.MText {
} }
func Key(k *d2ast.KeyPath) []string { func Key(k *d2ast.KeyPath) []string {
var ids []string return d2format.KeyPath(k)
for _, s := range k.Path {
// We format each string of the key to ensure the resulting strings can be parsed
// correctly.
n := &d2ast.KeyPath{
Path: []*d2ast.StringBox{d2ast.MakeValueBox(d2ast.RawString(s.Unbox().ScalarString(), true)).StringBox()},
}
ids = append(ids, d2format.Format(n))
}
return ids
} }
var ReservedKeywords = map[string]struct{}{ // All reserved keywords. See init below.
var ReservedKeywords map[string]struct{}
// All reserved keywords not including style keywords.
var ReservedKeywords2 map[string]struct{}
// Non Style/Holder keywords.
var SimpleReservedKeywords = map[string]struct{}{
"label": {}, "label": {},
"desc": {}, "desc": {},
"shape": {}, "shape": {},
@ -1331,15 +1430,88 @@ var NearConstantsArray = []string{
} }
var NearConstants map[string]struct{} var NearConstants map[string]struct{}
// BoardKeywords contains the keywords that create new boards.
var BoardKeywords = map[string]struct{}{
"layers": {},
"scenarios": {},
"steps": {},
}
func init() { func init() {
ReservedKeywords = make(map[string]struct{})
for k, v := range SimpleReservedKeywords {
ReservedKeywords[k] = v
}
for k, v := range StyleKeywords { for k, v := range StyleKeywords {
ReservedKeywords[k] = v ReservedKeywords[k] = v
} }
for k, v := range ReservedKeywordHolders { for k, v := range ReservedKeywordHolders {
ReservedKeywords[k] = v ReservedKeywords[k] = v
} }
for k, v := range BoardKeywords {
ReservedKeywords[k] = v
}
ReservedKeywords2 = make(map[string]struct{})
for k, v := range SimpleReservedKeywords {
ReservedKeywords2[k] = v
}
for k, v := range ReservedKeywordHolders {
ReservedKeywords2[k] = v
}
for k, v := range BoardKeywords {
ReservedKeywords2[k] = v
}
NearConstants = make(map[string]struct{}, len(NearConstantsArray)) NearConstants = make(map[string]struct{}, len(NearConstantsArray))
for _, k := range NearConstantsArray { for _, k := range NearConstantsArray {
NearConstants[k] = struct{}{} NearConstants[k] = struct{}{}
} }
} }
func (g *Graph) GetBoard(name string) *Graph {
for _, l := range g.Layers {
if l.Name == name {
return l
}
}
for _, l := range g.Scenarios {
if l.Name == name {
return l
}
}
for _, l := range g.Steps {
if l.Name == name {
return l
}
}
return nil
}
func (g *Graph) SortObjectsByAST() {
objects := append([]*Object(nil), g.Objects...)
sort.Slice(objects, func(i, j int) bool {
o1 := objects[i]
o2 := objects[j]
if len(o1.References) == 0 || len(o2.References) == 0 {
return i < j
}
r1 := o1.References[0]
r2 := o2.References[0]
return r1.Key.Path[r1.KeyPathIndex].Unbox().GetRange().Before(r2.Key.Path[r2.KeyPathIndex].Unbox().GetRange())
})
g.Objects = objects
}
func (g *Graph) SortEdgesByAST() {
edges := append([]*Edge(nil), g.Edges...)
sort.Slice(edges, func(i, j int) bool {
e1 := edges[i]
e2 := edges[j]
if len(e1.References) == 0 || len(e2.References) == 0 {
return i < j
}
return e1.References[0].Edge.Range.Before(e2.References[0].Edge.Range)
})
g.Edges = edges
}

View file

@ -3,7 +3,7 @@ package d2graph
import "oss.terrastruct.com/d2/d2target" import "oss.terrastruct.com/d2/d2target"
func (obj *Object) IsSequenceDiagram() bool { func (obj *Object) IsSequenceDiagram() bool {
return obj != nil && obj.Attributes.Shape.Value == d2target.ShapeSequenceDiagram return obj != nil && obj.Attributes != nil && obj.Attributes.Shape.Value == d2target.ShapeSequenceDiagram
} }
func (obj *Object) OuterSequenceDiagram() *Object { func (obj *Object) OuterSequenceDiagram() *Object {
@ -65,7 +65,7 @@ func (obj *Object) ContainsAnyObject(objects []*Object) bool {
func (o *Object) ContainedBy(obj *Object) bool { func (o *Object) ContainedBy(obj *Object) bool {
for _, ref := range o.References { for _, ref := range o.References {
curr := ref.UnresolvedScopeObj curr := ref.ScopeObj
for curr != nil { for curr != nil {
if curr == obj { if curr == obj {
return true return true

252
d2ir/compile.go Normal file
View file

@ -0,0 +1,252 @@
package d2ir
import (
"oss.terrastruct.com/d2/d2ast"
"oss.terrastruct.com/d2/d2parser"
)
type compiler struct {
err d2parser.ParseError
}
func (c *compiler) errorf(n d2ast.Node, f string, v ...interface{}) {
c.err.Errors = append(c.err.Errors, d2parser.Errorf(n, f, v...).(d2ast.Error))
}
func Compile(ast *d2ast.Map) (*Map, error) {
c := &compiler{}
m := &Map{}
m.initRoot()
m.parent.(*Field).References[0].Context.Scope = ast
c.compileMap(m, ast)
c.compileScenarios(m)
c.compileSteps(m)
if !c.err.Empty() {
return nil, c.err
}
return m, nil
}
func (c *compiler) compileScenarios(m *Map) {
scenariosf := m.GetField("scenarios")
if scenariosf == nil {
return
}
scenarios := scenariosf.Map()
if scenarios == nil {
return
}
for _, sf := range scenarios.Fields {
if sf.Map() == nil {
continue
}
base := m.CopyBase(sf)
OverlayMap(base, sf.Map())
sf.Composite = base
c.compileScenarios(sf.Map())
c.compileSteps(sf.Map())
}
}
func (c *compiler) compileSteps(m *Map) {
stepsf := m.GetField("steps")
if stepsf == nil {
return
}
steps := stepsf.Map()
if steps == nil {
return
}
for i, sf := range steps.Fields {
if sf.Map() == nil {
continue
}
var base *Map
if i == 0 {
base = m.CopyBase(sf)
} else {
base = steps.Fields[i-1].Map().CopyBase(sf)
}
OverlayMap(base, sf.Map())
sf.Composite = base
c.compileScenarios(sf.Map())
c.compileSteps(sf.Map())
}
}
func (c *compiler) compileMap(dst *Map, ast *d2ast.Map) {
for _, n := range ast.Nodes {
switch {
case n.MapKey != nil:
c.compileKey(&RefContext{
Key: n.MapKey,
Scope: ast,
ScopeMap: dst,
})
case n.Substitution != nil:
panic("TODO")
}
}
}
func (c *compiler) compileKey(refctx *RefContext) {
if len(refctx.Key.Edges) == 0 {
c.compileField(refctx.ScopeMap, refctx.Key.Key, refctx)
} else {
c.compileEdges(refctx)
}
}
func (c *compiler) compileField(dst *Map, kp *d2ast.KeyPath, refctx *RefContext) {
f, err := dst.EnsureField(kp, refctx)
if err != nil {
c.err.Errors = append(c.err.Errors, err.(d2ast.Error))
return
}
if refctx.Key.Primary.Unbox() != nil {
f.Primary_ = &Scalar{
parent: f,
Value: refctx.Key.Primary.Unbox(),
}
}
if refctx.Key.Value.Array != nil {
a := &Array{
parent: f,
}
c.compileArray(a, refctx.Key.Value.Array)
f.Composite = a
} else if refctx.Key.Value.Map != nil {
if f.Map() == nil {
f.Composite = &Map{
parent: f,
}
}
c.compileMap(f.Map(), refctx.Key.Value.Map)
} else if refctx.Key.Value.ScalarBox().Unbox() != nil {
f.Primary_ = &Scalar{
parent: f,
Value: refctx.Key.Value.ScalarBox().Unbox(),
}
}
}
func (c *compiler) compileEdges(refctx *RefContext) {
if refctx.Key.Key != nil {
f, err := refctx.ScopeMap.EnsureField(refctx.Key.Key, refctx)
if err != nil {
c.err.Errors = append(c.err.Errors, err.(d2ast.Error))
return
}
if _, ok := f.Composite.(*Array); ok {
c.errorf(refctx.Key.Key, "cannot index into array")
return
}
if f.Map() == nil {
f.Composite = &Map{
parent: f,
}
}
refctx.ScopeMap = f.Map()
}
eida := NewEdgeIDs(refctx.Key)
for i, eid := range eida {
refctx = refctx.Copy()
refctx.Edge = refctx.Key.Edges[i]
var e *Edge
if eid.Index != nil {
ea := refctx.ScopeMap.GetEdges(eid)
if len(ea) == 0 {
c.errorf(refctx.Edge, "indexed edge does not exist")
continue
}
e = ea[0]
e.References = append(e.References, &EdgeReference{
Context: refctx,
})
refctx.ScopeMap.appendFieldReferences(0, refctx.Edge.Src, refctx)
refctx.ScopeMap.appendFieldReferences(0, refctx.Edge.Dst, refctx)
} else {
_, err := refctx.ScopeMap.EnsureField(refctx.Edge.Src, refctx)
if err != nil {
c.err.Errors = append(c.err.Errors, err.(d2ast.Error))
continue
}
_, err = refctx.ScopeMap.EnsureField(refctx.Edge.Dst, refctx)
if err != nil {
c.err.Errors = append(c.err.Errors, err.(d2ast.Error))
continue
}
e, err = refctx.ScopeMap.CreateEdge(eid, refctx)
if err != nil {
c.err.Errors = append(c.err.Errors, err.(d2ast.Error))
continue
}
}
if refctx.Key.EdgeKey != nil {
if e.Map_ == nil {
e.Map_ = &Map{
parent: e,
}
}
c.compileField(e.Map_, refctx.Key.EdgeKey, refctx)
} else {
if refctx.Key.Primary.Unbox() != nil {
e.Primary_ = &Scalar{
parent: e,
Value: refctx.Key.Primary.Unbox(),
}
}
if refctx.Key.Value.Array != nil {
c.errorf(refctx.Key.Value.Unbox(), "edges cannot be assigned arrays")
continue
} else if refctx.Key.Value.Map != nil {
if e.Map_ == nil {
e.Map_ = &Map{
parent: e,
}
}
c.compileMap(e.Map_, refctx.Key.Value.Map)
} else if refctx.Key.Value.ScalarBox().Unbox() != nil {
e.Primary_ = &Scalar{
parent: e,
Value: refctx.Key.Value.ScalarBox().Unbox(),
}
}
}
}
}
func (c *compiler) compileArray(dst *Array, a *d2ast.Array) {
for _, an := range a.Nodes {
var irv Value
switch v := an.Unbox().(type) {
case *d2ast.Array:
ira := &Array{
parent: dst,
}
c.compileArray(ira, v)
irv = ira
case *d2ast.Map:
irm := &Map{
parent: dst,
}
c.compileMap(irm, v)
irv = irm
case d2ast.Scalar:
irv = &Scalar{
parent: dst,
Value: v,
}
case *d2ast.Substitution:
// panic("TODO")
}
dst.Values = append(dst.Values, irv)
}
}

476
d2ir/compile_test.go Normal file
View file

@ -0,0 +1,476 @@
package d2ir_test
import (
"fmt"
"math/big"
"path/filepath"
"strings"
"testing"
"oss.terrastruct.com/util-go/assert"
"oss.terrastruct.com/util-go/diff"
"oss.terrastruct.com/d2/d2ast"
"oss.terrastruct.com/d2/d2ir"
"oss.terrastruct.com/d2/d2parser"
)
func TestCompile(t *testing.T) {
t.Parallel()
t.Run("fields", testCompileFields)
t.Run("edges", testCompileEdges)
t.Run("layers", testCompileLayers)
t.Run("scenarios", testCompileScenarios)
t.Run("steps", testCompileSteps)
}
type testCase struct {
name string
run func(testing.TB)
}
func runa(t *testing.T, tca []testCase) {
for _, tc := range tca {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
tc.run(t)
})
}
}
func compile(t testing.TB, text string) (*d2ir.Map, error) {
t.Helper()
d2Path := fmt.Sprintf("%v.d2", t.Name())
ast, err := d2parser.Parse(d2Path, strings.NewReader(text), nil)
assert.Success(t, err)
m, err := d2ir.Compile(ast)
if err != nil {
return nil, err
}
err = diff.TestdataJSON(filepath.Join("..", "testdata", "d2ir", t.Name()), m)
if err != nil {
return nil, err
}
return m, nil
}
func assertQuery(t testing.TB, n d2ir.Node, nfields, nedges int, primary interface{}, idStr string) d2ir.Node {
t.Helper()
m := n.Map()
p := n.Primary()
if idStr != "" {
var err error
n, err = m.Query(idStr)
assert.Success(t, err)
assert.NotEqual(t, n, nil)
p = n.Primary()
m = n.Map()
}
assert.Equal(t, nfields, m.FieldCountRecursive())
assert.Equal(t, nedges, m.EdgeCountRecursive())
if !makeScalar(p).Equal(makeScalar(primary)) {
t.Fatalf("expected primary %#v but got %s", primary, p)
}
return n
}
func makeScalar(v interface{}) *d2ir.Scalar {
s := &d2ir.Scalar{}
switch v := v.(type) {
case *d2ir.Scalar:
if v == nil {
s.Value = &d2ast.Null{}
return s
}
return v
case bool:
s.Value = &d2ast.Boolean{
Value: v,
}
case float64:
bv := &big.Rat{}
bv.SetFloat64(v)
s.Value = &d2ast.Number{
Value: bv,
}
case int:
s.Value = &d2ast.Number{
Value: big.NewRat(int64(v), 1),
}
case string:
s.Value = d2ast.FlatDoubleQuotedString(v)
default:
if v != nil {
panic(fmt.Sprintf("d2ir: unexpected type to makeScalar: %#v", v))
}
s.Value = &d2ast.Null{}
}
return s
}
func testCompileFields(t *testing.T) {
t.Parallel()
tca := []testCase{
{
name: "root",
run: func(t testing.TB) {
m, err := compile(t, `x`)
assert.Success(t, err)
assertQuery(t, m, 1, 0, nil, "")
assertQuery(t, m, 0, 0, nil, "x")
},
},
{
name: "label",
run: func(t testing.TB) {
m, err := compile(t, `x: yes`)
assert.Success(t, err)
assertQuery(t, m, 1, 0, nil, "")
assertQuery(t, m, 0, 0, "yes", "x")
},
},
{
name: "nested",
run: func(t testing.TB) {
m, err := compile(t, `x.y: yes`)
assert.Success(t, err)
assertQuery(t, m, 2, 0, nil, "")
assertQuery(t, m, 1, 0, nil, "x")
assertQuery(t, m, 0, 0, "yes", "x.y")
},
},
{
name: "array",
run: func(t testing.TB) {
m, err := compile(t, `x: [1;2;3;4]`)
assert.Success(t, err)
assertQuery(t, m, 1, 0, nil, "")
f := assertQuery(t, m, 0, 0, nil, "x").(*d2ir.Field)
assert.String(t, `[1; 2; 3; 4]`, f.Composite.String())
},
},
{
name: "null",
run: func(t testing.TB) {
m, err := compile(t, `pq: pq
pq: null`)
assert.Success(t, err)
assertQuery(t, m, 1, 0, nil, "")
// null doesn't delete pq from *Map so that for language tooling
// we maintain the references.
// Instead d2compiler will ensure it doesn't get rendered.
assertQuery(t, m, 0, 0, nil, "pq")
},
},
}
runa(t, tca)
t.Run("primary", func(t *testing.T) {
t.Parallel()
tca := []testCase{
{
name: "root",
run: func(t testing.TB) {
m, err := compile(t, `x: yes { pqrs }`)
assert.Success(t, err)
assertQuery(t, m, 2, 0, nil, "")
assertQuery(t, m, 1, 0, "yes", "x")
assertQuery(t, m, 0, 0, nil, "x.pqrs")
},
},
{
name: "nested",
run: func(t testing.TB) {
m, err := compile(t, `x.y: yes { pqrs }`)
assert.Success(t, err)
assertQuery(t, m, 3, 0, nil, "")
assertQuery(t, m, 2, 0, nil, "x")
assertQuery(t, m, 1, 0, "yes", "x.y")
assertQuery(t, m, 0, 0, nil, "x.y.pqrs")
},
},
}
runa(t, tca)
})
}
func testCompileEdges(t *testing.T) {
t.Parallel()
tca := []testCase{
{
name: "root",
run: func(t testing.TB) {
m, err := compile(t, `x -> y`)
assert.Success(t, err)
assertQuery(t, m, 2, 1, nil, "")
assertQuery(t, m, 0, 0, nil, `(x -> y)[0]`)
assertQuery(t, m, 0, 0, nil, "x")
assertQuery(t, m, 0, 0, nil, "y")
},
},
{
name: "nested",
run: func(t testing.TB) {
m, err := compile(t, `x.y -> z.p`)
assert.Success(t, err)
assertQuery(t, m, 4, 1, nil, "")
assertQuery(t, m, 1, 0, nil, "x")
assertQuery(t, m, 0, 0, nil, "x.y")
assertQuery(t, m, 1, 0, nil, "z")
assertQuery(t, m, 0, 0, nil, "z.p")
assertQuery(t, m, 0, 0, nil, "(x.y -> z.p)[0]")
},
},
{
name: "underscore",
run: func(t testing.TB) {
m, err := compile(t, `p: { _.x -> z }`)
assert.Success(t, err)
assertQuery(t, m, 3, 1, nil, "")
assertQuery(t, m, 0, 0, nil, "x")
assertQuery(t, m, 1, 0, nil, "p")
assertQuery(t, m, 0, 0, nil, "(x -> p.z)[0]")
},
},
{
name: "chain",
run: func(t testing.TB) {
m, err := compile(t, `a -> b -> c -> d`)
assert.Success(t, err)
assertQuery(t, m, 4, 3, nil, "")
assertQuery(t, m, 0, 0, nil, "a")
assertQuery(t, m, 0, 0, nil, "b")
assertQuery(t, m, 0, 0, nil, "c")
assertQuery(t, m, 0, 0, nil, "d")
assertQuery(t, m, 0, 0, nil, "(a -> b)[0]")
assertQuery(t, m, 0, 0, nil, "(b -> c)[0]")
assertQuery(t, m, 0, 0, nil, "(c -> d)[0]")
},
},
}
runa(t, tca)
t.Run("errs", func(t *testing.T) {
t.Parallel()
tca := []testCase{
{
name: "bad_edge",
run: func(t testing.TB) {
_, err := compile(t, `(x -> y): { p -> q }`)
assert.ErrorString(t, err, `TestCompile/edges/errs/bad_edge.d2:1:13: cannot create edge inside edge`)
},
},
}
runa(t, tca)
})
}
func testCompileLayers(t *testing.T) {
t.Parallel()
tca := []testCase{
{
name: "root",
run: func(t testing.TB) {
m, err := compile(t, `x -> y
layers: {
bingo: { p.q.z }
}`)
assert.Success(t, err)
assertQuery(t, m, 7, 1, nil, "")
assertQuery(t, m, 0, 0, nil, `(x -> y)[0]`)
assertQuery(t, m, 0, 0, nil, "x")
assertQuery(t, m, 0, 0, nil, "y")
assertQuery(t, m, 3, 0, nil, "layers.bingo")
},
},
}
runa(t, tca)
t.Run("errs", func(t *testing.T) {
t.Parallel()
tca := []testCase{
{
name: "1/bad_edge",
run: func(t testing.TB) {
_, err := compile(t, `layers.x -> layers.y`)
assert.ErrorString(t, err, `TestCompile/layers/errs/1/bad_edge.d2:1:1: cannot create edges between boards`)
},
},
{
name: "2/bad_edge",
run: func(t testing.TB) {
_, err := compile(t, `layers -> scenarios`)
assert.ErrorString(t, err, `TestCompile/layers/errs/2/bad_edge.d2:1:1: edge with board keyword alone doesn't make sense`)
},
},
{
name: "3/bad_edge",
run: func(t testing.TB) {
_, err := compile(t, `layers.x.y -> steps.z.p`)
assert.ErrorString(t, err, `TestCompile/layers/errs/3/bad_edge.d2:1:1: cannot create edges between boards`)
},
},
{
name: "4/good_edge",
run: func(t testing.TB) {
_, err := compile(t, `layers.x.y -> layers.x.y`)
assert.Success(t, err)
},
},
}
runa(t, tca)
})
}
func testCompileScenarios(t *testing.T) {
t.Parallel()
tca := []testCase{
{
name: "root",
run: func(t testing.TB) {
m, err := compile(t, `x -> y
scenarios: {
bingo: { p.q.z }
nuclear: { quiche }
}`)
assert.Success(t, err)
assertQuery(t, m, 13, 3, nil, "")
assertQuery(t, m, 0, 0, nil, "x")
assertQuery(t, m, 0, 0, nil, "y")
assertQuery(t, m, 0, 0, nil, `(x -> y)[0]`)
assertQuery(t, m, 5, 1, nil, "scenarios.bingo")
assertQuery(t, m, 0, 0, nil, "scenarios.bingo.x")
assertQuery(t, m, 0, 0, nil, "scenarios.bingo.y")
assertQuery(t, m, 0, 0, nil, `scenarios.bingo.(x -> y)[0]`)
assertQuery(t, m, 2, 0, nil, "scenarios.bingo.p")
assertQuery(t, m, 1, 0, nil, "scenarios.bingo.p.q")
assertQuery(t, m, 0, 0, nil, "scenarios.bingo.p.q.z")
assertQuery(t, m, 3, 1, nil, "scenarios.nuclear")
assertQuery(t, m, 0, 0, nil, "scenarios.nuclear.x")
assertQuery(t, m, 0, 0, nil, "scenarios.nuclear.y")
assertQuery(t, m, 0, 0, nil, `scenarios.nuclear.(x -> y)[0]`)
assertQuery(t, m, 0, 0, nil, "scenarios.nuclear.quiche")
},
},
}
runa(t, tca)
}
func testCompileSteps(t *testing.T) {
t.Parallel()
tca := []testCase{
{
name: "root",
run: func(t testing.TB) {
m, err := compile(t, `x -> y
steps: {
bingo: { p.q.z }
nuclear: { quiche }
}`)
assert.Success(t, err)
assertQuery(t, m, 16, 3, nil, "")
assertQuery(t, m, 0, 0, nil, "x")
assertQuery(t, m, 0, 0, nil, "y")
assertQuery(t, m, 0, 0, nil, `(x -> y)[0]`)
assertQuery(t, m, 5, 1, nil, "steps.bingo")
assertQuery(t, m, 0, 0, nil, "steps.bingo.x")
assertQuery(t, m, 0, 0, nil, "steps.bingo.y")
assertQuery(t, m, 0, 0, nil, `steps.bingo.(x -> y)[0]`)
assertQuery(t, m, 2, 0, nil, "steps.bingo.p")
assertQuery(t, m, 1, 0, nil, "steps.bingo.p.q")
assertQuery(t, m, 0, 0, nil, "steps.bingo.p.q.z")
assertQuery(t, m, 6, 1, nil, "steps.nuclear")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.x")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.y")
assertQuery(t, m, 0, 0, nil, `steps.nuclear.(x -> y)[0]`)
assertQuery(t, m, 2, 0, nil, "steps.nuclear.p")
assertQuery(t, m, 1, 0, nil, "steps.nuclear.p.q")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.p.q.z")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.quiche")
},
},
{
name: "recursive",
run: func(t testing.TB) {
m, err := compile(t, `x -> y
steps: {
bingo: { p.q.z }
nuclear: {
quiche
scenarios: {
bavarian: {
perseverance
}
}
}
}`)
assert.Success(t, err)
assertQuery(t, m, 25, 4, nil, "")
assertQuery(t, m, 0, 0, nil, "x")
assertQuery(t, m, 0, 0, nil, "y")
assertQuery(t, m, 0, 0, nil, `(x -> y)[0]`)
assertQuery(t, m, 5, 1, nil, "steps.bingo")
assertQuery(t, m, 0, 0, nil, "steps.bingo.x")
assertQuery(t, m, 0, 0, nil, "steps.bingo.y")
assertQuery(t, m, 0, 0, nil, `steps.bingo.(x -> y)[0]`)
assertQuery(t, m, 2, 0, nil, "steps.bingo.p")
assertQuery(t, m, 1, 0, nil, "steps.bingo.p.q")
assertQuery(t, m, 0, 0, nil, "steps.bingo.p.q.z")
assertQuery(t, m, 15, 2, nil, "steps.nuclear")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.x")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.y")
assertQuery(t, m, 0, 0, nil, `steps.nuclear.(x -> y)[0]`)
assertQuery(t, m, 2, 0, nil, "steps.nuclear.p")
assertQuery(t, m, 1, 0, nil, "steps.nuclear.p.q")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.p.q.z")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.quiche")
assertQuery(t, m, 7, 1, nil, "steps.nuclear.scenarios.bavarian")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.scenarios.bavarian.x")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.scenarios.bavarian.y")
assertQuery(t, m, 0, 0, nil, `steps.nuclear.scenarios.bavarian.(x -> y)[0]`)
assertQuery(t, m, 2, 0, nil, "steps.nuclear.scenarios.bavarian.p")
assertQuery(t, m, 1, 0, nil, "steps.nuclear.scenarios.bavarian.p.q")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.scenarios.bavarian.p.q.z")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.scenarios.bavarian.quiche")
assertQuery(t, m, 0, 0, nil, "steps.nuclear.scenarios.bavarian.perseverance")
},
},
}
runa(t, tca)
}

1061
d2ir/d2ir.go Normal file

File diff suppressed because it is too large Load diff

69
d2ir/d2ir_test.go Normal file
View file

@ -0,0 +1,69 @@
package d2ir_test
import (
"testing"
"oss.terrastruct.com/util-go/assert"
"oss.terrastruct.com/d2/d2ast"
"oss.terrastruct.com/d2/d2ir"
)
func TestCopy(t *testing.T) {
t.Parallel()
const scalStr = `Those who claim the dead never return to life haven't ever been around.`
s := &d2ir.Scalar{
Value: d2ast.FlatUnquotedString(scalStr),
}
a := &d2ir.Array{
Values: []d2ir.Value{
&d2ir.Scalar{
Value: &d2ast.Boolean{
Value: true,
},
},
},
}
m2 := &d2ir.Map{
Fields: []*d2ir.Field{
{Primary_: s},
},
}
const keyStr = `Absence makes the heart grow frantic.`
f := &d2ir.Field{
Name: keyStr,
Primary_: s,
Composite: a,
}
e := &d2ir.Edge{
Primary_: s,
Map_: m2,
}
m := &d2ir.Map{
Fields: []*d2ir.Field{f},
Edges: []*d2ir.Edge{e},
}
m = m.Copy(nil).(*d2ir.Map)
f.Name = `Many a wife thinks her husband is the world's greatest lover.`
assert.Equal(t, m, m.Fields[0].Parent())
assert.Equal(t, keyStr, m.Fields[0].Name)
assert.Equal(t, m.Fields[0], m.Fields[0].Primary_.Parent())
assert.Equal(t, m.Fields[0], m.Fields[0].Composite.(*d2ir.Array).Parent())
assert.Equal(t,
m.Fields[0].Composite,
m.Fields[0].Composite.(*d2ir.Array).Values[0].(*d2ir.Scalar).Parent(),
)
assert.Equal(t, m, m.Edges[0].Parent())
assert.Equal(t, m.Edges[0], m.Edges[0].Primary_.Parent())
assert.Equal(t, m.Edges[0], m.Edges[0].Map_.Parent())
assert.Equal(t, m.Edges[0].Map_, m.Edges[0].Map_.Fields[0].Parent())
assert.Equal(t, m.Edges[0].Map_.Fields[0], m.Edges[0].Map_.Fields[0].Primary_.Parent())
}

52
d2ir/merge.go Normal file
View file

@ -0,0 +1,52 @@
package d2ir
func OverlayMap(base, overlay *Map) {
for _, of := range overlay.Fields {
bf := base.GetField(of.Name)
if bf == nil {
base.Fields = append(base.Fields, of.Copy(base).(*Field))
continue
}
OverlayField(bf, of)
}
for _, oe := range overlay.Edges {
bea := base.GetEdges(oe.ID)
if len(bea) == 0 {
base.Edges = append(base.Edges, oe.Copy(base).(*Edge))
continue
}
be := bea[0]
OverlayEdge(be, oe)
}
}
func OverlayField(bf, of *Field) {
if of.Primary_ != nil {
bf.Primary_ = of.Primary_.Copy(bf).(*Scalar)
}
if of.Composite != nil {
if bf.Map() != nil && of.Map() != nil {
OverlayMap(bf.Map(), of.Map())
} else {
bf.Composite = of.Composite.Copy(bf).(*Map)
}
}
bf.References = append(bf.References, of.References...)
}
func OverlayEdge(be, oe *Edge) {
if oe.Primary_ != nil {
be.Primary_ = oe.Primary_.Copy(be).(*Scalar)
}
if oe.Map_ != nil {
if be.Map_ != nil {
OverlayMap(be.Map(), oe.Map_)
} else {
be.Map_ = oe.Map_.Copy(be).(*Map)
}
}
be.References = append(be.References, oe.References...)
}

62
d2ir/query.go Normal file
View file

@ -0,0 +1,62 @@
package d2ir
import (
"fmt"
"oss.terrastruct.com/d2/d2parser"
)
// QueryAll is only for tests and debugging.
func (m *Map) QueryAll(idStr string) (na []Node, _ error) {
k, err := d2parser.ParseMapKey(idStr)
if err != nil {
return nil, err
}
if k.Key != nil {
f := m.GetField(k.Key.IDA()...)
if f == nil {
return nil, nil
}
if len(k.Edges) == 0 {
na = append(na, f)
return na, nil
}
m = f.Map()
if m == nil {
return nil, nil
}
}
eida := NewEdgeIDs(k)
for _, eid := range eida {
ea := m.GetEdges(eid)
for _, e := range ea {
if k.EdgeKey == nil {
na = append(na, e)
} else if e.Map_ != nil {
f := e.Map_.GetField(k.EdgeKey.IDA()...)
if f != nil {
na = append(na, f)
}
}
}
}
return na, nil
}
// Query is only for tests and debugging.
func (m *Map) Query(idStr string) (Node, error) {
na, err := m.QueryAll(idStr)
if err != nil {
return nil, err
}
if len(na) == 0 {
return nil, nil
}
if len(na) > 1 {
return nil, fmt.Errorf("expected only one query result but got: %#v", err)
}
return na[0], nil
}

View file

@ -5,11 +5,12 @@ import (
"sort" "sort"
"strings" "strings"
"oss.terrastruct.com/util-go/go2"
"oss.terrastruct.com/d2/d2graph" "oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2target" "oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/lib/geo" "oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/label" "oss.terrastruct.com/d2/lib/label"
"oss.terrastruct.com/util-go/go2"
) )
func WithoutSequenceDiagrams(ctx context.Context, g *d2graph.Graph) (map[string]*sequenceDiagram, map[string]int, map[string]int, error) { func WithoutSequenceDiagrams(ctx context.Context, g *d2graph.Graph) (map[string]*sequenceDiagram, map[string]int, map[string]int, error) {
@ -113,6 +114,7 @@ func layoutSequenceDiagram(g *d2graph.Graph, obj *d2graph.Object) (*sequenceDiag
func getLayoutEdges(g *d2graph.Graph, toRemove map[*d2graph.Edge]struct{}) ([]*d2graph.Edge, map[string]int) { func getLayoutEdges(g *d2graph.Graph, toRemove map[*d2graph.Edge]struct{}) ([]*d2graph.Edge, map[string]int) {
edgeOrder := make(map[string]int) edgeOrder := make(map[string]int)
layoutEdges := make([]*d2graph.Edge, 0, len(g.Edges)-len(toRemove)) layoutEdges := make([]*d2graph.Edge, 0, len(g.Edges)-len(toRemove))
for i, edge := range g.Edges { for i, edge := range g.Edges {
edgeOrder[edge.AbsID()] = i edgeOrder[edge.AbsID()] = i
if _, exists := toRemove[edge]; !exists { if _, exists := toRemove[edge]; !exists {

View file

@ -377,7 +377,7 @@ container -> c: edge 1
} }
func TestSelfEdges(t *testing.T) { func TestSelfEdges(t *testing.T) {
g := d2graph.NewGraph(nil) g := d2graph.NewGraph()
g.Root.Attributes.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram} g.Root.Attributes.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram}
n1 := g.Root.EnsureChild([]string{"n1"}) n1 := g.Root.EnsureChild([]string{"n1"})
n1.Box = geo.NewBox(nil, 100, 100) n1.Box = geo.NewBox(nil, 100, 100)
@ -387,7 +387,7 @@ func TestSelfEdges(t *testing.T) {
Src: n1, Src: n1,
Dst: n1, Dst: n1,
Index: 0, Index: 0,
Attributes: d2graph.Attributes{ Attributes: &d2graph.Attributes{
Label: d2graph.Scalar{Value: "left to right"}, Label: d2graph.Scalar{Value: "left to right"},
}, },
}, },
@ -413,11 +413,11 @@ func TestSelfEdges(t *testing.T) {
} }
func TestSequenceToDescendant(t *testing.T) { func TestSequenceToDescendant(t *testing.T) {
g := d2graph.NewGraph(nil) g := d2graph.NewGraph()
g.Root.Attributes.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram} g.Root.Attributes.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram}
a := g.Root.EnsureChild([]string{"a"}) a := g.Root.EnsureChild([]string{"a"})
a.Box = geo.NewBox(nil, 100, 100) a.Box = geo.NewBox(nil, 100, 100)
a.Attributes = d2graph.Attributes{ a.Attributes = &d2graph.Attributes{
Shape: d2graph.Scalar{Value: shape.PERSON_TYPE}, Shape: d2graph.Scalar{Value: shape.PERSON_TYPE},
} }
a_t1 := a.EnsureChild([]string{"t1"}) a_t1 := a.EnsureChild([]string{"t1"})
@ -428,10 +428,12 @@ func TestSequenceToDescendant(t *testing.T) {
Src: a, Src: a,
Dst: a_t1, Dst: a_t1,
Index: 0, Index: 0,
Attributes: &d2graph.Attributes{},
}, { }, {
Src: a_t1, Src: a_t1,
Dst: a, Dst: a,
Index: 0, Index: 0,
Attributes: &d2graph.Attributes{},
}, },
} }

View file

@ -105,6 +105,12 @@ func newSequenceDiagram(objects []*d2graph.Object, messages []*d2graph.Edge) *se
sd.objectRank[actor] = rank sd.objectRank[actor] = rank
if actor.Width < MIN_ACTOR_WIDTH { if actor.Width < MIN_ACTOR_WIDTH {
dslShape := strings.ToLower(actor.Attributes.Shape.Value)
switch dslShape {
case d2target.ShapePerson, d2target.ShapeSquare, d2target.ShapeCircle:
// scale shape up to min width uniformly
actor.Height *= MIN_ACTOR_WIDTH / actor.Width
}
actor.Width = MIN_ACTOR_WIDTH actor.Width = MIN_ACTOR_WIDTH
} }
sd.maxActorHeight = math.Max(sd.maxActorHeight, actor.Height) sd.maxActorHeight = math.Max(sd.maxActorHeight, actor.Height)
@ -225,7 +231,7 @@ func (sd *sequenceDiagram) placeGroup(group *d2graph.Object) {
for _, n := range sd.notes { for _, n := range sd.notes {
inGroup := false inGroup := false
for _, ref := range n.References { for _, ref := range n.References {
curr := ref.UnresolvedScopeObj curr := ref.ScopeObj
for curr != nil { for curr != nil {
if curr == group { if curr == group {
inGroup = true inGroup = true
@ -324,7 +330,7 @@ func (sd *sequenceDiagram) addLifelineEdges() {
actorLifelineEnd := actor.Center() actorLifelineEnd := actor.Center()
actorLifelineEnd.Y = endY actorLifelineEnd.Y = endY
sd.lifelines = append(sd.lifelines, &d2graph.Edge{ sd.lifelines = append(sd.lifelines, &d2graph.Edge{
Attributes: d2graph.Attributes{ Attributes: &d2graph.Attributes{
Style: d2graph.Style{ Style: d2graph.Style{
StrokeDash: &d2graph.Scalar{Value: fmt.Sprintf("%d", LIFELINE_STROKE_DASH)}, StrokeDash: &d2graph.Scalar{Value: fmt.Sprintf("%d", LIFELINE_STROKE_DASH)},
StrokeWidth: &d2graph.Scalar{Value: fmt.Sprintf("%d", LIFELINE_STROKE_WIDTH)}, StrokeWidth: &d2graph.Scalar{Value: fmt.Sprintf("%d", LIFELINE_STROKE_WIDTH)},

View file

@ -44,32 +44,65 @@ func Compile(ctx context.Context, input string, opts *CompileOptions) (*d2target
return nil, nil, err return nil, nil, err
} }
if len(g.Objects) > 0 { d, err := compile(ctx, g, opts)
err = g.SetDimensions(opts.MeasuredTexts, opts.Ruler, opts.FontFamily)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
return d, g, nil
}
func compile(ctx context.Context, g *d2graph.Graph, opts *CompileOptions) (*d2target.Diagram, error) {
if len(g.Objects) > 0 {
err := g.SetDimensions(opts.MeasuredTexts, opts.Ruler, opts.FontFamily)
if err != nil {
return nil, err
}
coreLayout, err := getLayout(opts) coreLayout, err := getLayout(opts)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
constantNears := d2near.WithoutConstantNears(ctx, g) constantNears := d2near.WithoutConstantNears(ctx, g)
err = d2sequence.Layout(ctx, g, coreLayout) err = d2sequence.Layout(ctx, g, coreLayout)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
err = d2near.Layout(ctx, g, constantNears) err = d2near.Layout(ctx, g, constantNears)
if err != nil { if err != nil {
return nil, nil, err return nil, err
} }
} }
diagram, err := d2exporter.Export(ctx, g, opts.ThemeID, opts.FontFamily) d, err := d2exporter.Export(ctx, g, opts.ThemeID, opts.FontFamily)
return diagram, g, err if err != nil {
return nil, err
}
for _, l := range g.Layers {
ld, err := compile(ctx, l, opts)
if err != nil {
return nil, err
}
d.Layers = append(d.Layers, ld)
}
for _, l := range g.Scenarios {
ld, err := compile(ctx, l, opts)
if err != nil {
return nil, err
}
d.Scenarios = append(d.Scenarios, ld)
}
for _, l := range g.Steps {
ld, err := compile(ctx, l, opts)
if err != nil {
return nil, err
}
d.Steps = append(d.Steps, ld)
}
return d, nil
} }
func getLayout(opts *CompileOptions) (func(context.Context, *d2graph.Graph) error, error) { func getLayout(opts *CompileOptions) (func(context.Context, *d2graph.Graph) error, error) {

View file

@ -396,7 +396,6 @@ func Delete(g *d2graph.Graph, key string) (_ *d2graph.Graph, err error) {
if g != g2 { if g != g2 {
return g2, nil return g2, nil
} }
g = g2
if len(mk.Edges) == 1 { if len(mk.Edges) == 1 {
obj := g.Root obj := g.Root
@ -1109,7 +1108,7 @@ func move(g *d2graph.Graph, key, newKey string) (*d2graph.Graph, error) {
Key: detachedMK.Key, Key: detachedMK.Key,
MapKey: detachedMK, MapKey: detachedMK,
Scope: mostNestedRef.Scope, Scope: mostNestedRef.Scope,
}, mostNestedRef.UnresolvedScopeObj) }, mostNestedRef.ScopeObj)
} }
} }
@ -1284,8 +1283,8 @@ func move(g *d2graph.Graph, key, newKey string) (*d2graph.Graph, error) {
// We don't want this to be underscore-resolved scope. We want to ignore underscores // We don't want this to be underscore-resolved scope. We want to ignore underscores
var scopeak []string var scopeak []string
if ref.UnresolvedScopeObj != g.Root { if ref.ScopeObj != g.Root {
scopek, err := d2parser.ParseKey(ref.UnresolvedScopeObj.AbsID()) scopek, err := d2parser.ParseKey(ref.ScopeObj.AbsID())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1373,12 +1373,12 @@ more.(ok.q.z -> p.k): "furbling, v.:"
{ {
name: "complex_edge_1", name: "complex_edge_1",
text: `a.b.(x -> y).q.z text: `a.b.(x -> y).style.animated
`, `,
key: "a.b", key: "a.b",
newName: "ooo", newName: "ooo",
exp: `a.ooo.(x -> y).q.z exp: `a.ooo.(x -> y).style.animated
`, `,
assertions: func(t *testing.T, g *d2graph.Graph) { assertions: func(t *testing.T, g *d2graph.Graph) {
if len(g.Objects) != 4 { if len(g.Objects) != 4 {
@ -1392,12 +1392,12 @@ more.(ok.q.z -> p.k): "furbling, v.:"
{ {
name: "complex_edge_2", name: "complex_edge_2",
text: `a.b.(x -> y).q.z text: `a.b.(x -> y).style.animated
`, `,
key: "a.b.x", key: "a.b.x",
newName: "papa", newName: "papa",
exp: `a.b.(papa -> y).q.z exp: `a.b.(papa -> y).style.animated
`, `,
assertions: func(t *testing.T, g *d2graph.Graph) { assertions: func(t *testing.T, g *d2graph.Graph) {
if len(g.Objects) != 4 { if len(g.Objects) != 4 {
@ -1454,12 +1454,12 @@ more.(ok.q.z -> p.k): "furbling, v.:"
{ {
name: "arrows_complex", name: "arrows_complex",
text: `a.b.(x -- y).q.z text: `a.b.(x -- y).style.animated
`, `,
key: "a.b.(x -- y)[0]", key: "a.b.(x -- y)[0]",
newName: "(x <-> y)[0]", newName: "(x <-> y)[0]",
exp: `a.b.(x <-> y).q.z exp: `a.b.(x <-> y).style.animated
`, `,
assertions: func(t *testing.T, g *d2graph.Graph) { assertions: func(t *testing.T, g *d2graph.Graph) {
if len(g.Objects) != 4 { if len(g.Objects) != 4 {
@ -3025,7 +3025,7 @@ d
if err == nil { if err == nil {
objectsAfter := len(g.Objects) objectsAfter := len(g.Objects)
if objectsBefore != objectsAfter { if objectsBefore != objectsAfter {
println(d2format.Format(g.AST)) t.Log(d2format.Format(g.AST))
return nil, fmt.Errorf("move cannot destroy or create objects: found %d objects before and %d objects after", objectsBefore, objectsAfter) return nil, fmt.Errorf("move cannot destroy or create objects: found %d objects before and %d objects after", objectsBefore, objectsAfter)
} }
} }

View file

@ -45,7 +45,7 @@ func Parse(path string, r io.RuneReader, opts *ParseOptions) (*d2ast.Map, error)
} }
m := p.parseMap(true) m := p.parseMap(true)
if !p.err.empty() { if !p.err.Empty() {
return m, p.err return m, p.err
} }
return m, nil return m, nil
@ -57,7 +57,7 @@ func ParseKey(key string) (*d2ast.KeyPath, error) {
} }
k := p.parseKey() k := p.parseKey()
if !p.err.empty() { if !p.err.Empty() {
return nil, fmt.Errorf("failed to parse key %q: %w", key, p.err) return nil, fmt.Errorf("failed to parse key %q: %w", key, p.err)
} }
if k == nil { if k == nil {
@ -72,7 +72,7 @@ func ParseMapKey(mapKey string) (*d2ast.Key, error) {
} }
mk := p.parseMapKey() mk := p.parseMapKey()
if !p.err.empty() { if !p.err.Empty() {
return nil, fmt.Errorf("failed to parse map key %q: %w", mapKey, p.err) return nil, fmt.Errorf("failed to parse map key %q: %w", mapKey, p.err)
} }
if mk == nil { if mk == nil {
@ -87,7 +87,7 @@ func ParseValue(value string) (d2ast.Value, error) {
} }
v := p.parseValue() v := p.parseValue()
if !p.err.empty() { if !p.err.Empty() {
return nil, fmt.Errorf("failed to parse value %q: %w", value, p.err) return nil, fmt.Errorf("failed to parse value %q: %w", value, p.err)
} }
if v.Unbox() == nil { if v.Unbox() == nil {
@ -130,7 +130,16 @@ type ParseError struct {
Errors []d2ast.Error `json:"errs"` Errors []d2ast.Error `json:"errs"`
} }
func (pe ParseError) empty() bool { func Errorf(n d2ast.Node, f string, v ...interface{}) error {
f = "%v: " + f
v = append([]interface{}{n.GetRange()}, v...)
return d2ast.Error{
Range: n.GetRange(),
Message: fmt.Sprintf(f, v...),
}
}
func (pe ParseError) Empty() bool {
return pe.IOError == nil && len(pe.Errors) == 0 return pe.IOError == nil && len(pe.Errors) == 0
} }
@ -138,11 +147,12 @@ func (pe ParseError) Error() string {
var sb strings.Builder var sb strings.Builder
if pe.IOError != nil { if pe.IOError != nil {
sb.WriteString(pe.IOError.Error()) sb.WriteString(pe.IOError.Error())
}
for i, err := range pe.Errors {
if pe.IOError != nil || i > 0 {
sb.WriteByte('\n') sb.WriteByte('\n')
} }
for _, err := range pe.Errors {
sb.WriteString(err.Error()) sb.WriteString(err.Error())
sb.WriteByte('\n')
} }
return sb.String() return sb.String()
} }

View file

@ -63,7 +63,7 @@ func TestSketch(t *testing.T) {
} }
People discovery: "People discovery \nservice" People discovery: "People discovery \nservice"
admixer: Ad mixer { admixer: Ad mixer {
fill: "#c1a2f3" style.fill: "#c1a2f3"
} }
onboarding service: "Onboarding \nservice" onboarding service: "Onboarding \nservice"
@ -107,7 +107,7 @@ Android: {
web -> twitter fe web -> twitter fe
timeline scorer: "Timeline\nScorer" { timeline scorer: "Timeline\nScorer" {
fill: "#ffdef1" style.fill "#ffdef1"
} }
home ranker: Home Ranker home ranker: Home Ranker
@ -119,7 +119,7 @@ timeline mixer -> home ranker: {
} }
timeline mixer -> timeline service timeline mixer -> timeline service
home mixer: Home mixer { home mixer: Home mixer {
# fill: "#c1a2f3" # style.fill "#c1a2f3"
} }
container0.graphql -> home mixer: { container0.graphql -> home mixer: {
style.stroke-dash: 4 style.stroke-dash: 4
@ -146,7 +146,7 @@ prediction service2: Prediction Service {
icon: https://cdn-icons-png.flaticon.com/512/6461/6461819.png icon: https://cdn-icons-png.flaticon.com/512/6461/6461819.png
} }
home scorer: Home Scorer { home scorer: Home Scorer {
fill: "#ffdef1" style.fill "#ffdef1"
} }
manhattan: Manhattan manhattan: Manhattan
memcache: Memcache { memcache: Memcache {
@ -154,15 +154,15 @@ memcache: Memcache {
} }
fetch: Fetch { fetch: Fetch {
multiple: true style.multiple: true
shape: step shape: step
} }
feature: Feature { feature: Feature {
multiple: true style.multiple: true
shape: step shape: step
} }
scoring: Scoring { scoring: Scoring {
multiple: true style.multiple: true
shape: step shape: step
} }
fetch -> feature fetch -> feature

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 271 KiB

After

Width:  |  Height:  |  Size: 267 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 253 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 304 KiB

After

Width:  |  Height:  |  Size: 303 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 196 KiB

After

Width:  |  Height:  |  Size: 196 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 248 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 196 KiB

After

Width:  |  Height:  |  Size: 196 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 246 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 310 KiB

After

Width:  |  Height:  |  Size: 309 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 388 KiB

After

Width:  |  Height:  |  Size: 387 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 803 KiB

After

Width:  |  Height:  |  Size: 803 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 651 KiB

After

Width:  |  Height:  |  Size: 651 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 650 KiB

After

Width:  |  Height:  |  Size: 650 KiB

View file

@ -42,7 +42,7 @@ const (
appendixIconRadius = 16 appendixIconRadius = 16
) )
var multipleOffset = geo.NewVector(10, -10) var multipleOffset = geo.NewVector(d2target.MULTIPLE_OFFSET, -d2target.MULTIPLE_OFFSET)
//go:embed tooltip.svg //go:embed tooltip.svg
var TooltipIcon string var TooltipIcon string
@ -734,7 +734,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
var multipleTL *geo.Point var multipleTL *geo.Point
if targetShape.Multiple { if targetShape.Multiple {
multipleTL = tl.AddVector(geo.NewVector(d2target.MULTIPLE_OFFSET, -d2target.MULTIPLE_OFFSET)) multipleTL = tl.AddVector(multipleOffset)
} }
switch targetShape.Type { switch targetShape.Type {
@ -744,13 +744,13 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
if err != nil { if err != nil {
return "", err return "", err
} }
fmt.Fprintf(writer, out) fmt.Fprint(writer, out)
} else { } else {
drawClass(writer, targetShape) drawClass(writer, targetShape)
} }
addAppendixItems(writer, targetShape) addAppendixItems(writer, targetShape)
fmt.Fprintf(writer, `</g>`) fmt.Fprint(writer, `</g>`)
fmt.Fprintf(writer, closingTag) fmt.Fprint(writer, closingTag)
return labelMask, nil return labelMask, nil
case d2target.ShapeSQLTable: case d2target.ShapeSQLTable:
if sketchRunner != nil { if sketchRunner != nil {
@ -758,13 +758,13 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
if err != nil { if err != nil {
return "", err return "", err
} }
fmt.Fprintf(writer, out) fmt.Fprint(writer, out)
} else { } else {
drawTable(writer, targetShape) drawTable(writer, targetShape)
} }
addAppendixItems(writer, targetShape) addAppendixItems(writer, targetShape)
fmt.Fprintf(writer, `</g>`) fmt.Fprint(writer, `</g>`)
fmt.Fprintf(writer, closingTag) fmt.Fprint(writer, closingTag)
return labelMask, nil return labelMask, nil
case d2target.ShapeOval: case d2target.ShapeOval:
if targetShape.DoubleBorder { if targetShape.DoubleBorder {
@ -776,7 +776,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
if err != nil { if err != nil {
return "", err return "", err
} }
fmt.Fprintf(writer, out) fmt.Fprint(writer, out)
} else { } else {
fmt.Fprint(writer, renderDoubleOval(tl, width, height, style)) fmt.Fprint(writer, renderDoubleOval(tl, width, height, style))
} }
@ -789,7 +789,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
if err != nil { if err != nil {
return "", err return "", err
} }
fmt.Fprintf(writer, out) fmt.Fprint(writer, out)
} else { } else {
fmt.Fprint(writer, renderOval(tl, width, height, style)) fmt.Fprint(writer, renderOval(tl, width, height, style))
} }
@ -815,7 +815,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
if err != nil { if err != nil {
return "", err return "", err
} }
fmt.Fprintf(writer, out) fmt.Fprint(writer, out)
} else { } else {
fmt.Fprintf(writer, `<rect x="%d" y="%d" width="%d" height="%d" style="%s" />`, fmt.Fprintf(writer, `<rect x="%d" y="%d" width="%d" height="%d" style="%s" />`,
targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style) targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style)
@ -832,7 +832,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
if err != nil { if err != nil {
return "", err return "", err
} }
fmt.Fprintf(writer, out) fmt.Fprint(writer, out)
} else { } else {
fmt.Fprintf(writer, `<rect x="%d" y="%d" width="%d" height="%d" style="%s" />`, fmt.Fprintf(writer, `<rect x="%d" y="%d" width="%d" height="%d" style="%s" />`,
targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style) targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style)
@ -855,7 +855,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
if err != nil { if err != nil {
return "", err return "", err
} }
fmt.Fprintf(writer, out) fmt.Fprint(writer, out)
} else { } else {
for _, pathData := range s.GetSVGPathData() { for _, pathData := range s.GetSVGPathData() {
fmt.Fprintf(writer, `<path d="%s" style="%s"/>`, pathData, style) fmt.Fprintf(writer, `<path d="%s" style="%s"/>`, pathData, style)
@ -864,7 +864,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
} }
// Closes the class=shape // Closes the class=shape
fmt.Fprintf(writer, `</g>`) fmt.Fprint(writer, `</g>`)
if targetShape.Icon != nil && targetShape.Type != d2target.ShapeImage { if targetShape.Icon != nil && targetShape.Type != d2target.ShapeImage {
iconPosition := label.Position(targetShape.IconPosition) iconPosition := label.Position(targetShape.IconPosition)
@ -895,7 +895,10 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
} else { } else {
box = s.GetInnerBox() box = s.GetInnerBox()
} }
labelTL := labelPosition.GetPointOnBox(box, label.PADDING, float64(targetShape.LabelWidth), float64(targetShape.LabelHeight)) labelTL := labelPosition.GetPointOnBox(box, label.PADDING,
float64(targetShape.LabelWidth),
float64(targetShape.LabelHeight),
)
fontClass := "text" fontClass := "text"
if targetShape.Bold { if targetShape.Bold {
@ -932,7 +935,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
fmt.Fprintf(writer, `<rect class="shape" width="%d" height="%d" style="%s" />`, fmt.Fprintf(writer, `<rect class="shape" width="%d" height="%d" style="%s" />`,
targetShape.Width, targetShape.Height, containerStyle) targetShape.Width, targetShape.Height, containerStyle)
// Padding // Padding
fmt.Fprintf(writer, `<g transform="translate(6 6)">`) fmt.Fprint(writer, `<g transform="translate(6 6)">`)
for index, tokens := range chroma.SplitTokensIntoLines(iterator.Tokens()) { for index, tokens := range chroma.SplitTokensIntoLines(iterator.Tokens()) {
// TODO mono font looks better with 1.2 em (use px equivalent), but textmeasure needs to account for it. Not obvious how that should be done // TODO mono font looks better with 1.2 em (use px equivalent), but textmeasure needs to account for it. Not obvious how that should be done
@ -947,7 +950,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
} }
fmt.Fprint(writer, "</text>") fmt.Fprint(writer, "</text>")
} }
fmt.Fprintf(writer, "</g></g>") fmt.Fprint(writer, "</g></g>")
} else if targetShape.Type == d2target.ShapeText && targetShape.Language == "latex" { } else if targetShape.Type == d2target.ShapeText && targetShape.Language == "latex" {
render, err := d2latex.Render(targetShape.Label) render, err := d2latex.Render(targetShape.Label)
if err != nil { if err != nil {
@ -955,7 +958,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
} }
fmt.Fprintf(writer, `<g transform="translate(%f %f)">`, box.TopLeft.X, box.TopLeft.Y) fmt.Fprintf(writer, `<g transform="translate(%f %f)">`, box.TopLeft.X, box.TopLeft.Y)
fmt.Fprint(writer, render) fmt.Fprint(writer, render)
fmt.Fprintf(writer, "</g>") fmt.Fprint(writer, "</g>")
} else if targetShape.Type == d2target.ShapeText && targetShape.Language != "" { } else if targetShape.Type == d2target.ShapeText && targetShape.Language != "" {
render, err := textmeasure.RenderMarkdown(targetShape.Label) render, err := textmeasure.RenderMarkdown(targetShape.Label)
if err != nil { if err != nil {
@ -1000,7 +1003,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
addAppendixItems(writer, targetShape) addAppendixItems(writer, targetShape)
fmt.Fprintf(writer, closingTag) fmt.Fprint(writer, closingTag)
return labelMask, nil return labelMask, nil
} }
@ -1268,7 +1271,7 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
fmt.Fprintf(buf, `<style type="text/css">%s</style>`, mdCSS) fmt.Fprintf(buf, `<style type="text/css">%s</style>`, mdCSS)
} }
if sketchRunner != nil { if sketchRunner != nil {
fmt.Fprintf(buf, d2sketch.DefineFillPattern()) fmt.Fprint(buf, d2sketch.DefineFillPattern())
} }
// only define shadow filter if a shape uses it // only define shadow filter if a shape uses it

View file

@ -9,6 +9,9 @@ import (
const ( const (
PrefixPadding = 10 PrefixPadding = 10
PrefixWidth = 20 PrefixWidth = 20
CenterPadding = 50
// 10px of padding top and bottom so text doesn't look squished
VerticalPadding = 20
) )
type Class struct { type Class struct {

View file

@ -37,6 +37,10 @@ type Diagram struct {
Shapes []Shape `json:"shapes"` Shapes []Shape `json:"shapes"`
Connections []Connection `json:"connections"` Connections []Connection `json:"connections"`
Layers []*Diagram `json:"layers,omitempty"`
Scenarios []*Diagram `json:"scenarios,omitempty"`
Steps []*Diagram `json:"steps,omitempty"`
} }
func (diagram Diagram) HashID() (string, error) { func (diagram Diagram) HashID() (string, error) {
@ -547,19 +551,19 @@ func (s *Shape) GetIconSize(box *geo.Box) int {
if iconPosition == label.InsideMiddleCenter { if iconPosition == label.InsideMiddleCenter {
size = halfMinDimension size = halfMinDimension
} else { } else {
size = go2.IntMin( size = go2.Min(
minDimension, minDimension,
go2.IntMax(DEFAULT_ICON_SIZE, halfMinDimension), go2.Max(DEFAULT_ICON_SIZE, halfMinDimension),
) )
} }
size = go2.IntMin(size, MAX_ICON_SIZE) size = go2.Min(size, MAX_ICON_SIZE)
if !iconPosition.IsOutside() { if !iconPosition.IsOutside() {
size = go2.IntMin(size, size = go2.Min(size,
go2.IntMin( go2.Min(
go2.IntMax(int(box.Width)-2*label.PADDING, 0), go2.Max(int(box.Width)-2*label.PADDING, 0),
go2.IntMax(int(box.Height)-2*label.PADDING, 0), go2.Max(int(box.Height)-2*label.PADDING, 0),
), ),
) )
} }

View file

@ -17,6 +17,6 @@ If a change results in test diffs, you can run this script to generate a visual
report with the old vs new renders. report with the old vs new renders.
``` ```
go run ./e2etests/report/main.go go run ./e2etests/report/main.go -delta
open ./e2etests/out/e2e_report.html open ./e2etests/out/e2e_report.html
``` ```

View file

@ -12,7 +12,7 @@ import (
"cdr.dev/slog" "cdr.dev/slog"
tassert "github.com/stretchr/testify/assert" trequire "github.com/stretchr/testify/require"
"oss.terrastruct.com/util-go/assert" "oss.terrastruct.com/util-go/assert"
"oss.terrastruct.com/util-go/diff" "oss.terrastruct.com/util-go/diff"
@ -101,18 +101,18 @@ func serde(t *testing.T, tc testCase, ruler *textmeasure.Ruler) {
g, err := d2compiler.Compile("", strings.NewReader(tc.script), &d2compiler.CompileOptions{ g, err := d2compiler.Compile("", strings.NewReader(tc.script), &d2compiler.CompileOptions{
UTF16: false, UTF16: false,
}) })
tassert.Nil(t, err) trequire.Nil(t, err)
if len(g.Objects) > 0 { if len(g.Objects) > 0 {
err = g.SetDimensions(nil, ruler, nil) err = g.SetDimensions(nil, ruler, nil)
tassert.Nil(t, err) trequire.Nil(t, err)
d2near.WithoutConstantNears(ctx, g) d2near.WithoutConstantNears(ctx, g)
d2sequence.WithoutSequenceDiagrams(ctx, g) d2sequence.WithoutSequenceDiagrams(ctx, g)
} }
b, err := d2graph.SerializeGraph(g) b, err := d2graph.SerializeGraph(g)
tassert.Nil(t, err) trequire.Nil(t, err)
var newG d2graph.Graph var newG d2graph.Graph
err = d2graph.DeserializeGraph(b, &newG) err = d2graph.DeserializeGraph(b, &newG)
tassert.Nil(t, err) trequire.Nil(t, err)
} }
func run(t *testing.T, tc testCase) { func run(t *testing.T, tc testCase) {
@ -124,9 +124,7 @@ func run(t *testing.T, tc testCase) {
var err error var err error
if tc.mtexts == nil { if tc.mtexts == nil {
ruler, err = textmeasure.NewRuler() ruler, err = textmeasure.NewRuler()
if !tassert.Nil(t, err) { trequire.Nil(t, err)
return
}
serde(t, tc, ruler) serde(t, tc, ruler)
} }
@ -150,9 +148,7 @@ func run(t *testing.T, tc testCase) {
ThemeID: 0, ThemeID: 0,
Layout: layout, Layout: layout,
}) })
if !tassert.Nil(t, err) { trequire.Nil(t, err)
return
}
if tc.assertions != nil { if tc.assertions != nil {
t.Run("assertions", func(t *testing.T) { t.Run("assertions", func(t *testing.T) {
@ -171,26 +167,19 @@ func run(t *testing.T, tc testCase) {
assert.Success(t, err) assert.Success(t, err)
err = ioutil.WriteFile(pathGotSVG, svgBytes, 0600) err = ioutil.WriteFile(pathGotSVG, svgBytes, 0600)
assert.Success(t, err) assert.Success(t, err)
// if running from e2ereport.sh, we want to keep .got.svg on a failure
forReport := os.Getenv("E2E_REPORT") != ""
if !forReport {
defer os.Remove(pathGotSVG)
}
// Check that it's valid SVG // Check that it's valid SVG
var xmlParsed interface{} var xmlParsed interface{}
err = xml.Unmarshal(svgBytes, &xmlParsed) err = xml.Unmarshal(svgBytes, &xmlParsed)
assert.Success(t, err) assert.Success(t, err)
var err2 error
err = diff.TestdataJSON(filepath.Join(dataPath, "board"), diagram) err = diff.TestdataJSON(filepath.Join(dataPath, "board"), diagram)
assert.Success(t, err)
if os.Getenv("SKIP_SVG_CHECK") == "" { if os.Getenv("SKIP_SVG_CHECK") == "" {
err = diff.Testdata(filepath.Join(dataPath, "sketch"), ".svg", svgBytes) err2 = diff.Testdata(filepath.Join(dataPath, "sketch"), ".svg", svgBytes)
}
assert.Success(t, err) assert.Success(t, err)
} assert.Success(t, err2)
if forReport {
os.Remove(pathGotSVG)
}
} }
} }

View file

@ -1,7 +1,10 @@
package e2etests package e2etests
import ( import (
"math"
"testing" "testing"
"oss.terrastruct.com/d2/d2target"
) )
func testRegression(t *testing.T) { func testRegression(t *testing.T) {
@ -446,6 +449,30 @@ b -> c
`, `,
}, },
{
name: "empty_class_height",
script: `
class1: class with rows {
shape: class
-num: int
-timeout: int
}
class2: class without rows {
shape: class
}
`,
assertions: func(t *testing.T, g *d2target.Diagram) {
if len(g.Shapes) != 2 {
t.Fatal("expected 2 shapes")
}
c1Height := float64(g.Shapes[0].Height)
c2Height := float64(g.Shapes[1].Height)
if math.Round(c1Height/2.) != c2Height {
t.Fatal("expected rowless class to be 1/2 height of class with 2 rows")
}
},
},
} }
runa(t, tcs) runa(t, tcs)

View file

@ -6,6 +6,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
stdlog "log"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -38,6 +39,7 @@ func main() {
flag.BoolVar(&deltaFlag, "delta", false, "Generate the report only for cases that changed.") flag.BoolVar(&deltaFlag, "delta", false, "Generate the report only for cases that changed.")
flag.StringVar(&testSetFlag, "test-set", "", "Only run set of tests matching this string. e.g. regressions") flag.StringVar(&testSetFlag, "test-set", "", "Only run set of tests matching this string. e.g. regressions")
flag.StringVar(&testCaseFlag, "test-case", "", "Only run tests matching this string. e.g. all_shapes") flag.StringVar(&testCaseFlag, "test-case", "", "Only run tests matching this string. e.g. all_shapes")
skipTests := flag.Bool("skip-tests", false, "Skip running tests first")
flag.BoolVar(&vFlag, "v", false, "verbose") flag.BoolVar(&vFlag, "v", false, "verbose")
flag.Parse() flag.Parse()
@ -52,6 +54,7 @@ func main() {
testDir = "./e2etests" testDir = "./e2etests"
} }
if !*skipTests {
ctx := log.Stderr(context.Background()) ctx := log.Stderr(context.Background())
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel() defer cancel()
@ -64,6 +67,7 @@ func main() {
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
log.Debug(ctx, cmd.String()) log.Debug(ctx, cmd.String())
_ = cmd.Run() _ = cmd.Run()
}
var tests []TestItem var tests []TestItem
err := filepath.Walk(filepath.Join(testDir, "testdata"), func(path string, info os.FileInfo, err error) error { err := filepath.Walk(filepath.Join(testDir, "testdata"), func(path string, info os.FileInfo, err error) error {
@ -144,6 +148,13 @@ func main() {
} }
path := os.Getenv("REPORT_OUTPUT") path := os.Getenv("REPORT_OUTPUT")
if path == "" {
path = filepath.Join(testDir, "./out/e2e_report.html")
}
err = os.MkdirAll(filepath.Dir(path), 0755)
if err != nil {
stdlog.Fatal(err)
}
f, err := os.Create(path) f, err := os.Create(path)
if err != nil { if err != nil {
panic(fmt.Errorf("error creating file `%s`. %v", path, err)) panic(fmt.Errorf("error creating file `%s`. %v", path, err))

View file

@ -1,16 +1,26 @@
<html> <html>
<title>E2E report</title> <title>E2E report</title>
<body> <body>
<h1>Table of Contents</h1>
<ul>
{{range .Tests}}
<li><a href="#{{.Name}}">{{.Name}}</a></li>
{{end}}
</ul>
<div class="cases"> <div class="cases">
{{range .Tests}} {{range .Tests}}
<div class="case"> <div class="case" id="{{.Name}}">
<h1><a href="../{{.GotSVG}}">{{.Name}}</a></h1> <h1><a href="../../{{.GotSVG}}">{{.Name}}</a></h1>
{{ if .ExpSVG }} {{ if .ExpSVG }}
<h2>Expected</h2> <h2 class="case-exp">Expected</h2>
<img src="../{{.ExpSVG}}" width="100%" />
<h2>Got</h2>
{{ end }} {{ end }}
<img src="../{{.GotSVG}}" width="100%" /> <h2 class="case-got">Got</h2>
<div class="case-img-wrapper">
{{ if .ExpSVG }}
<img src="../../{{.ExpSVG}}" width="100%" />
{{ end }}
<img src="../../{{.GotSVG}}" width="100%" />
</div>
</div> </div>
{{end}} {{end}}
</div> </div>
@ -20,17 +30,24 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
.case { .case {
align-items: center; position: relative;
justify-content: center;
padding: 20px; padding: 20px;
width: 100%;
} }
.case svg { .case-img-wrapper {
width: 400px; display: flex;
height: 400px; align-items: center;
} }
.case pre { .case img {
font-size: 10pt; width: 600px;
width: 400px; }
.case-got {
position: absolute;
left: 600px;
}
.case h2 {
margin: 0;
display: inline;
} }
</style> </style>
</body> </body>

View file

@ -79,23 +79,23 @@ callout -> stored_data -> person
diamond -> oval -> circle diamond -> oval -> circle
hexagon -> cloud hexagon -> cloud
rectangle.multiple: true rectangle.style.multiple: true
square.multiple: true square.style.multiple: true
page.multiple: true page.style.multiple: true
parallelogram.multiple: true parallelogram.style.multiple: true
document.multiple: true document.style.multiple: true
cylinder.multiple: true cylinder.style.multiple: true
queue.multiple: true queue.style.multiple: true
package.multiple: true package.style.multiple: true
step.multiple: true step.style.multiple: true
callout.multiple: true callout.style.multiple: true
stored_data.multiple: true stored_data.style.multiple: true
person.multiple: true person.style.multiple: true
diamond.multiple: true diamond.style.multiple: true
oval.multiple: true oval.style.multiple: true
circle.multiple: true circle.style.multiple: true
hexagon.multiple: true hexagon.style.multiple: true
cloud.multiple: true cloud.style.multiple: true
`, `,
}, },
{ {
@ -126,23 +126,23 @@ callout -> stored_data -> person
diamond -> oval -> circle diamond -> oval -> circle
hexagon -> cloud hexagon -> cloud
rectangle.shadow: true rectangle.style.shadow: true
square.shadow: true square.style.shadow: true
page.shadow: true page.style.shadow: true
parallelogram.shadow: true parallelogram.style.shadow: true
document.shadow: true document.style.shadow: true
cylinder.shadow: true cylinder.style.shadow: true
queue.shadow: true queue.style.shadow: true
package.shadow: true package.style.shadow: true
step.shadow: true step.style.shadow: true
callout.shadow: true callout.style.shadow: true
stored_data.shadow: true stored_data.style.shadow: true
person.shadow: true person.style.shadow: true
diamond.shadow: true diamond.style.shadow: true
oval.shadow: true oval.style.shadow: true
circle.shadow: true circle.style.shadow: true
hexagon.shadow: true hexagon.style.shadow: true
cloud.shadow: true cloud.style.shadow: true
`, `,
}, },
{ {
@ -153,8 +153,8 @@ square: {shape: "square"}
rectangle -> square rectangle -> square
rectangle.3d: true rectangle.style.3d: true
square.3d: true square.style.3d: true
`, `,
}, },
{ {
@ -1109,17 +1109,17 @@ scorer.t -> itemOutcome.t3: setFeedback(missingConcepts)`,
script: `shape: sequence_diagram script: `shape: sequence_diagram
scorer: { scorer: {
stroke: red style.stroke: red
stroke-width: 5 style.stroke-width: 5
} }
scorer.abc: { scorer.abc: {
fill: yellow style.fill: yellow
stroke-width: 7 style.stroke-width: 7
} }
scorer -> itemResponse.a: { scorer -> itemResponse.a: {
stroke-width: 10 style.stroke-width: 10
} }
itemResponse.a -> item.a.b itemResponse.a -> item.a.b
item.a.b -> essayRubric.a.b.c item.a.b -> essayRubric.a.b.c
@ -1877,6 +1877,97 @@ a.sp1 -> a.sp2: redirect
a.sp2 -> b: bar a.sp2 -> b: bar
`, `,
}, },
{
name: "people",
script: `
a.shape: person
b.shape: person
c.shape: person
d.shape: person
e.shape: person
f.shape: person
g.shape: person
a: -
b: --
c: ----
d: --------
e: ----------------
f: --------------------------------
g: ----------------------------------------------------------------
1.shape: person
2.shape: person
3.shape: person
4.shape: person
5.shape: person
1.width: 16
2.width: 64
3.width: 128
4.width: 512
# entering both width and height overrides aspect ratio limit
5.height: 256
5.width: 32
`,
},
{
name: "complex-layers",
script: `
desc: Multi-layer diagram of a home.
window: {
style.double-border: true
}
roof
garage
layers: {
window: {
blinds
glass
}
roof: {
shingles
starlink
utility hookup
}
garage: {
tools
vehicles
}
repair: {
desc: How to repair a home.
steps: {
1: {
find contractors: {
craigslist
facebook
}
}
2: {
find contractors -> solicit quotes
}
3: {
obtain quotes -> negotiate
}
4: {
negotiate -> book the best bid
}
}
}
}
scenarios: {
storm: {
water
rain
thunder
}
}`,
},
} }
runa(t, tcs) runa(t, tcs)

View file

@ -10,7 +10,7 @@
"y": 0 "y": 0
}, },
"width": 112, "width": 112,
"height": 12, "height": 44,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="316" height="216" viewBox="-102 -102 316 216"><style type="text/css"> width="316" height="248" viewBox="-102 -102 316 248"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -39,7 +39,7 @@ width="316" height="216" viewBox="-102 -102 316 216"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="a"><g class="shape" ><rect class="shape" x="0" y="0" width="112" height="12" style="fill:#FFFFFF;stroke:#0A0F25;stroke-width:2;"/><rect class="class_header" x="0.000000" y="0.000000" width="112.000000" height="12.000000" fill="#0A0F25" /><line x1="0.000000" y1="12.000000" x2="112.000000" y2="12.000000" style="stroke-width:1;stroke:#0A0F25" /></g></g><mask id="3176154718" maskUnits="userSpaceOnUse" x="-100" y="-100" width="316" height="216"> ]]></script><g id="a"><g class="shape" ><rect class="shape" x="0" y="0" width="112" height="44" style="fill:#FFFFFF;stroke:#0A0F25;stroke-width:2;"/><rect class="class_header" x="0.000000" y="0.000000" width="112.000000" height="44.000000" fill="#0A0F25" /><line x1="0.000000" y1="44.000000" x2="112.000000" y2="44.000000" style="stroke-width:1;stroke:#0A0F25" /></g></g><mask id="2019199647" maskUnits="userSpaceOnUse" x="-100" y="-100" width="316" height="248">
<rect x="-100" y="-100" width="316" height="216" fill="white"></rect> <rect x="-100" y="-100" width="316" height="248" fill="white"></rect>
</mask><style type="text/css"><![CDATA[]]></style></svg> </mask><style type="text/css"><![CDATA[]]></style></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "a", "id": "a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0

View file

@ -39,7 +39,7 @@ width="304" height="304" viewBox="-102 -102 304 304"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="a"><g class="shape" ><rect x="0" y="0" width="100" height="100" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g></g><mask id="3624597608" maskUnits="userSpaceOnUse" x="-100" y="-100" width="304" height="304"> ]]></script><g id="a"><g class="shape" ><rect x="0" y="0" width="100" height="100" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g></g><mask id="4175712569" maskUnits="userSpaceOnUse" x="-100" y="-100" width="304" height="304">
<rect x="-100" y="-100" width="304" height="304" fill="white"></rect> <rect x="-100" y="-100" width="304" height="304" fill="white"></rect>
</mask><style type="text/css"><![CDATA[]]></style></svg> </mask><style type="text/css"><![CDATA[]]></style></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -37,8 +37,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 239, "labelWidth": 234,
"labelHeight": 150, "labelHeight": 145,
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
@ -77,8 +77,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 160, "labelWidth": 155,
"labelHeight": 118, "labelHeight": 113,
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
@ -117,8 +117,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 160, "labelWidth": 155,
"labelHeight": 118, "labelHeight": 113,
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
} }

View file

@ -56,7 +56,7 @@ width="883" height="354" viewBox="-102 -102 883 354"><style type="text/css">
</text><text class="text-mono" x="0" y="3.000000em" xml:space="preserve"> </text><text class="text-mono" x="0" y="3.000000em" xml:space="preserve">
</text><text class="text-mono" x="0" y="4.000000em" xml:space="preserve">&#160;&#160;<tspan fill="#0086b3">print</tspan>&#160;<tspan fill="#dd1144"></tspan><tspan fill="#dd1144">&quot;</tspan><tspan fill="#dd1144">world</tspan><tspan fill="#dd1144">&quot;</tspan> </text><text class="text-mono" x="0" y="4.000000em" xml:space="preserve">&#160;&#160;<tspan fill="#0086b3">print</tspan>&#160;<tspan fill="#dd1144"></tspan><tspan fill="#dd1144">&quot;</tspan><tspan fill="#dd1144">world</tspan><tspan fill="#dd1144">&quot;</tspan>
</text><text class="text-mono" x="0" y="5.000000em" xml:space="preserve"> </text><text class="text-mono" x="0" y="5.000000em" xml:space="preserve">
</text></g></g></g><mask id="2229987818" maskUnits="userSpaceOnUse" x="-100" y="-100" width="883" height="354"> </text></g></g></g><mask id="2314789821" maskUnits="userSpaceOnUse" x="-100" y="-100" width="883" height="354">
<rect x="-100" y="-100" width="883" height="354" fill="white"></rect> <rect x="-100" y="-100" width="883" height="354" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 350 KiB

After

Width:  |  Height:  |  Size: 350 KiB

View file

@ -37,8 +37,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 239, "labelWidth": 234,
"labelHeight": 150, "labelHeight": 145,
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
@ -77,8 +77,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 160, "labelWidth": 155,
"labelHeight": 118, "labelHeight": 113,
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
@ -117,8 +117,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 160, "labelWidth": 155,
"labelHeight": 118, "labelHeight": 113,
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
} }

View file

@ -56,7 +56,7 @@ width="803" height="354" viewBox="-90 -90 803 354"><style type="text/css">
</text><text class="text-mono" x="0" y="3.000000em" xml:space="preserve"> </text><text class="text-mono" x="0" y="3.000000em" xml:space="preserve">
</text><text class="text-mono" x="0" y="4.000000em" xml:space="preserve">&#160;&#160;<tspan fill="#0086b3">print</tspan>&#160;<tspan fill="#dd1144"></tspan><tspan fill="#dd1144">&quot;</tspan><tspan fill="#dd1144">world</tspan><tspan fill="#dd1144">&quot;</tspan> </text><text class="text-mono" x="0" y="4.000000em" xml:space="preserve">&#160;&#160;<tspan fill="#0086b3">print</tspan>&#160;<tspan fill="#dd1144"></tspan><tspan fill="#dd1144">&quot;</tspan><tspan fill="#dd1144">world</tspan><tspan fill="#dd1144">&quot;</tspan>
</text><text class="text-mono" x="0" y="5.000000em" xml:space="preserve"> </text><text class="text-mono" x="0" y="5.000000em" xml:space="preserve">
</text></g></g></g><mask id="3995090615" maskUnits="userSpaceOnUse" x="-100" y="-100" width="803" height="354"> </text></g></g></g><mask id="2399438644" maskUnits="userSpaceOnUse" x="-100" y="-100" width="803" height="354">
<rect x="-100" y="-100" width="803" height="354" fill="white"></rect> <rect x="-100" y="-100" width="803" height="354" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 350 KiB

After

Width:  |  Height:  |  Size: 350 KiB

View file

@ -4,13 +4,13 @@
"shapes": [ "shapes": [
{ {
"id": "a", "id": "a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0
}, },
"width": 571, "width": 425,
"height": 648, "height": 528,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -37,103 +37,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 17, "labelWidth": 12,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{
"id": "a.c",
"type": "",
"pos": {
"x": 40,
"y": 359
},
"width": 478,
"height": 235,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "white",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "c",
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 15,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "a.c.d",
"type": "",
"pos": {
"x": 236,
"y": 413
},
"width": 114,
"height": 126,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "d",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 14,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
},
{ {
"id": "a.b", "id": "a.b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 64, "x": 94,
"y": 55 "y": 55
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -160,21 +78,62 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "a.1", "id": "a.c",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 237, "x": 40,
"y": 299
},
"width": 345,
"height": 175,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "white",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "c",
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 10,
"labelHeight": 31,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "a.1",
"type": "rectangle",
"pos": {
"x": 207,
"y": 55 "y": 55
}, },
"width": 112, "width": 52,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -201,21 +160,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 12, "labelWidth": 7,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "a.2", "id": "a.2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 409, "x": 319,
"y": 55 "y": 55
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -242,11 +201,52 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
},
{
"id": "a.c.d",
"type": "rectangle",
"pos": {
"x": 206,
"y": 353
},
"width": 54,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "d",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 9,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
} }
], ],
"connections": [ "connections": [
@ -277,19 +277,19 @@
"route": [ "route": [
{ {
"x": 120, "x": 120,
"y": 181.5 "y": 121.5
}, },
{ {
"x": 120, "x": 120,
"y": 251.9 "y": 191.9
}, },
{ {
"x": 120, "x": 120,
"y": 287.5 "y": 227.5
}, },
{ {
"x": 120, "x": 120,
"y": 359.5 "y": 299.5
} }
], ],
"isCurve": true, "isCurve": true,
@ -324,20 +324,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 292.5, "x": 232.5,
"y": 181.5 "y": 121.5
}, },
{ {
"x": 292.5, "x": 232.5,
"y": 251.9 "y": 191.9
}, },
{ {
"x": 292.5, "x": 232.5,
"y": 287.5 "y": 227.5
}, },
{ {
"x": 292.5, "x": 232.5,
"y": 359.5 "y": 299.5
} }
], ],
"isCurve": true, "isCurve": true,
@ -372,20 +372,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 465, "x": 345,
"y": 181.5 "y": 121.5
}, },
{ {
"x": 465, "x": 345,
"y": 251.9 "y": 191.9
}, },
{ {
"x": 465, "x": 345,
"y": 287.5 "y": 227.5
}, },
{ {
"x": 465, "x": 345,
"y": 359.5 "y": 299.5
} }
], ],
"isCurve": true, "isCurve": true,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="775" height="852" viewBox="-102 -102 775 852"><style type="text/css"> width="629" height="732" viewBox="-102 -102 629 732"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -39,9 +39,9 @@ width="775" height="852" viewBox="-102 -102 775 852"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="a"><g class="shape" ><rect x="0" y="0" width="571" height="648" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="285.500000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">a</text></g><g id="a.c"><g class="shape" ><rect x="40" y="359" width="478" height="235" style="fill:#EDF0FD;stroke:white;stroke-width:2;" /></g><text class="text" x="279.000000" y="388.000000" style="text-anchor:middle;font-size:24px;fill:#0A0F25">c</text></g><g id="a.b"><g class="shape" ><rect x="64" y="55" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="120.500000" y="121.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="a.1"><g class="shape" ><rect x="237" y="55" width="112" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="293.000000" y="121.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">1</text></g><g id="a.2"><g class="shape" ><rect x="409" y="55" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="465.500000" y="121.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">2</text></g><g id="a.c.d"><g class="shape" ><rect x="236" y="413" width="114" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="293.000000" y="479.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">d</text></g><g id="a.(b -&gt; c)[0]"><marker id="mk-1065319532" markerWidth="24.200000" markerHeight="18.000000" refX="20.800000" refY="9.000000" viewBox="0.000000 0.000000 24.200000 18.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="white" stroke="red" stroke-width="2" points="0.000000,9.000000 11.000000,2.250000 22.000000,9.000000 11.000000,16.200000" /> </marker><path d="M 120.000000 183.500000 C 120.000000 251.900000 120.000000 287.500000 120.000000 355.500000" class="connection" style="fill:none;stroke:red;stroke-width:2;" marker-end="url(#mk-1065319532)" mask="url(#1474862432)"/><text class="text-italic" x="120.000000" y="252.000000" style="text-anchor:middle;font-size:16px;fill:red"><tspan x="120.000000" dy="0.000000">line 1</tspan><tspan x="120.000000" dy="17.250000">line 2</tspan><tspan x="120.000000" dy="17.250000">line 3</tspan><tspan x="120.000000" dy="17.250000">line 4</tspan></text></g><g id="a.(1 -&gt; c)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 292.500000 183.500000 C 292.500000 251.900000 292.500000 287.500000 292.500000 355.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1474862432)"/></g><g id="a.(2 &lt;-&gt; c)[0]"><marker id="mk-2510427236" markerWidth="10.000000" markerHeight="12.000000" refX="3.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="10.000000,0.000000 0.000000,6.000000 10.000000,12.000000" /> </marker><path d="M 465.000000 185.500000 C 465.000000 251.900000 465.000000 287.500000 465.000000 355.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-start="url(#mk-2510427236)" marker-end="url(#mk-3990223579)" mask="url(#1474862432)"/></g><mask id="1474862432" maskUnits="userSpaceOnUse" x="-100" y="-100" width="775" height="852"> ]]></script><g id="a"><g class="shape" ><rect x="0" y="0" width="425" height="528" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="212.500000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">a</text></g><g id="a.b"><g class="shape" ><rect x="94" y="55" width="53" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="120.500000" y="93.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="a.c"><g class="shape" ><rect x="40" y="299" width="345" height="175" style="fill:#EDF0FD;stroke:white;stroke-width:2;" /></g><text class="text" x="212.500000" y="328.000000" style="text-anchor:middle;font-size:24px;fill:#0A0F25">c</text></g><g id="a.1"><g class="shape" ><rect x="207" y="55" width="52" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="233.000000" y="93.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">1</text></g><g id="a.2"><g class="shape" ><rect x="319" y="55" width="53" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="345.500000" y="93.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">2</text></g><g id="a.c.d"><g class="shape" ><rect x="206" y="353" width="54" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="233.000000" y="391.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">d</text></g><g id="a.(b -&gt; c)[0]"><marker id="mk-1065319532" markerWidth="24.200000" markerHeight="18.000000" refX="20.800000" refY="9.000000" viewBox="0.000000 0.000000 24.200000 18.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="white" stroke="red" stroke-width="2" points="0.000000,9.000000 11.000000,2.250000 22.000000,9.000000 11.000000,16.200000" /> </marker><path d="M 120.000000 123.500000 C 120.000000 191.900000 120.000000 227.500000 120.000000 295.500000" class="connection" style="fill:none;stroke:red;stroke-width:2;" marker-end="url(#mk-1065319532)" mask="url(#89896559)"/><text class="text-italic" x="120.000000" y="192.000000" style="text-anchor:middle;font-size:16px;fill:red"><tspan x="120.000000" dy="0.000000">line 1</tspan><tspan x="120.000000" dy="17.250000">line 2</tspan><tspan x="120.000000" dy="17.250000">line 3</tspan><tspan x="120.000000" dy="17.250000">line 4</tspan></text></g><g id="a.(1 -&gt; c)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 232.500000 123.500000 C 232.500000 191.900000 232.500000 227.500000 232.500000 295.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#89896559)"/></g><g id="a.(2 &lt;-&gt; c)[0]"><marker id="mk-2510427236" markerWidth="10.000000" markerHeight="12.000000" refX="3.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="10.000000,0.000000 0.000000,6.000000 10.000000,12.000000" /> </marker><path d="M 345.000000 125.500000 C 345.000000 191.900000 345.000000 227.500000 345.000000 295.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-start="url(#mk-2510427236)" marker-end="url(#mk-3990223579)" mask="url(#89896559)"/></g><mask id="89896559" maskUnits="userSpaceOnUse" x="-100" y="-100" width="629" height="732">
<rect x="-100" y="-100" width="775" height="852" fill="white"></rect> <rect x="-100" y="-100" width="629" height="732" fill="white"></rect>
<rect x="102.000000" y="236.000000" width="36" height="69" fill="black"></rect> <rect x="102.000000" y="176.000000" width="36" height="69" fill="black"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text { .text {
font-family: "font-regular"; font-family: "font-regular";

Before

Width:  |  Height:  |  Size: 794 KiB

After

Width:  |  Height:  |  Size: 794 KiB

View file

@ -4,13 +4,13 @@
"shapes": [ "shapes": [
{ {
"id": "a", "id": "a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12
}, },
"width": 490, "width": 354,
"height": 878, "height": 701,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -37,103 +37,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 17, "labelWidth": 12,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{
"id": "a.c",
"type": "",
"pos": {
"x": 106,
"y": 539
},
"width": 264,
"height": 276,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "white",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "c",
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 15,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "a.c.d",
"type": "",
"pos": {
"x": 181,
"y": 614
},
"width": 114,
"height": 126,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "d",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 14,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
},
{ {
"id": "a.b", "id": "a.b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 87, "x": 97,
"y": 87 "y": 87
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -160,21 +78,62 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "a.1", "id": "a.c",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 182, "x": 87,
"y": 313 "y": 422
}, },
"width": 112, "width": 204,
"height": 126, "height": 216,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "white",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "c",
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 10,
"labelHeight": 31,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "a.1",
"type": "rectangle",
"pos": {
"x": 163,
"y": 256
},
"width": 52,
"height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -201,21 +160,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 12, "labelWidth": 7,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "a.2", "id": "a.2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 314, "x": 235,
"y": 313 "y": 256
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -242,11 +201,52 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
},
{
"id": "a.c.d",
"type": "rectangle",
"pos": {
"x": 162,
"y": 497
},
"width": 54,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "d",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 9,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
} }
], ],
"connections": [ "connections": [
@ -276,20 +276,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 143.5, "x": 124,
"y": 213 "y": 153
}, },
{ {
"x": 143.5, "x": 124,
"y": 489 "y": 372
}, },
{ {
"x": 172.5, "x": 138,
"y": 489 "y": 372
}, },
{ {
"x": 172.5, "x": 138,
"y": 539 "y": 422
} }
], ],
"animated": false, "animated": false,
@ -323,12 +323,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 238.5, "x": 189,
"y": 439 "y": 322
}, },
{ {
"x": 238.5, "x": 189,
"y": 539 "y": 422
} }
], ],
"animated": false, "animated": false,
@ -362,20 +362,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 371, "x": 261.5,
"y": 439 "y": 322
}, },
{ {
"x": 371, "x": 261.5,
"y": 489 "y": 372
}, },
{ {
"x": 304.5, "x": 240,
"y": 489 "y": 372
}, },
{ {
"x": 304.5, "x": 240,
"y": 539 "y": 422
} }
], ],
"animated": false, "animated": false,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="694" height="1082" viewBox="-90 -90 694 1082"><style type="text/css"> width="558" height="905" viewBox="-90 -90 558 905"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -39,9 +39,9 @@ width="694" height="1082" viewBox="-90 -90 694 1082"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="a"><g class="shape" ><rect x="12" y="12" width="490" height="878" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="257.000000" y="45.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">a</text></g><g id="a.c"><g class="shape" ><rect x="106" y="539" width="264" height="276" style="fill:#EDF0FD;stroke:white;stroke-width:2;" /></g><text class="text" x="238.000000" y="568.000000" style="text-anchor:middle;font-size:24px;fill:#0A0F25">c</text></g><g id="a.b"><g class="shape" ><rect x="87" y="87" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="143.500000" y="153.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="a.1"><g class="shape" ><rect x="182" y="313" width="112" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="238.000000" y="379.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">1</text></g><g id="a.2"><g class="shape" ><rect x="314" y="313" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="370.500000" y="379.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">2</text></g><g id="a.c.d"><g class="shape" ><rect x="181" y="614" width="114" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="238.000000" y="680.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">d</text></g><g id="a.(b -&gt; c)[0]"><marker id="mk-1065319532" markerWidth="24.200000" markerHeight="18.000000" refX="20.800000" refY="9.000000" viewBox="0.000000 0.000000 24.200000 18.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="white" stroke="red" stroke-width="2" points="0.000000,9.000000 11.000000,2.250000 22.000000,9.000000 11.000000,16.200000" /> </marker><path d="M 143.500000 215.000000 L 143.500000 479.000000 S 143.500000 489.000000 153.500000 489.000000 L 162.500000 489.000000 S 172.500000 489.000000 172.500000 499.000000 L 172.500000 535.000000" class="connection" style="fill:none;stroke:red;stroke-width:2;" marker-end="url(#mk-1065319532)" mask="url(#3390014606)"/><text class="text-italic" x="144.000000" y="372.000000" style="text-anchor:middle;font-size:16px;fill:red"><tspan x="144.000000" dy="0.000000">line 1</tspan><tspan x="144.000000" dy="17.250000">line 2</tspan><tspan x="144.000000" dy="17.250000">line 3</tspan><tspan x="144.000000" dy="17.250000">line 4</tspan></text></g><g id="a.(1 -&gt; c)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 238.500000 441.000000 L 238.500000 535.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3390014606)"/></g><g id="a.(2 &lt;-&gt; c)[0]"><marker id="mk-2510427236" markerWidth="10.000000" markerHeight="12.000000" refX="3.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="10.000000,0.000000 0.000000,6.000000 10.000000,12.000000" /> </marker><path d="M 371.000000 443.000000 L 371.000000 479.000000 S 371.000000 489.000000 361.000000 489.000000 L 314.500000 489.000000 S 304.500000 489.000000 304.500000 499.000000 L 304.500000 535.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-start="url(#mk-2510427236)" marker-end="url(#mk-3990223579)" mask="url(#3390014606)"/></g><mask id="3390014606" maskUnits="userSpaceOnUse" x="-100" y="-100" width="694" height="1082"> ]]></script><g id="a"><g class="shape" ><rect x="12" y="12" width="354" height="701" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="189.000000" y="45.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">a</text></g><g id="a.b"><g class="shape" ><rect x="97" y="87" width="53" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="123.500000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="a.c"><g class="shape" ><rect x="87" y="422" width="204" height="216" style="fill:#EDF0FD;stroke:white;stroke-width:2;" /></g><text class="text" x="189.000000" y="451.000000" style="text-anchor:middle;font-size:24px;fill:#0A0F25">c</text></g><g id="a.1"><g class="shape" ><rect x="163" y="256" width="52" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="189.000000" y="294.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">1</text></g><g id="a.2"><g class="shape" ><rect x="235" y="256" width="53" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="261.500000" y="294.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">2</text></g><g id="a.c.d"><g class="shape" ><rect x="162" y="497" width="54" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="189.000000" y="535.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">d</text></g><g id="a.(b -&gt; c)[0]"><marker id="mk-1065319532" markerWidth="24.200000" markerHeight="18.000000" refX="20.800000" refY="9.000000" viewBox="0.000000 0.000000 24.200000 18.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="white" stroke="red" stroke-width="2" points="0.000000,9.000000 11.000000,2.250000 22.000000,9.000000 11.000000,16.200000" /> </marker><path d="M 124.000000 155.000000 L 124.000000 365.000000 C 124.000000 379.000000 138.000000 365.000000 138.000000 379.000000 L 138.000000 418.000000" class="connection" style="fill:none;stroke:red;stroke-width:2;" marker-end="url(#mk-1065319532)" mask="url(#731079584)"/><text class="text-italic" x="124.000000" y="276.000000" style="text-anchor:middle;font-size:16px;fill:red"><tspan x="124.000000" dy="0.000000">line 1</tspan><tspan x="124.000000" dy="17.250000">line 2</tspan><tspan x="124.000000" dy="17.250000">line 3</tspan><tspan x="124.000000" dy="17.250000">line 4</tspan></text></g><g id="a.(1 -&gt; c)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 189.000000 324.000000 L 189.000000 418.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#731079584)"/></g><g id="a.(2 &lt;-&gt; c)[0]"><marker id="mk-2510427236" markerWidth="10.000000" markerHeight="12.000000" refX="3.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="10.000000,0.000000 0.000000,6.000000 10.000000,12.000000" /> </marker><path d="M 261.500000 326.000000 L 261.500000 362.000000 S 261.500000 372.000000 251.500000 372.000000 L 250.000000 372.000000 S 240.000000 372.000000 240.000000 382.000000 L 240.000000 418.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-start="url(#mk-2510427236)" marker-end="url(#mk-3990223579)" mask="url(#731079584)"/></g><mask id="731079584" maskUnits="userSpaceOnUse" x="-100" y="-100" width="558" height="905">
<rect x="-100" y="-100" width="694" height="1082" fill="white"></rect> <rect x="-100" y="-100" width="558" height="905" fill="white"></rect>
<rect x="126.000000" y="356.000000" width="36" height="69" fill="black"></rect> <rect x="106.000000" y="260.000000" width="36" height="69" fill="black"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text { .text {
font-family: "font-regular"; font-family: "font-regular";

Before

Width:  |  Height:  |  Size: 794 KiB

After

Width:  |  Height:  |  Size: 794 KiB

View file

@ -4,13 +4,13 @@
"shapes": [ "shapes": [
{ {
"id": "build_workflow", "id": "build_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0
}, },
"width": 2628, "width": 2328,
"height": 237, "height": 177,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -37,21 +37,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 226, "labelWidth": 221,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "build_workflow.push", "id": "build_workflow.push",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 105, "x": 105,
"y": 50 "y": 50
}, },
"width": 330, "width": 270,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -78,21 +78,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 230, "labelWidth": 225,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.GHA", "id": "build_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 698, "x": 638,
"y": 50 "y": 50
}, },
"width": 269, "width": 209,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -119,21 +119,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 169, "labelWidth": 164,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.S3", "id": "build_workflow.S3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1314, "x": 1194,
"y": 50 "y": 50
}, },
"width": 131, "width": 71,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -160,21 +160,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 31, "labelWidth": 26,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.Terraform", "id": "build_workflow.Terraform",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1773, "x": 1593,
"y": 50 "y": 50
}, },
"width": 218, "width": 158,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -201,21 +201,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 118, "labelWidth": 113,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.AWS", "id": "build_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 2369, "x": 2129,
"y": 50 "y": 50
}, },
"width": 155, "width": 95,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -242,8 +242,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 55, "labelWidth": 50,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
@ -276,20 +276,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 435.5, "x": 375.5,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 539.9, "x": 479.9,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 592.3, "x": 532.3,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 697.5, "x": 637.5,
"y": 118.5 "y": 88.5
} }
], ],
"isCurve": true, "isCurve": true,
@ -324,20 +324,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 966.5, "x": 846.5,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 1105.3, "x": 985.3,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 1174.7, "x": 1054.7,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 1313.5, "x": 1193.5,
"y": 118.5 "y": 88.5
} }
], ],
"isCurve": true, "isCurve": true,
@ -372,20 +372,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1445.5, "x": 1265.5,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 1575.9, "x": 1395.9,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 1641.3, "x": 1461.3,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 1772.5, "x": 1592.5,
"y": 118.5 "y": 88.5
} }
], ],
"isCurve": true, "isCurve": true,
@ -420,20 +420,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1991.5, "x": 1751.5,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 2141.9, "x": 1901.9,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 2217.3, "x": 1977.3,
"y": 118.5 "y": 88.5
}, },
{ {
"x": 2368.5, "x": 2128.5,
"y": 118.5 "y": 88.5
} }
], ],
"isCurve": true, "isCurve": true,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="2832" height="441" viewBox="-102 -102 2832 441"><style type="text/css"> width="2532" height="381" viewBox="-102 -102 2532 381"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -39,12 +39,12 @@ width="2832" height="441" viewBox="-102 -102 2832 441"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="build_workflow"><g class="shape" ><rect x="0" y="0" width="2628" height="237" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="1314.000000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">lambda-build.yaml</text></g><g id="build_workflow.push"><g class="shape" ><rect x="105" y="50" width="330" height="137" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="270.000000" y="125.000000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">Push to main branch</text></g><g id="build_workflow.GHA"><g class="shape" ><rect x="698" y="50" width="269" height="137" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="832.500000" y="125.000000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">GitHub Actions</text></g><g id="build_workflow.S3"><g class="shape" ><rect x="1314" y="50" width="131" height="137" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1379.500000" y="125.000000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">S3</text></g><g id="build_workflow.Terraform"><g class="shape" ><rect x="1773" y="50" width="218" height="137" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1882.000000" y="125.000000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">Terraform</text></g><g id="build_workflow.AWS"><g class="shape" ><rect x="2369" y="50" width="155" height="137" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="2446.500000" y="125.000000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">AWS</text></g><g id="build_workflow.(push -&gt; GHA)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 437.500000 118.500000 C 539.900000 118.500000 592.300000 118.500000 693.500000 118.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#351638657)"/><text class="text-italic" x="567.000000" y="124.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Triggers</text></g><g id="build_workflow.(GHA -&gt; S3)[0]"><path d="M 968.500000 118.500000 C 1105.300000 118.500000 1174.700000 118.500000 1309.500000 118.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#351638657)"/><text class="text-italic" x="1140.000000" y="124.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Builds zip &amp; pushes it</text></g><g id="build_workflow.(S3 &lt;-&gt; Terraform)[0]"><marker id="mk-2510427236" markerWidth="10.000000" markerHeight="12.000000" refX="3.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="10.000000,0.000000 0.000000,6.000000 10.000000,12.000000" /> </marker><path d="M 1449.500000 118.500000 C 1575.900000 118.500000 1641.300000 118.500000 1768.500000 118.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-start="url(#mk-2510427236)" marker-end="url(#mk-3990223579)" mask="url(#351638657)"/><text class="text-italic" x="1609.500000" y="124.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Pulls zip to deploy</text></g><g id="build_workflow.(Terraform -&gt; AWS)[0]"><path d="M 1993.500000 118.500000 C 2141.900000 118.500000 2217.300000 118.500000 2364.500000 118.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#351638657)"/><text class="text-italic" x="2180.500000" y="124.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Changes the live lambdas</text></g><mask id="351638657" maskUnits="userSpaceOnUse" x="-100" y="-100" width="2832" height="441"> ]]></script><g id="build_workflow"><g class="shape" ><rect x="0" y="0" width="2328" height="177" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="1164.000000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">lambda-build.yaml</text></g><g id="build_workflow.push"><g class="shape" ><rect x="105" y="50" width="270" height="77" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="240.000000" y="97.500000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">Push to main branch</text></g><g id="build_workflow.GHA"><g class="shape" ><rect x="638" y="50" width="209" height="77" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="742.500000" y="97.500000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">GitHub Actions</text></g><g id="build_workflow.S3"><g class="shape" ><rect x="1194" y="50" width="71" height="77" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1229.500000" y="97.500000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">S3</text></g><g id="build_workflow.Terraform"><g class="shape" ><rect x="1593" y="50" width="158" height="77" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1672.000000" y="97.500000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">Terraform</text></g><g id="build_workflow.AWS"><g class="shape" ><rect x="2129" y="50" width="95" height="77" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="2176.500000" y="97.500000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">AWS</text></g><g id="build_workflow.(push -&gt; GHA)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 377.500000 88.500000 C 479.900000 88.500000 532.300000 88.500000 633.500000 88.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2796260647)"/><text class="text-italic" x="507.000000" y="94.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Triggers</text></g><g id="build_workflow.(GHA -&gt; S3)[0]"><path d="M 848.500000 88.500000 C 985.300000 88.500000 1054.700000 88.500000 1189.500000 88.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2796260647)"/><text class="text-italic" x="1020.000000" y="94.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Builds zip &amp; pushes it</text></g><g id="build_workflow.(S3 &lt;-&gt; Terraform)[0]"><marker id="mk-2510427236" markerWidth="10.000000" markerHeight="12.000000" refX="3.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="10.000000,0.000000 0.000000,6.000000 10.000000,12.000000" /> </marker><path d="M 1269.500000 88.500000 C 1395.900000 88.500000 1461.300000 88.500000 1588.500000 88.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-start="url(#mk-2510427236)" marker-end="url(#mk-3990223579)" mask="url(#2796260647)"/><text class="text-italic" x="1429.500000" y="94.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Pulls zip to deploy</text></g><g id="build_workflow.(Terraform -&gt; AWS)[0]"><path d="M 1753.500000 88.500000 C 1901.900000 88.500000 1977.300000 88.500000 2124.500000 88.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2796260647)"/><text class="text-italic" x="1940.500000" y="94.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Changes the live lambdas</text></g><mask id="2796260647" maskUnits="userSpaceOnUse" x="-100" y="-100" width="2532" height="381">
<rect x="-100" y="-100" width="2832" height="441" fill="white"></rect> <rect x="-100" y="-100" width="2532" height="381" fill="white"></rect>
<rect x="540.000000" y="108.000000" width="54" height="21" fill="black"></rect> <rect x="480.000000" y="78.000000" width="54" height="21" fill="black"></rect>
<rect x="1071.000000" y="108.000000" width="138" height="21" fill="black"></rect> <rect x="951.000000" y="78.000000" width="138" height="21" fill="black"></rect>
<rect x="1550.000000" y="108.000000" width="119" height="21" fill="black"></rect> <rect x="1370.000000" y="78.000000" width="119" height="21" fill="black"></rect>
<rect x="2096.000000" y="108.000000" width="169" height="21" fill="black"></rect> <rect x="1856.000000" y="78.000000" width="169" height="21" fill="black"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text { .text {
font-family: "font-regular"; font-family: "font-regular";

Before

Width:  |  Height:  |  Size: 795 KiB

After

Width:  |  Height:  |  Size: 795 KiB

View file

@ -4,13 +4,13 @@
"shapes": [ "shapes": [
{ {
"id": "build_workflow", "id": "build_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12
}, },
"width": 2533, "width": 2233,
"height": 287, "height": 227,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -37,21 +37,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 226, "labelWidth": 221,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "build_workflow.push", "id": "build_workflow.push",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 87, "x": 87,
"y": 87 "y": 87
}, },
"width": 330, "width": 270,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -78,21 +78,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 230, "labelWidth": 225,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.GHA", "id": "build_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 671, "x": 611,
"y": 87 "y": 87
}, },
"width": 269, "width": 209,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -119,21 +119,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 169, "labelWidth": 164,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.S3", "id": "build_workflow.S3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1278, "x": 1158,
"y": 87 "y": 87
}, },
"width": 131, "width": 71,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -160,21 +160,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 31, "labelWidth": 26,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.Terraform", "id": "build_workflow.Terraform",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1728, "x": 1548,
"y": 87 "y": 87
}, },
"width": 218, "width": 158,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -201,21 +201,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 118, "labelWidth": 113,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.AWS", "id": "build_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 2315, "x": 2075,
"y": 87 "y": 87
}, },
"width": 155, "width": 95,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -242,8 +242,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 55, "labelWidth": 50,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
@ -276,12 +276,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 417, "x": 357,
"y": 155.5 "y": 125.5
}, },
{ {
"x": 671, "x": 611,
"y": 155.5 "y": 125.5
} }
], ],
"animated": false, "animated": false,
@ -315,12 +315,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 940, "x": 820,
"y": 155.5 "y": 125.5
}, },
{ {
"x": 1278, "x": 1158,
"y": 155.5 "y": 125.5
} }
], ],
"animated": false, "animated": false,
@ -354,12 +354,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1409, "x": 1229,
"y": 155.5 "y": 125.5
}, },
{ {
"x": 1728, "x": 1548,
"y": 155.5 "y": 125.5
} }
], ],
"animated": false, "animated": false,
@ -393,12 +393,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1946, "x": 1706,
"y": 155.5 "y": 125.5
}, },
{ {
"x": 2315, "x": 2075,
"y": 155.5 "y": 125.5
} }
], ],
"animated": false, "animated": false,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="2737" height="491" viewBox="-90 -90 2737 491"><style type="text/css"> width="2437" height="431" viewBox="-90 -90 2437 431"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -39,12 +39,12 @@ width="2737" height="491" viewBox="-90 -90 2737 491"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="build_workflow"><g class="shape" ><rect x="12" y="12" width="2533" height="287" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="1278.500000" y="45.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">lambda-build.yaml</text></g><g id="build_workflow.push"><g class="shape" ><rect x="87" y="87" width="330" height="137" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="252.000000" y="162.000000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">Push to main branch</text></g><g id="build_workflow.GHA"><g class="shape" ><rect x="671" y="87" width="269" height="137" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="805.500000" y="162.000000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">GitHub Actions</text></g><g id="build_workflow.S3"><g class="shape" ><rect x="1278" y="87" width="131" height="137" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1343.500000" y="162.000000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">S3</text></g><g id="build_workflow.Terraform"><g class="shape" ><rect x="1728" y="87" width="218" height="137" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1837.000000" y="162.000000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">Terraform</text></g><g id="build_workflow.AWS"><g class="shape" ><rect x="2315" y="87" width="155" height="137" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="2392.500000" y="162.000000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">AWS</text></g><g id="build_workflow.(push -&gt; GHA)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 419.000000 155.500000 L 667.000000 155.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1057310123)"/><text class="text-italic" x="544.000000" y="161.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Triggers</text></g><g id="build_workflow.(GHA -&gt; S3)[0]"><path d="M 942.000000 155.500000 L 1274.000000 155.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1057310123)"/><text class="text-italic" x="1109.000000" y="161.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Builds zip &amp; pushes it</text></g><g id="build_workflow.(S3 &lt;-&gt; Terraform)[0]"><marker id="mk-2510427236" markerWidth="10.000000" markerHeight="12.000000" refX="3.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="10.000000,0.000000 0.000000,6.000000 10.000000,12.000000" /> </marker><path d="M 1413.000000 155.500000 L 1724.000000 155.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-start="url(#mk-2510427236)" marker-end="url(#mk-3990223579)" mask="url(#1057310123)"/><text class="text-italic" x="1568.500000" y="161.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Pulls zip to deploy</text></g><g id="build_workflow.(Terraform -&gt; AWS)[0]"><path d="M 1948.000000 155.500000 L 2311.000000 155.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1057310123)"/><text class="text-italic" x="2130.500000" y="161.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Changes the live lambdas</text></g><mask id="1057310123" maskUnits="userSpaceOnUse" x="-100" y="-100" width="2737" height="491"> ]]></script><g id="build_workflow"><g class="shape" ><rect x="12" y="12" width="2233" height="227" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="1128.500000" y="45.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">lambda-build.yaml</text></g><g id="build_workflow.push"><g class="shape" ><rect x="87" y="87" width="270" height="77" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="222.000000" y="134.500000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">Push to main branch</text></g><g id="build_workflow.GHA"><g class="shape" ><rect x="611" y="87" width="209" height="77" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="715.500000" y="134.500000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">GitHub Actions</text></g><g id="build_workflow.S3"><g class="shape" ><rect x="1158" y="87" width="71" height="77" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1193.500000" y="134.500000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">S3</text></g><g id="build_workflow.Terraform"><g class="shape" ><rect x="1548" y="87" width="158" height="77" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1627.000000" y="134.500000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">Terraform</text></g><g id="build_workflow.AWS"><g class="shape" ><rect x="2075" y="87" width="95" height="77" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="2122.500000" y="134.500000" style="text-anchor:middle;font-size:25px;fill:#0A0F25">AWS</text></g><g id="build_workflow.(push -&gt; GHA)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 359.000000 125.500000 L 607.000000 125.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#483332612)"/><text class="text-italic" x="484.000000" y="131.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Triggers</text></g><g id="build_workflow.(GHA -&gt; S3)[0]"><path d="M 822.000000 125.500000 L 1154.000000 125.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#483332612)"/><text class="text-italic" x="989.000000" y="131.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Builds zip &amp; pushes it</text></g><g id="build_workflow.(S3 &lt;-&gt; Terraform)[0]"><marker id="mk-2510427236" markerWidth="10.000000" markerHeight="12.000000" refX="3.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="10.000000,0.000000 0.000000,6.000000 10.000000,12.000000" /> </marker><path d="M 1233.000000 125.500000 L 1544.000000 125.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-start="url(#mk-2510427236)" marker-end="url(#mk-3990223579)" mask="url(#483332612)"/><text class="text-italic" x="1388.500000" y="131.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Pulls zip to deploy</text></g><g id="build_workflow.(Terraform -&gt; AWS)[0]"><path d="M 1708.000000 125.500000 L 2071.000000 125.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#483332612)"/><text class="text-italic" x="1890.500000" y="131.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">Changes the live lambdas</text></g><mask id="483332612" maskUnits="userSpaceOnUse" x="-100" y="-100" width="2437" height="431">
<rect x="-100" y="-100" width="2737" height="491" fill="white"></rect> <rect x="-100" y="-100" width="2437" height="431" fill="white"></rect>
<rect x="517.000000" y="145.000000" width="54" height="21" fill="black"></rect> <rect x="457.000000" y="115.000000" width="54" height="21" fill="black"></rect>
<rect x="1040.000000" y="145.000000" width="138" height="21" fill="black"></rect> <rect x="920.000000" y="115.000000" width="138" height="21" fill="black"></rect>
<rect x="1509.000000" y="145.000000" width="119" height="21" fill="black"></rect> <rect x="1329.000000" y="115.000000" width="119" height="21" fill="black"></rect>
<rect x="2046.000000" y="145.000000" width="169" height="21" fill="black"></rect> <rect x="1806.000000" y="115.000000" width="169" height="21" fill="black"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text { .text {
font-family: "font-regular"; font-family: "font-regular";

Before

Width:  |  Height:  |  Size: 795 KiB

After

Width:  |  Height:  |  Size: 795 KiB

View file

@ -4,13 +4,13 @@
"shapes": [ "shapes": [
{ {
"id": "\"ninety\\nnine\"", "id": "\"ninety\\nnine\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0
}, },
"width": 151, "width": 91,
"height": 142, "height": 82,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -37,21 +37,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 51, "labelWidth": 46,
"labelHeight": 42, "labelHeight": 37,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "eighty\reight", "id": "eighty\reight",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 211, "x": 151,
"y": 8 "y": 8
}, },
"width": 151, "width": 91,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -78,21 +78,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 51, "labelWidth": 46,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "\"seventy\r\\nseven\"", "id": "\"seventy\r\\nseven\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 422, "x": 302,
"y": 0 "y": 0
}, },
"width": 162, "width": 102,
"height": 142, "height": 82,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -119,21 +119,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 62, "labelWidth": 57,
"labelHeight": 42, "labelHeight": 37,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "\"a\\\\yode\"", "id": "\"a\\\\yode\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 644, "x": 464,
"y": 8 "y": 8
}, },
"width": 154, "width": 94,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -160,21 +160,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 54, "labelWidth": 49,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "there", "id": "there",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 864, "x": 624,
"y": 242 "y": 182
}, },
"width": 143, "width": 83,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -201,21 +201,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 43, "labelWidth": 38,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "'a\\\"ode'", "id": "'a\\\"ode'",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 858, "x": 618,
"y": 8 "y": 8
}, },
"width": 154, "width": 94,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -242,21 +242,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 54, "labelWidth": 49,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "\"a\\\\node\"", "id": "\"a\\\\node\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1072, "x": 772,
"y": 8 "y": 8
}, },
"width": 155, "width": 95,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -283,8 +283,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 55, "labelWidth": 50,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
@ -317,20 +317,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 721, "x": 511,
"y": 134 "y": 74
}, },
{ {
"x": 721, "x": 511,
"y": 180.4 "y": 120.4
}, },
{ {
"x": 749.5, "x": 533.5,
"y": 207.04906542056074 "y": 144.12662337662337
}, },
{ {
"x": 863.5, "x": 623.5,
"y": 267.24532710280374 "y": 192.63311688311688
} }
], ],
"isCurve": true, "isCurve": true,
@ -365,20 +365,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 935, "x": 665,
"y": 134 "y": 74
}, },
{ {
"x": 935, "x": 665,
"y": 180.4 "y": 120.4
}, },
{ {
"x": 935, "x": 665,
"y": 202 "y": 142
}, },
{ {
"x": 935, "x": 665,
"y": 242 "y": 182
} }
], ],
"isCurve": true, "isCurve": true,
@ -413,20 +413,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1149.5, "x": 819.5,
"y": 134 "y": 74
}, },
{ {
"x": 1149.5, "x": 819.5,
"y": 180.4 "y": 120.4
}, },
{ {
"x": 1120.9, "x": 796.9,
"y": 207 "y": 144
}, },
{ {
"x": 1006.5, "x": 706.5,
"y": 267 "y": 192
} }
], ],
"isCurve": true, "isCurve": true,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="1431" height="572" viewBox="-102 -102 1431 572"><style type="text/css"> width="1071" height="452" viewBox="-102 -102 1071 452"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -39,8 +39,8 @@ width="1431" height="572" viewBox="-102 -102 1431 572"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="&#34;ninety\nnine&#34;"><g class="shape" ><rect x="0" y="0" width="151" height="142" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="75.500000" y="66.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25"><tspan x="75.500000" dy="0.000000">ninety</tspan><tspan x="75.500000" dy="21.000000">nine</tspan></text></g><g id="eighty&#xD;eight"><g class="shape" ><rect x="211" y="8" width="151" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="286.500000" y="74.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">eighty&#xD;eight</text></g><g id="&#34;seventy&#xD;\nseven&#34;"><g class="shape" ><rect x="422" y="0" width="162" height="142" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="503.000000" y="66.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25"><tspan x="503.000000" dy="0.000000">seventy&#xD;</tspan><tspan x="503.000000" dy="21.000000">seven</tspan></text></g><g id="&#34;a\\yode&#34;"><g class="shape" ><rect x="644" y="8" width="154" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="721.000000" y="74.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\yode</text></g><g id="there"><g class="shape" ><rect x="864" y="242" width="143" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="935.500000" y="308.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">there</text></g><g id="&#39;a\&#34;ode&#39;"><g class="shape" ><rect x="858" y="8" width="154" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="935.000000" y="74.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\&#34;ode</text></g><g id="&#34;a\\node&#34;"><g class="shape" ><rect x="1072" y="8" width="155" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1149.500000" y="74.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\node</text></g><g id="(&#34;a\\yode&#34; -&gt; there)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 721.000000 136.000000 C 721.000000 180.400000 749.500000 207.049065 859.962840 265.377574" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1203581638)"/></g><g id="(&#39;a\&#34;ode&#39; -&gt; there)[0]"><path d="M 935.000000 136.000000 C 935.000000 180.400000 935.000000 202.000000 935.000000 238.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1203581638)"/></g><g id="(&#34;a\\node&#34; -&gt; there)[0]"><path d="M 1149.500000 136.000000 C 1149.500000 180.400000 1120.900000 207.000000 1010.042356 265.142121" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1203581638)"/></g><mask id="1203581638" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1431" height="572"> ]]></script><g id="&#34;ninety\nnine&#34;"><g class="shape" ><rect x="0" y="0" width="91" height="82" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="45.500000" y="38.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25"><tspan x="45.500000" dy="0.000000">ninety</tspan><tspan x="45.500000" dy="18.500000">nine</tspan></text></g><g id="eighty&#xD;eight"><g class="shape" ><rect x="151" y="8" width="91" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="196.500000" y="46.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">eighty&#xD;eight</text></g><g id="&#34;seventy&#xD;\nseven&#34;"><g class="shape" ><rect x="302" y="0" width="102" height="82" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="353.000000" y="38.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25"><tspan x="353.000000" dy="0.000000">seventy&#xD;</tspan><tspan x="353.000000" dy="18.500000">seven</tspan></text></g><g id="&#34;a\\yode&#34;"><g class="shape" ><rect x="464" y="8" width="94" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="511.000000" y="46.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\yode</text></g><g id="there"><g class="shape" ><rect x="624" y="182" width="83" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="665.500000" y="220.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">there</text></g><g id="&#39;a\&#34;ode&#39;"><g class="shape" ><rect x="618" y="8" width="94" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="665.000000" y="46.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\&#34;ode</text></g><g id="&#34;a\\node&#34;"><g class="shape" ><rect x="772" y="8" width="95" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="819.500000" y="46.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\node</text></g><g id="(&#34;a\\yode&#34; -&gt; there)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 511.000000 76.000000 C 511.000000 120.400000 533.500000 144.126623 619.978850 190.735354" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1631294189)"/></g><g id="(&#39;a\&#34;ode&#39; -&gt; there)[0]"><path d="M 665.000000 76.000000 C 665.000000 120.400000 665.000000 142.000000 665.000000 178.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1631294189)"/></g><g id="(&#34;a\\node&#34; -&gt; there)[0]"><path d="M 819.500000 76.000000 C 819.500000 120.400000 796.900000 144.000000 710.032868 190.124141" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1631294189)"/></g><mask id="1631294189" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1071" height="452">
<rect x="-100" y="-100" width="1431" height="572" fill="white"></rect> <rect x="-100" y="-100" width="1071" height="452" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text-bold { .text-bold {

Before

Width:  |  Height:  |  Size: 327 KiB

After

Width:  |  Height:  |  Size: 327 KiB

View file

@ -4,13 +4,13 @@
"shapes": [ "shapes": [
{ {
"id": "\"ninety\\nnine\"", "id": "\"ninety\\nnine\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12
}, },
"width": 151, "width": 91,
"height": 142, "height": 82,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -37,21 +37,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 51, "labelWidth": 46,
"labelHeight": 42, "labelHeight": 37,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "eighty\reight", "id": "eighty\reight",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 183, "x": 123,
"y": 20 "y": 20
}, },
"width": 151, "width": 91,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -78,21 +78,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 51, "labelWidth": 46,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "\"seventy\r\\nseven\"", "id": "\"seventy\r\\nseven\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 354, "x": 234,
"y": 12 "y": 12
}, },
"width": 162, "width": 102,
"height": 142, "height": 82,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -119,21 +119,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 62, "labelWidth": 57,
"labelHeight": 42, "labelHeight": 37,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "\"a\\\\yode\"", "id": "\"a\\\\yode\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 536, "x": 356,
"y": 28 "y": 28
}, },
"width": 154, "width": 94,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -160,21 +160,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 54, "labelWidth": 49,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "there", "id": "there",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 715, "x": 475,
"y": 254 "y": 194
}, },
"width": 143, "width": 83,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -201,21 +201,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 43, "labelWidth": 38,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "'a\\\"ode'", "id": "'a\\\"ode'",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 710, "x": 470,
"y": 28 "y": 28
}, },
"width": 154, "width": 94,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -242,21 +242,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 54, "labelWidth": 49,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "\"a\\\\node\"", "id": "\"a\\\\node\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 884, "x": 584,
"y": 28 "y": 28
}, },
"width": 155, "width": 95,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -283,8 +283,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 55, "labelWidth": 50,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
@ -317,20 +317,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 613, "x": 403,
"y": 154 "y": 94
}, },
{ {
"x": 613, "x": 403,
"y": 204 "y": 144
}, },
{ {
"x": 751.25, "x": 496.25,
"y": 204 "y": 144
}, },
{ {
"x": 751.25, "x": 496.25,
"y": 254 "y": 194
} }
], ],
"animated": false, "animated": false,
@ -364,12 +364,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 787, "x": 517,
"y": 154 "y": 94
}, },
{ {
"x": 787, "x": 517,
"y": 254 "y": 194
} }
], ],
"animated": false, "animated": false,
@ -403,20 +403,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 961.5, "x": 631.5,
"y": 154 "y": 94
}, },
{ {
"x": 961.5, "x": 631.5,
"y": 204 "y": 144
}, },
{ {
"x": 822.75, "x": 537.75,
"y": 204 "y": 144
}, },
{ {
"x": 822.75, "x": 537.75,
"y": 254 "y": 194
} }
], ],
"animated": false, "animated": false,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="1231" height="572" viewBox="-90 -90 1231 572"><style type="text/css"> width="871" height="452" viewBox="-90 -90 871 452"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -39,8 +39,8 @@ width="1231" height="572" viewBox="-90 -90 1231 572"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="&#34;ninety\nnine&#34;"><g class="shape" ><rect x="12" y="12" width="151" height="142" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="87.500000" y="78.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25"><tspan x="87.500000" dy="0.000000">ninety</tspan><tspan x="87.500000" dy="21.000000">nine</tspan></text></g><g id="eighty&#xD;eight"><g class="shape" ><rect x="183" y="20" width="151" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="258.500000" y="86.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">eighty&#xD;eight</text></g><g id="&#34;seventy&#xD;\nseven&#34;"><g class="shape" ><rect x="354" y="12" width="162" height="142" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="435.000000" y="78.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25"><tspan x="435.000000" dy="0.000000">seventy&#xD;</tspan><tspan x="435.000000" dy="21.000000">seven</tspan></text></g><g id="&#34;a\\yode&#34;"><g class="shape" ><rect x="536" y="28" width="154" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="613.000000" y="94.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\yode</text></g><g id="there"><g class="shape" ><rect x="715" y="254" width="143" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="786.500000" y="320.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">there</text></g><g id="&#39;a\&#34;ode&#39;"><g class="shape" ><rect x="710" y="28" width="154" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="787.000000" y="94.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\&#34;ode</text></g><g id="&#34;a\\node&#34;"><g class="shape" ><rect x="884" y="28" width="155" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="961.500000" y="94.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\node</text></g><g id="(&#34;a\\yode&#34; -&gt; there)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 613.000000 156.000000 L 613.000000 194.000000 S 613.000000 204.000000 623.000000 204.000000 L 741.250000 204.000000 S 751.250000 204.000000 751.250000 214.000000 L 751.250000 250.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3116272567)"/></g><g id="(&#39;a\&#34;ode&#39; -&gt; there)[0]"><path d="M 787.000000 156.000000 L 787.000000 250.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3116272567)"/></g><g id="(&#34;a\\node&#34; -&gt; there)[0]"><path d="M 961.500000 156.000000 L 961.500000 194.000000 S 961.500000 204.000000 951.500000 204.000000 L 832.750000 204.000000 S 822.750000 204.000000 822.750000 214.000000 L 822.750000 250.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3116272567)"/></g><mask id="3116272567" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1231" height="572"> ]]></script><g id="&#34;ninety\nnine&#34;"><g class="shape" ><rect x="12" y="12" width="91" height="82" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="57.500000" y="50.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25"><tspan x="57.500000" dy="0.000000">ninety</tspan><tspan x="57.500000" dy="18.500000">nine</tspan></text></g><g id="eighty&#xD;eight"><g class="shape" ><rect x="123" y="20" width="91" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="168.500000" y="58.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">eighty&#xD;eight</text></g><g id="&#34;seventy&#xD;\nseven&#34;"><g class="shape" ><rect x="234" y="12" width="102" height="82" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="285.000000" y="50.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25"><tspan x="285.000000" dy="0.000000">seventy&#xD;</tspan><tspan x="285.000000" dy="18.500000">seven</tspan></text></g><g id="&#34;a\\yode&#34;"><g class="shape" ><rect x="356" y="28" width="94" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="403.000000" y="66.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\yode</text></g><g id="there"><g class="shape" ><rect x="475" y="194" width="83" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="516.500000" y="232.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">there</text></g><g id="&#39;a\&#34;ode&#39;"><g class="shape" ><rect x="470" y="28" width="94" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="517.000000" y="66.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\&#34;ode</text></g><g id="&#34;a\\node&#34;"><g class="shape" ><rect x="584" y="28" width="95" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="631.500000" y="66.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a\node</text></g><g id="(&#34;a\\yode&#34; -&gt; there)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 403.000000 96.000000 L 403.000000 134.000000 S 403.000000 144.000000 413.000000 144.000000 L 486.250000 144.000000 S 496.250000 144.000000 496.250000 154.000000 L 496.250000 190.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1355253866)"/></g><g id="(&#39;a\&#34;ode&#39; -&gt; there)[0]"><path d="M 517.000000 96.000000 L 517.000000 190.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1355253866)"/></g><g id="(&#34;a\\node&#34; -&gt; there)[0]"><path d="M 631.500000 96.000000 L 631.500000 134.000000 S 631.500000 144.000000 621.500000 144.000000 L 547.750000 144.000000 S 537.750000 144.000000 537.750000 154.000000 L 537.750000 190.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1355253866)"/></g><mask id="1355253866" maskUnits="userSpaceOnUse" x="-100" y="-100" width="871" height="452">
<rect x="-100" y="-100" width="1231" height="572" fill="white"></rect> <rect x="-100" y="-100" width="871" height="452" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text-bold { .text-bold {

Before

Width:  |  Height:  |  Size: 328 KiB

After

Width:  |  Height:  |  Size: 327 KiB

View file

@ -4,13 +4,13 @@
"shapes": [ "shapes": [
{ {
"id": "build_workflow", "id": "build_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0
}, },
"width": 430, "width": 370,
"height": 1672, "height": 1372,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -37,21 +37,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 226, "labelWidth": 221,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "build_workflow.push", "id": "build_workflow.push",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 50, "x": 50,
"y": 73 "y": 73
}, },
"width": 330, "width": 270,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -78,21 +78,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 230, "labelWidth": 225,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.GHA", "id": "build_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 81, "x": 81,
"y": 382 "y": 322
}, },
"width": 269, "width": 209,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -119,21 +119,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 169, "labelWidth": 164,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.S3", "id": "build_workflow.S3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 150, "x": 150,
"y": 771 "y": 651
}, },
"width": 131, "width": 71,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -160,21 +160,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 31, "labelWidth": 26,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.Terraform", "id": "build_workflow.Terraform",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 106, "x": 106,
"y": 1153 "y": 973
}, },
"width": 218, "width": 158,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -201,21 +201,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 118, "labelWidth": 113,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.AWS", "id": "build_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 138, "x": 138,
"y": 1462 "y": 1222
}, },
"width": 155, "width": 95,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -242,21 +242,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 55, "labelWidth": 50,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "deploy_workflow", "id": "deploy_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 470, "x": 410,
"y": 0 "y": 0
}, },
"width": 371, "width": 311,
"height": 981, "height": 801,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -283,21 +283,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 247, "labelWidth": 242,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "deploy_workflow.manual", "id": "deploy_workflow.manual",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 520, "x": 460,
"y": 73 "y": 73
}, },
"width": 271, "width": 211,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -324,21 +324,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 171, "labelWidth": 166,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "deploy_workflow.GHA", "id": "deploy_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 521, "x": 461,
"y": 382 "y": 322
}, },
"width": 269, "width": 209,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -365,21 +365,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 169, "labelWidth": 164,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "deploy_workflow.AWS", "id": "deploy_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 578, "x": 518,
"y": 771 "y": 651
}, },
"width": 155, "width": 95,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -406,21 +406,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 55, "labelWidth": 50,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "apollo_workflow", "id": "apollo_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 881, "x": 761,
"y": 0 "y": 0
}, },
"width": 613, "width": 613,
"height": 981, "height": 801,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -447,21 +447,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 232, "labelWidth": 227,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "apollo_workflow.apollo", "id": "apollo_workflow.apollo",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1069, "x": 979,
"y": 73 "y": 73
}, },
"width": 238, "width": 178,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -488,21 +488,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 138, "labelWidth": 133,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "apollo_workflow.GHA", "id": "apollo_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1053, "x": 963,
"y": 382 "y": 322
}, },
"width": 269, "width": 209,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -529,21 +529,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 169, "labelWidth": 164,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "apollo_workflow.AWS", "id": "apollo_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1110, "x": 1020,
"y": 771 "y": 651
}, },
"width": 155, "width": 95,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -570,8 +570,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 55, "labelWidth": 50,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
@ -604,20 +604,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 215, "x": 185,
"y": 210 "y": 150
}, },
{ {
"x": 215, "x": 185,
"y": 278.8 "y": 218.8
}, },
{ {
"x": 215, "x": 185,
"y": 313.2 "y": 253.2
}, },
{ {
"x": 215, "x": 185,
"y": 382 "y": 322
} }
], ],
"isCurve": true, "isCurve": true,
@ -652,20 +652,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 215, "x": 185,
"y": 519 "y": 399
}, },
{ {
"x": 215, "x": 185,
"y": 619.8 "y": 499.8
}, },
{ {
"x": 215, "x": 185,
"y": 670.2 "y": 550.2
}, },
{ {
"x": 215, "x": 185,
"y": 771 "y": 651
} }
], ],
"isCurve": true, "isCurve": true,
@ -700,20 +700,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 215, "x": 185,
"y": 908 "y": 728
}, },
{ {
"x": 215, "x": 185,
"y": 966.4 "y": 786.4
}, },
{ {
"x": 215, "x": 185,
"y": 1084.2 "y": 904.2
}, },
{ {
"x": 215, "x": 185,
"y": 1153 "y": 973
} }
], ],
"isCurve": true, "isCurve": true,
@ -748,20 +748,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 215, "x": 185,
"y": 1290 "y": 1050
}, },
{ {
"x": 215, "x": 185,
"y": 1358.8 "y": 1118.8
}, },
{ {
"x": 215, "x": 185,
"y": 1393.2 "y": 1153.2
}, },
{ {
"x": 215, "x": 185,
"y": 1462 "y": 1222
} }
], ],
"isCurve": true, "isCurve": true,
@ -796,20 +796,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 655.5, "x": 565.5,
"y": 210 "y": 150
}, },
{ {
"x": 655.5, "x": 565.5,
"y": 278.8 "y": 218.8
}, },
{ {
"x": 655.5, "x": 565.5,
"y": 313.2 "y": 253.2
}, },
{ {
"x": 655.5, "x": 565.5,
"y": 382 "y": 322
} }
], ],
"isCurve": true, "isCurve": true,
@ -844,20 +844,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 655.5, "x": 565.5,
"y": 519 "y": 399
}, },
{ {
"x": 655.5, "x": 565.5,
"y": 619.8 "y": 499.8
}, },
{ {
"x": 655.5, "x": 565.5,
"y": 670.2 "y": 550.2
}, },
{ {
"x": 655.5, "x": 565.5,
"y": 771 "y": 651
} }
], ],
"isCurve": true, "isCurve": true,
@ -892,20 +892,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1187.5, "x": 1067.5,
"y": 210 "y": 150
}, },
{ {
"x": 1187.5, "x": 1067.5,
"y": 278.8 "y": 218.8
}, },
{ {
"x": 1187.5, "x": 1067.5,
"y": 313.2 "y": 253.2
}, },
{ {
"x": 1187.5, "x": 1067.5,
"y": 382 "y": 322
} }
], ],
"isCurve": true, "isCurve": true,
@ -940,20 +940,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1187.5, "x": 1067.5,
"y": 519 "y": 399
}, },
{ {
"x": 1187.5, "x": 1067.5,
"y": 619.8 "y": 499.8
}, },
{ {
"x": 1187.5, "x": 1067.5,
"y": 670.2 "y": 550.2
}, },
{ {
"x": 1187.5, "x": 1067.5,
"y": 771 "y": 651
} }
], ],
"isCurve": true, "isCurve": true,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 799 KiB

After

Width:  |  Height:  |  Size: 799 KiB

View file

@ -4,13 +4,13 @@
"shapes": [ "shapes": [
{ {
"id": "build_workflow", "id": "build_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12
}, },
"width": 480, "width": 420,
"height": 1739, "height": 1439,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -37,21 +37,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 226, "labelWidth": 221,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "build_workflow.push", "id": "build_workflow.push",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 87, "x": 87,
"y": 87 "y": 87
}, },
"width": 330, "width": 270,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -78,21 +78,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 230, "labelWidth": 225,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.GHA", "id": "build_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 117, "x": 117,
"y": 450 "y": 390
}, },
"width": 269, "width": 209,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -119,21 +119,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 169, "labelWidth": 164,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.S3", "id": "build_workflow.S3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 186, "x": 186,
"y": 813 "y": 693
}, },
"width": 131, "width": 71,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -160,21 +160,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 31, "labelWidth": 26,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.Terraform", "id": "build_workflow.Terraform",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 143, "x": 143,
"y": 1176 "y": 996
}, },
"width": 218, "width": 158,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -201,21 +201,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 118, "labelWidth": 113,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "build_workflow.AWS", "id": "build_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 174, "x": 174,
"y": 1539 "y": 1299
}, },
"width": 155, "width": 95,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -242,21 +242,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 55, "labelWidth": 50,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "deploy_workflow", "id": "deploy_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 512, "x": 452,
"y": 335 "y": 275
}, },
"width": 421, "width": 361,
"height": 1093, "height": 913,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -283,21 +283,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 247, "labelWidth": 242,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "deploy_workflow.manual", "id": "deploy_workflow.manual",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 587, "x": 527,
"y": 410 "y": 350
}, },
"width": 271, "width": 211,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -324,21 +324,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 171, "labelWidth": 166,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "deploy_workflow.GHA", "id": "deploy_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 588, "x": 528,
"y": 773 "y": 653
}, },
"width": 269, "width": 209,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -365,21 +365,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 169, "labelWidth": 164,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "deploy_workflow.AWS", "id": "deploy_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 645, "x": 585,
"y": 1216 "y": 1036
}, },
"width": 155, "width": 95,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -406,21 +406,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 55, "labelWidth": 50,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "apollo_workflow", "id": "apollo_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 953, "x": 833,
"y": 375 "y": 315
}, },
"width": 684, "width": 684,
"height": 1013, "height": 833,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -447,21 +447,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 232, "labelWidth": 227,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "apollo_workflow.apollo", "id": "apollo_workflow.apollo",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1175, "x": 1085,
"y": 450 "y": 390
}, },
"width": 238, "width": 178,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -488,21 +488,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 138, "labelWidth": 133,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "apollo_workflow.GHA", "id": "apollo_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1160, "x": 1070,
"y": 813 "y": 693
}, },
"width": 269, "width": 209,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -529,21 +529,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 169, "labelWidth": 164,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "apollo_workflow.AWS", "id": "apollo_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1217, "x": 1127,
"y": 1176 "y": 996
}, },
"width": 155, "width": 95,
"height": 137, "height": 77,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -570,8 +570,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 55, "labelWidth": 50,
"labelHeight": 37, "labelHeight": 32,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
@ -604,12 +604,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 252, "x": 222,
"y": 224 "y": 164
}, },
{ {
"x": 252, "x": 222,
"y": 450 "y": 390
} }
], ],
"animated": false, "animated": false,
@ -643,12 +643,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 252, "x": 222,
"y": 587 "y": 467
}, },
{ {
"x": 252, "x": 222,
"y": 813 "y": 693
} }
], ],
"animated": false, "animated": false,
@ -682,12 +682,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 252, "x": 222,
"y": 950 "y": 770
}, },
{ {
"x": 252, "x": 222,
"y": 1176 "y": 996
} }
], ],
"animated": false, "animated": false,
@ -721,12 +721,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 252, "x": 222,
"y": 1313 "y": 1073
}, },
{ {
"x": 252, "x": 222,
"y": 1539 "y": 1299
} }
], ],
"animated": false, "animated": false,
@ -760,12 +760,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 722.5, "x": 632.5,
"y": 547 "y": 427
}, },
{ {
"x": 722.5, "x": 632.5,
"y": 773 "y": 653
} }
], ],
"animated": false, "animated": false,
@ -799,12 +799,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 722.5, "x": 632.5,
"y": 910 "y": 730
}, },
{ {
"x": 722.5, "x": 632.5,
"y": 1216 "y": 1036
} }
], ],
"animated": false, "animated": false,
@ -838,12 +838,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1294.5, "x": 1174.5,
"y": 587 "y": 467
}, },
{ {
"x": 1294.5, "x": 1174.5,
"y": 813 "y": 693
} }
], ],
"animated": false, "animated": false,
@ -877,12 +877,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1294.5, "x": 1174.5,
"y": 950 "y": 770
}, },
{ {
"x": 1294.5, "x": 1174.5,
"y": 1176 "y": 996
} }
], ],
"animated": false, "animated": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 799 KiB

After

Width:  |  Height:  |  Size: 799 KiB

View file

@ -55,7 +55,7 @@
}, },
{ {
"id": "ico", "id": "ico",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 188, "x": 188,
"y": 14 "y": 14

View file

@ -39,7 +39,7 @@ width="492" height="332" viewBox="-102 -102 492 332"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="img"><g class="shape" ><image href="https://icons.terrastruct.com/infra/019-network.svg" x="0" y="0" width="128" height="128" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:2;" /></g></g><g id="ico"><g class="shape" ><rect x="188" y="14" width="100" height="100" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><image href="https://icons.terrastruct.com/infra/019-network.svg" x="213.000000" y="39.000000" width="50" height="50" /></g><mask id="1658185428" maskUnits="userSpaceOnUse" x="-100" y="-100" width="492" height="332"> ]]></script><g id="img"><g class="shape" ><image href="https://icons.terrastruct.com/infra/019-network.svg" x="0" y="0" width="128" height="128" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:2;" /></g></g><g id="ico"><g class="shape" ><rect x="188" y="14" width="100" height="100" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><image href="https://icons.terrastruct.com/infra/019-network.svg" x="213.000000" y="39.000000" width="50" height="50" /></g><mask id="2468208653" maskUnits="userSpaceOnUse" x="-100" y="-100" width="492" height="332">
<rect x="-100" y="-100" width="492" height="332" fill="white"></rect> <rect x="-100" y="-100" width="492" height="332" fill="white"></rect>
</mask><style type="text/css"><![CDATA[]]></style></svg> </mask><style type="text/css"><![CDATA[]]></style></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -55,7 +55,7 @@
}, },
{ {
"id": "ico", "id": "ico",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 160, "x": 160,
"y": 26 "y": 26

View file

@ -39,7 +39,7 @@ width="452" height="332" viewBox="-90 -90 452 332"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="img"><g class="shape" ><image href="https://icons.terrastruct.com/infra/019-network.svg" x="12" y="12" width="128" height="128" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:2;" /></g></g><g id="ico"><g class="shape" ><rect x="160" y="26" width="100" height="100" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><image href="https://icons.terrastruct.com/infra/019-network.svg" x="185.000000" y="51.000000" width="50" height="50" /></g><mask id="2006067969" maskUnits="userSpaceOnUse" x="-100" y="-100" width="452" height="332"> ]]></script><g id="img"><g class="shape" ><image href="https://icons.terrastruct.com/infra/019-network.svg" x="12" y="12" width="128" height="128" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:2;" /></g></g><g id="ico"><g class="shape" ><rect x="160" y="26" width="100" height="100" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><image href="https://icons.terrastruct.com/infra/019-network.svg" x="185.000000" y="51.000000" width="50" height="50" /></g><mask id="882453984" maskUnits="userSpaceOnUse" x="-100" y="-100" width="452" height="332">
<rect x="-100" y="-100" width="452" height="332" fill="white"></rect> <rect x="-100" y="-100" width="452" height="332" fill="white"></rect>
</mask><style type="text/css"><![CDATA[]]></style></svg> </mask><style type="text/css"><![CDATA[]]></style></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -4,13 +4,13 @@
"shapes": [ "shapes": [
{ {
"id": "x", "id": "x",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0
}, },
"width": 426, "width": 306,
"height": 226, "height": 166,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -37,21 +37,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 18, "labelWidth": 13,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "x.a", "id": "x.a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 50, "x": 50,
"y": 50 "y": 50
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -78,21 +78,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "x.b", "id": "x.b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 263, "x": 203,
"y": 50 "y": 50
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -119,8 +119,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
@ -153,56 +153,56 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 163, "x": 103,
"y": 73.37662337662337 "y": 68.38440111420613
}, },
{ {
"x": 189.66666666666669, "x": 129.66666666666669,
"y": 54.675324675324674 "y": 53.67688022284123
}, },
{ {
"x": 198, "x": 138,
"y": 50 "y": 50
}, },
{ {
"x": 200.5, "x": 140.5,
"y": 50 "y": 50
}, },
{ {
"x": 203, "x": 143,
"y": 50 "y": 50
}, },
{ {
"x": 206.33333333333331, "x": 146.33333333333331,
"y": 62.6 "y": 56.6
}, },
{ {
"x": 208.83333333333331, "x": 148.83333333333331,
"y": 81.5 "y": 66.5
}, },
{ {
"x": 211.33333333333334, "x": 151.33333333333334,
"y": 100.4 "y": 76.4
}, },
{ {
"x": 211.33333333333334, "x": 151.33333333333334,
"y": 125.6 "y": 89.6
}, },
{ {
"x": 208.83333333333331, "x": 148.83333333333331,
"y": 144.5 "y": 99.5
}, },
{ {
"x": 206.33333333333331, "x": 146.33333333333331,
"y": 163.4 "y": 109.4
}, },
{ {
"x": 189.66666666666669, "x": 129.66666666666669,
"y": 171.32467532467533 "y": 112.32311977715878
}, },
{ {
"x": 163, "x": 103,
"y": 152.62337662337663 "y": 97.61559888579387
} }
], ],
"isCurve": true, "isCurve": true,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="630" height="430" viewBox="-102 -102 630 430"><style type="text/css"> width="510" height="370" viewBox="-102 -102 510 370"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -39,8 +39,8 @@ width="630" height="430" viewBox="-102 -102 630 430"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="x"><g class="shape" ><rect x="0" y="0" width="426" height="226" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="213.000000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">x</text></g><g id="x.a"><g class="shape" ><rect x="50" y="50" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="106.500000" y="116.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="x.b"><g class="shape" ><rect x="263" y="50" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="319.500000" y="116.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="x.(a -&gt; a)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 164.637464 72.228272 C 189.666667 54.675325 198.000000 50.000000 200.500000 50.000000 C 203.000000 50.000000 206.333333 62.600000 208.833333 81.500000 C 211.333333 100.400000 211.333333 125.600000 208.833333 144.500000 C 206.333333 163.400000 189.666667 171.324675 166.274928 154.920080" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#4032396985)"/></g><mask id="4032396985" maskUnits="userSpaceOnUse" x="-100" y="-100" width="630" height="430"> ]]></script><g id="x"><g class="shape" ><rect x="0" y="0" width="306" height="166" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="153.000000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">x</text></g><g id="x.a"><g class="shape" ><rect x="50" y="50" width="53" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="76.500000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="x.b"><g class="shape" ><rect x="203" y="50" width="53" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="229.500000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="x.(a -&gt; a)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 104.751298 67.418504 C 129.666667 53.676880 138.000000 50.000000 140.500000 50.000000 C 143.000000 50.000000 146.333333 56.600000 148.833333 66.500000 C 151.333333 76.400000 151.333333 89.600000 148.833333 99.500000 C 146.333333 109.400000 129.666667 112.323120 106.502595 99.547392" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2444376964)"/></g><mask id="2444376964" maskUnits="userSpaceOnUse" x="-100" y="-100" width="510" height="370">
<rect x="-100" y="-100" width="630" height="430" fill="white"></rect> <rect x="-100" y="-100" width="510" height="370" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text { .text {

Before

Width:  |  Height:  |  Size: 649 KiB

After

Width:  |  Height:  |  Size: 649 KiB

View file

@ -4,13 +4,13 @@
"shapes": [ "shapes": [
{ {
"id": "x", "id": "x",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12
}, },
"width": 446, "width": 326,
"height": 276, "height": 216,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -37,21 +37,21 @@
"italic": false, "italic": false,
"bold": false, "bold": false,
"underline": false, "underline": false,
"labelWidth": 18, "labelWidth": 13,
"labelHeight": 41, "labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER", "labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "x.a", "id": "x.a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 137, "x": 137,
"y": 87 "y": 87
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -78,21 +78,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "x.b", "id": "x.b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 270, "x": 210,
"y": 87 "y": 87
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -119,8 +119,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
@ -154,19 +154,19 @@
"route": [ "route": [
{ {
"x": 137, "x": 137,
"y": 129 "y": 109
}, },
{ {
"x": 87, "x": 87,
"y": 129 "y": 109
}, },
{ {
"x": 87, "x": 87,
"y": 171 "y": 131
}, },
{ {
"x": 137, "x": 137,
"y": 171 "y": 131
} }
], ],
"animated": false, "animated": false,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="650" height="480" viewBox="-90 -90 650 480"><style type="text/css"> width="530" height="420" viewBox="-90 -90 530 420"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -39,8 +39,8 @@ width="650" height="480" viewBox="-90 -90 650 480"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="x"><g class="shape" ><rect x="12" y="12" width="446" height="276" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="235.000000" y="45.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">x</text></g><g id="x.a"><g class="shape" ><rect x="137" y="87" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="193.500000" y="153.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="x.b"><g class="shape" ><rect x="270" y="87" width="113" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="326.500000" y="153.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="x.(a -&gt; a)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 135.000000 129.000000 L 97.000000 129.000000 S 87.000000 129.000000 87.000000 139.000000 L 87.000000 161.000000 S 87.000000 171.000000 97.000000 171.000000 L 133.000000 171.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#108613724)"/></g><mask id="108613724" maskUnits="userSpaceOnUse" x="-100" y="-100" width="650" height="480"> ]]></script><g id="x"><g class="shape" ><rect x="12" y="12" width="326" height="216" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="175.000000" y="45.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">x</text></g><g id="x.a"><g class="shape" ><rect x="137" y="87" width="53" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="163.500000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="x.b"><g class="shape" ><rect x="210" y="87" width="53" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="236.500000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="x.(a -&gt; a)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 135.000000 109.000000 L 97.000000 109.000000 S 87.000000 109.000000 87.000000 119.000000 L 87.000000 121.000000 S 87.000000 131.000000 97.000000 131.000000 L 133.000000 131.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#672125111)"/></g><mask id="672125111" maskUnits="userSpaceOnUse" x="-100" y="-100" width="530" height="420">
<rect x="-100" y="-100" width="650" height="480" fill="white"></rect> <rect x="-100" y="-100" width="530" height="420" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text { .text {

Before

Width:  |  Height:  |  Size: 649 KiB

After

Width:  |  Height:  |  Size: 649 KiB

View file

@ -9,8 +9,8 @@
"x": 0, "x": 0,
"y": 148 "y": 148
}, },
"width": 1336, "width": 966,
"height": 226, "height": 166,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -44,13 +44,13 @@
}, },
{ {
"id": "queue.M0", "id": "queue.M0",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 50, "x": 50,
"y": 198 "y": 198
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -77,21 +77,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M1", "id": "queue.M1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 235, "x": 175,
"y": 198 "y": 198
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -118,21 +118,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M2", "id": "queue.M2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 420, "x": 300,
"y": 198 "y": 198
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -159,21 +159,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M3", "id": "queue.M3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 605, "x": 425,
"y": 198 "y": 198
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -200,21 +200,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M4", "id": "queue.M4",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 790, "x": 550,
"y": 198 "y": 198
}, },
"width": 126, "width": 66,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -241,21 +241,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 26, "labelWidth": 21,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M5", "id": "queue.M5",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 976, "x": 676,
"y": 198 "y": 198
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -282,21 +282,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M6", "id": "queue.M6",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1161, "x": 851,
"y": 198 "y": 198
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -323,8 +323,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
@ -333,7 +333,7 @@
"id": "m0_desc", "id": "m0_desc",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 60, "x": 30,
"y": 12 "y": 12
}, },
"width": 106, "width": 106,
@ -373,7 +373,7 @@
"id": "m2_desc", "id": "m2_desc",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 462, "x": 312,
"y": 12 "y": 12
}, },
"width": 41, "width": 41,
@ -413,7 +413,7 @@
"id": "m5_desc", "id": "m5_desc",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 994, "x": 664,
"y": 12 "y": 12
}, },
"width": 90, "width": 90,
@ -453,7 +453,7 @@
"id": "m6_desc", "id": "m6_desc",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 1154, "x": 814,
"y": 0 "y": 0
}, },
"width": 140, "width": 140,
@ -517,19 +517,19 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 112.5, "x": 82.5,
"y": 36 "y": 36
}, },
{ {
"x": 112.5, "x": 82.5,
"y": 85.6 "y": 85.6
}, },
{ {
"x": 112.5, "x": 82.5,
"y": 158 "y": 158
}, },
{ {
"x": 112.5, "x": 82.5,
"y": 198 "y": 198
} }
], ],
@ -565,19 +565,19 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 482.5, "x": 332.5,
"y": 36 "y": 36
}, },
{ {
"x": 482.5, "x": 332.5,
"y": 85.6 "y": 85.6
}, },
{ {
"x": 482.5, "x": 332.5,
"y": 158 "y": 158
}, },
{ {
"x": 482.5, "x": 332.5,
"y": 198 "y": 198
} }
], ],
@ -613,19 +613,19 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1038.5, "x": 708.5,
"y": 36 "y": 36
}, },
{ {
"x": 1038.5, "x": 708.5,
"y": 85.6 "y": 85.6
}, },
{ {
"x": 1038.5, "x": 708.5,
"y": 158 "y": 158
}, },
{ {
"x": 1038.5, "x": 708.5,
"y": 198 "y": 198
} }
], ],
@ -661,19 +661,19 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1223.5, "x": 883.5,
"y": 48 "y": 48
}, },
{ {
"x": 1223.5, "x": 883.5,
"y": 88 "y": 88
}, },
{ {
"x": 1223.5, "x": 883.5,
"y": 158 "y": 158
}, },
{ {
"x": 1223.5, "x": 883.5,
"y": 198 "y": 198
} }
], ],

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="1540" height="578" viewBox="-102 -102 1540 578"><style type="text/css"> width="1170" height="518" viewBox="-102 -102 1170 518"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -796,13 +796,13 @@ width="1540" height="578" viewBox="-102 -102 1540 578"><style type="text/css">
.md .contains-task-list:dir(rtl) .task-list-item-checkbox { .md .contains-task-list:dir(rtl) .task-list-item-checkbox {
margin: 0 -1.6em 0.25em 0.2em; margin: 0 -1.6em 0.25em 0.2em;
} }
</style><g id="queue"><g class="shape" ><path d="M 24 148 H 1312 C 1336 148 1336 249.7 1336 261 C 1336 272.3 1336 374 1312 374 H 24 C 0 374 0 272.3 0 261 C 0 249.7 0 148 24 148 Z" style="fill:#DEE1EB;stroke:#0D32B2;stroke-width:2;"/><path d="M 1312 148 C 1288 148 1288 249.7 1288 261 C 1288 272.3 1288 374 1312 374" style="fill:#DEE1EB;stroke:#0D32B2;stroke-width:2;"/></g></g><g id="m0_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="60.000000" y="12.000000" width="106" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Oldest message</p> </style><g id="queue"><g class="shape" ><path d="M 24 148 H 942 C 966 148 966 223 966 231 C 966 239 966 314 942 314 H 24 C 0 314 0 239 0 231 C 0 223 0 148 24 148 Z" style="fill:#DEE1EB;stroke:#0D32B2;stroke-width:2;"/><path d="M 942 148 C 918 148 918 223 918 231 C 918 239 918 314 942 314" style="fill:#DEE1EB;stroke:#0D32B2;stroke-width:2;"/></g></g><g id="m0_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="30.000000" y="12.000000" width="106" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Oldest message</p>
</div></foreignObject></g></g><g id="m2_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="462.000000" y="12.000000" width="41" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Offset</p> </div></foreignObject></g></g><g id="m2_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="312.000000" y="12.000000" width="41" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Offset</p>
</div></foreignObject></g></g><g id="m5_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="994.000000" y="12.000000" width="90" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Last message</p> </div></foreignObject></g></g><g id="m5_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="664.000000" y="12.000000" width="90" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Last message</p>
</div></foreignObject></g></g><g id="m6_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="1154.000000" y="0.000000" width="140" height="48"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Next message will be<br /> </div></foreignObject></g></g><g id="m6_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="814.000000" y="0.000000" width="140" height="48"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Next message will be<br />
inserted here</p> inserted here</p>
</div></foreignObject></g></g><g id="queue.M0"><g class="shape" ><rect x="50" y="198" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="112.500000" y="264.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M0</text></g><g id="queue.M1"><g class="shape" ><rect x="235" y="198" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="297.500000" y="264.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M1</text></g><g id="queue.M2"><g class="shape" ><rect x="420" y="198" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="482.500000" y="264.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M2</text></g><g id="queue.M3"><g class="shape" ><rect x="605" y="198" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="667.500000" y="264.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M3</text></g><g id="queue.M4"><g class="shape" ><rect x="790" y="198" width="126" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="853.000000" y="264.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M4</text></g><g id="queue.M5"><g class="shape" ><rect x="976" y="198" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1038.500000" y="264.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M5</text></g><g id="queue.M6"><g class="shape" ><rect x="1161" y="198" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1223.500000" y="264.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M6</text></g><g id="(m0_desc -&gt; queue.M0)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 112.500000 38.000000 C 112.500000 85.600000 112.500000 158.000000 112.500000 194.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2000745678)"/></g><g id="(m2_desc -&gt; queue.M2)[0]"><path d="M 482.500000 38.000000 C 482.500000 85.600000 482.500000 158.000000 482.500000 194.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2000745678)"/></g><g id="(m5_desc -&gt; queue.M5)[0]"><path d="M 1038.500000 38.000000 C 1038.500000 85.600000 1038.500000 158.000000 1038.500000 194.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2000745678)"/></g><g id="(m6_desc -&gt; queue.M6)[0]"><path d="M 1223.500000 50.000000 C 1223.500000 88.000000 1223.500000 158.000000 1223.500000 194.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2000745678)"/></g><mask id="2000745678" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1540" height="578"> </div></foreignObject></g></g><g id="queue.M0"><g class="shape" ><rect x="50" y="198" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="82.500000" y="236.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M0</text></g><g id="queue.M1"><g class="shape" ><rect x="175" y="198" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="207.500000" y="236.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M1</text></g><g id="queue.M2"><g class="shape" ><rect x="300" y="198" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="332.500000" y="236.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M2</text></g><g id="queue.M3"><g class="shape" ><rect x="425" y="198" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="457.500000" y="236.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M3</text></g><g id="queue.M4"><g class="shape" ><rect x="550" y="198" width="66" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="583.000000" y="236.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M4</text></g><g id="queue.M5"><g class="shape" ><rect x="676" y="198" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="708.500000" y="236.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M5</text></g><g id="queue.M6"><g class="shape" ><rect x="851" y="198" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="883.500000" y="236.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M6</text></g><g id="(m0_desc -&gt; queue.M0)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 82.500000 38.000000 C 82.500000 85.600000 82.500000 158.000000 82.500000 194.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1051552217)"/></g><g id="(m2_desc -&gt; queue.M2)[0]"><path d="M 332.500000 38.000000 C 332.500000 85.600000 332.500000 158.000000 332.500000 194.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1051552217)"/></g><g id="(m5_desc -&gt; queue.M5)[0]"><path d="M 708.500000 38.000000 C 708.500000 85.600000 708.500000 158.000000 708.500000 194.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1051552217)"/></g><g id="(m6_desc -&gt; queue.M6)[0]"><path d="M 883.500000 50.000000 C 883.500000 88.000000 883.500000 158.000000 883.500000 194.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1051552217)"/></g><mask id="1051552217" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1170" height="518">
<rect x="-100" y="-100" width="1540" height="578" fill="white"></rect> <rect x="-100" y="-100" width="1170" height="518" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text { .text {

Before

Width:  |  Height:  |  Size: 664 KiB

After

Width:  |  Height:  |  Size: 664 KiB

View file

@ -9,8 +9,8 @@
"x": 12, "x": 12,
"y": 165 "y": 165
}, },
"width": 1146, "width": 726,
"height": 276, "height": 216,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -44,13 +44,13 @@
}, },
{ {
"id": "queue.M0", "id": "queue.M0",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 87, "x": 87,
"y": 240 "y": 240
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -77,21 +77,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M1", "id": "queue.M1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 232, "x": 172,
"y": 240 "y": 240
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -118,21 +118,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M2", "id": "queue.M2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 377, "x": 257,
"y": 240 "y": 240
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -159,21 +159,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M3", "id": "queue.M3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 522, "x": 342,
"y": 240 "y": 240
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -200,21 +200,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M4", "id": "queue.M4",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 667, "x": 427,
"y": 240 "y": 240
}, },
"width": 126, "width": 66,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -241,21 +241,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 26, "labelWidth": 21,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M5", "id": "queue.M5",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 813, "x": 513,
"y": 240 "y": 240
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -282,21 +282,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{ {
"id": "queue.M6", "id": "queue.M6",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 958, "x": 598,
"y": 240 "y": 240
}, },
"width": 125, "width": 65,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -323,8 +323,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 25, "labelWidth": 20,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
@ -333,7 +333,7 @@
"id": "m0_desc", "id": "m0_desc",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 96, "x": 66,
"y": 36 "y": 36
}, },
"width": 106, "width": 106,
@ -373,7 +373,7 @@
"id": "m2_desc", "id": "m2_desc",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 419, "x": 269,
"y": 36 "y": 36
}, },
"width": 41, "width": 41,
@ -413,7 +413,7 @@
"id": "m5_desc", "id": "m5_desc",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 830, "x": 450,
"y": 36 "y": 36
}, },
"width": 90, "width": 90,
@ -453,7 +453,7 @@
"id": "m6_desc", "id": "m6_desc",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 950, "x": 560,
"y": 12 "y": 12
}, },
"width": 140, "width": 140,
@ -517,11 +517,11 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 149.5, "x": 119.5,
"y": 60 "y": 60
}, },
{ {
"x": 149.5, "x": 119.5,
"y": 240 "y": 240
} }
], ],
@ -556,11 +556,11 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 439.5, "x": 289.5,
"y": 60 "y": 60
}, },
{ {
"x": 439.5, "x": 289.5,
"y": 240 "y": 240
} }
], ],
@ -595,11 +595,19 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 875.5, "x": 495.5,
"y": 60 "y": 60
}, },
{ {
"x": 875.5, "x": 495.5,
"y": 110
},
{
"x": 545.5,
"y": 110
},
{
"x": 545.5,
"y": 240 "y": 240
} }
], ],
@ -634,11 +642,11 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 1020.5, "x": 630.5,
"y": 60 "y": 60
}, },
{ {
"x": 1020.5, "x": 630.5,
"y": 240 "y": 240
} }
], ],

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="1350" height="633" viewBox="-90 -90 1350 633"><style type="text/css"> width="930" height="573" viewBox="-90 -90 930 573"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -796,13 +796,13 @@ width="1350" height="633" viewBox="-90 -90 1350 633"><style type="text/css">
.md .contains-task-list:dir(rtl) .task-list-item-checkbox { .md .contains-task-list:dir(rtl) .task-list-item-checkbox {
margin: 0 -1.6em 0.25em 0.2em; margin: 0 -1.6em 0.25em 0.2em;
} }
</style><g id="queue"><g class="shape" ><path d="M 36 165 H 1134 C 1158 165 1158 289.2 1158 303 C 1158 316.8 1158 441 1134 441 H 36 C 12 441 12 316.8 12 303 C 12 289.2 12 165 36 165 Z" style="fill:#DEE1EB;stroke:#0D32B2;stroke-width:2;"/><path d="M 1134 165 C 1110 165 1110 289.2 1110 303 C 1110 316.8 1110 441 1134 441" style="fill:#DEE1EB;stroke:#0D32B2;stroke-width:2;"/></g></g><g id="m0_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="96.000000" y="36.000000" width="106" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Oldest message</p> </style><g id="queue"><g class="shape" ><path d="M 36 165 H 714 C 738 165 738 262 738 273 C 738 284 738 381 714 381 H 36 C 12 381 12 284 12 273 C 12 262 12 165 36 165 Z" style="fill:#DEE1EB;stroke:#0D32B2;stroke-width:2;"/><path d="M 714 165 C 690 165 690 262 690 273 C 690 284 690 381 714 381" style="fill:#DEE1EB;stroke:#0D32B2;stroke-width:2;"/></g></g><g id="m0_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="66.000000" y="36.000000" width="106" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Oldest message</p>
</div></foreignObject></g></g><g id="m2_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="419.000000" y="36.000000" width="41" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Offset</p> </div></foreignObject></g></g><g id="m2_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="269.000000" y="36.000000" width="41" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Offset</p>
</div></foreignObject></g></g><g id="m5_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="830.000000" y="36.000000" width="90" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Last message</p> </div></foreignObject></g></g><g id="m5_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="450.000000" y="36.000000" width="90" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Last message</p>
</div></foreignObject></g></g><g id="m6_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="950.000000" y="12.000000" width="140" height="48"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Next message will be<br /> </div></foreignObject></g></g><g id="m6_desc"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="560.000000" y="12.000000" width="140" height="48"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>Next message will be<br />
inserted here</p> inserted here</p>
</div></foreignObject></g></g><g id="queue.M0"><g class="shape" ><rect x="87" y="240" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="149.500000" y="306.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M0</text></g><g id="queue.M1"><g class="shape" ><rect x="232" y="240" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="294.500000" y="306.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M1</text></g><g id="queue.M2"><g class="shape" ><rect x="377" y="240" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="439.500000" y="306.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M2</text></g><g id="queue.M3"><g class="shape" ><rect x="522" y="240" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="584.500000" y="306.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M3</text></g><g id="queue.M4"><g class="shape" ><rect x="667" y="240" width="126" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="730.000000" y="306.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M4</text></g><g id="queue.M5"><g class="shape" ><rect x="813" y="240" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="875.500000" y="306.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M5</text></g><g id="queue.M6"><g class="shape" ><rect x="958" y="240" width="125" height="126" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1020.500000" y="306.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M6</text></g><g id="(m0_desc -&gt; queue.M0)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 149.500000 62.000000 L 149.500000 236.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1429777714)"/></g><g id="(m2_desc -&gt; queue.M2)[0]"><path d="M 439.500000 62.000000 L 439.500000 236.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1429777714)"/></g><g id="(m5_desc -&gt; queue.M5)[0]"><path d="M 875.500000 62.000000 L 875.500000 236.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1429777714)"/></g><g id="(m6_desc -&gt; queue.M6)[0]"><path d="M 1020.500000 62.000000 L 1020.500000 236.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1429777714)"/></g><mask id="1429777714" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1350" height="633"> </div></foreignObject></g></g><g id="queue.M0"><g class="shape" ><rect x="87" y="240" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="119.500000" y="278.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M0</text></g><g id="queue.M1"><g class="shape" ><rect x="172" y="240" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="204.500000" y="278.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M1</text></g><g id="queue.M2"><g class="shape" ><rect x="257" y="240" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="289.500000" y="278.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M2</text></g><g id="queue.M3"><g class="shape" ><rect x="342" y="240" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="374.500000" y="278.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M3</text></g><g id="queue.M4"><g class="shape" ><rect x="427" y="240" width="66" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="460.000000" y="278.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M4</text></g><g id="queue.M5"><g class="shape" ><rect x="513" y="240" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="545.500000" y="278.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M5</text></g><g id="queue.M6"><g class="shape" ><rect x="598" y="240" width="65" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="630.500000" y="278.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">M6</text></g><g id="(m0_desc -&gt; queue.M0)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 119.500000 62.000000 L 119.500000 236.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2142408228)"/></g><g id="(m2_desc -&gt; queue.M2)[0]"><path d="M 289.500000 62.000000 L 289.500000 236.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2142408228)"/></g><g id="(m5_desc -&gt; queue.M5)[0]"><path d="M 495.500000 62.000000 L 495.500000 100.000000 S 495.500000 110.000000 505.500000 110.000000 L 535.500000 110.000000 S 545.500000 110.000000 545.500000 120.000000 L 545.500000 236.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2142408228)"/></g><g id="(m6_desc -&gt; queue.M6)[0]"><path d="M 630.500000 62.000000 L 630.500000 236.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2142408228)"/></g><mask id="2142408228" maskUnits="userSpaceOnUse" x="-100" y="-100" width="930" height="573">
<rect x="-100" y="-100" width="1350" height="633" fill="white"></rect> <rect x="-100" y="-100" width="930" height="573" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text { .text {

Before

Width:  |  Height:  |  Size: 664 KiB

After

Width:  |  Height:  |  Size: 664 KiB

View file

@ -0,0 +1,104 @@
{
"name": "",
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "class1",
"type": "class",
"pos": {
"x": 0,
"y": 0
},
"width": 319,
"height": 184,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#0A0F25",
"stroke": "#FFFFFF",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": [
{
"name": "num",
"type": "int",
"visibility": "private"
},
{
"name": "timeout",
"type": "int",
"visibility": "private"
}
],
"methods": null,
"columns": null,
"label": "class with rows",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 214,
"labelHeight": 31,
"zIndex": 0,
"level": 1,
"primaryAccentColor": "#0D32B2",
"secondaryAccentColor": "#4A6FF3",
"neutralAccentColor": "#676C7E"
},
{
"id": "class2",
"type": "class",
"pos": {
"x": 379,
"y": 46
},
"width": 362,
"height": 92,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#0A0F25",
"stroke": "#FFFFFF",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "class without rows",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 257,
"labelHeight": 31,
"zIndex": 0,
"level": 1,
"primaryAccentColor": "#0D32B2",
"secondaryAccentColor": "#4A6FF3",
"neutralAccentColor": "#676C7E"
}
],
"connections": []
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 184 KiB

View file

@ -0,0 +1,104 @@
{
"name": "",
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "class1",
"type": "class",
"pos": {
"x": 12,
"y": 12
},
"width": 319,
"height": 184,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#0A0F25",
"stroke": "#FFFFFF",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": [
{
"name": "num",
"type": "int",
"visibility": "private"
},
{
"name": "timeout",
"type": "int",
"visibility": "private"
}
],
"methods": null,
"columns": null,
"label": "class with rows",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 214,
"labelHeight": 31,
"zIndex": 0,
"level": 1,
"primaryAccentColor": "#0D32B2",
"secondaryAccentColor": "#4A6FF3",
"neutralAccentColor": "#676C7E"
},
{
"id": "class2",
"type": "class",
"pos": {
"x": 351,
"y": 58
},
"width": 362,
"height": 92,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#0A0F25",
"stroke": "#FFFFFF",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "class without rows",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 257,
"labelHeight": 31,
"zIndex": 0,
"level": 1,
"primaryAccentColor": "#0D32B2",
"secondaryAccentColor": "#4A6FF3",
"neutralAccentColor": "#676C7E"
}
],
"connections": []
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 184 KiB

View file

@ -9,8 +9,8 @@
"x": 13, "x": 13,
"y": 0 "y": 0
}, },
"width": 140, "width": 80,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 0, "strokeWidth": 0,
@ -37,8 +37,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 40, "labelWidth": 35,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
@ -48,10 +48,10 @@
"type": "sequence_diagram", "type": "sequence_diagram",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 226 "y": 166
}, },
"width": 166, "width": 106,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 0, "strokeWidth": 0,
@ -78,8 +78,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 66, "labelWidth": 61,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
@ -112,20 +112,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 83, "x": 53,
"y": 66
},
{
"x": 53,
"y": 106
},
{
"x": 53,
"y": 126 "y": 126
}, },
{ {
"x": 83, "x": 53,
"y": 166 "y": 166
},
{
"x": 83,
"y": 186
},
{
"x": 83,
"y": 226
} }
], ],
"isCurve": true, "isCurve": true,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="366" height="552" viewBox="-100 -100 366 552"><style type="text/css"> width="306" height="432" viewBox="-100 -100 306 432"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -39,8 +39,8 @@ width="366" height="552" viewBox="-100 -100 366 552"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="A"><g class="shape" ><rect x="13" y="0" width="140" height="126" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text-bold" x="83.000000" y="66.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">hello</text></g><g id="B"><g class="shape" ><rect x="0" y="226" width="166" height="126" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text-bold" x="83.000000" y="292.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">goodbye</text></g><g id="(A -&gt; B)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 83.000000 127.000000 C 83.000000 166.000000 83.000000 186.000000 83.000000 223.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3673457740)"/></g><mask id="3673457740" maskUnits="userSpaceOnUse" x="-100" y="-100" width="366" height="552"> ]]></script><g id="A"><g class="shape" ><rect x="13" y="0" width="80" height="66" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text-bold" x="53.000000" y="38.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">hello</text></g><g id="B"><g class="shape" ><rect x="0" y="166" width="106" height="66" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text-bold" x="53.000000" y="204.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">goodbye</text></g><g id="(A -&gt; B)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 53.000000 67.000000 C 53.000000 106.000000 53.000000 126.000000 53.000000 163.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#584752433)"/></g><mask id="584752433" maskUnits="userSpaceOnUse" x="-100" y="-100" width="306" height="432">
<rect x="-100" y="-100" width="366" height="552" fill="white"></rect> <rect x="-100" y="-100" width="306" height="432" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text-bold { .text-bold {

Before

Width:  |  Height:  |  Size: 325 KiB

After

Width:  |  Height:  |  Size: 325 KiB

View file

@ -9,8 +9,8 @@
"x": 25, "x": 25,
"y": 12 "y": 12
}, },
"width": 140, "width": 80,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 0, "strokeWidth": 0,
@ -37,8 +37,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 40, "labelWidth": 35,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
@ -48,10 +48,10 @@
"type": "sequence_diagram", "type": "sequence_diagram",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 238 "y": 178
}, },
"width": 166, "width": 106,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 0, "strokeWidth": 0,
@ -78,8 +78,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 66, "labelWidth": 61,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
@ -112,12 +112,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 95, "x": 65,
"y": 138 "y": 78
}, },
{ {
"x": 95, "x": 65,
"y": 238 "y": 178
} }
], ],
"animated": false, "animated": false,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="366" height="552" viewBox="-88 -88 366 552"><style type="text/css"> width="306" height="432" viewBox="-88 -88 306 432"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -39,8 +39,8 @@ width="366" height="552" viewBox="-88 -88 366 552"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="A"><g class="shape" ><rect x="25" y="12" width="140" height="126" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text-bold" x="95.000000" y="78.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">hello</text></g><g id="B"><g class="shape" ><rect x="12" y="238" width="166" height="126" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text-bold" x="95.000000" y="304.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">goodbye</text></g><g id="(A -&gt; B)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 95.000000 139.000000 L 95.000000 235.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3245083993)"/></g><mask id="3245083993" maskUnits="userSpaceOnUse" x="-100" y="-100" width="366" height="552"> ]]></script><g id="A"><g class="shape" ><rect x="25" y="12" width="80" height="66" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text-bold" x="65.000000" y="50.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">hello</text></g><g id="B"><g class="shape" ><rect x="12" y="178" width="106" height="66" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text-bold" x="65.000000" y="216.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">goodbye</text></g><g id="(A -&gt; B)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 65.000000 79.000000 L 65.000000 175.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2561647952)"/></g><mask id="2561647952" maskUnits="userSpaceOnUse" x="-100" y="-100" width="306" height="432">
<rect x="-100" y="-100" width="366" height="552" fill="white"></rect> <rect x="-100" y="-100" width="306" height="432" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text-bold { .text-bold {

Before

Width:  |  Height:  |  Size: 325 KiB

After

Width:  |  Height:  |  Size: 325 KiB

View file

@ -6,8 +6,8 @@
"id": "md", "id": "md",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 9, "x": 0,
"y": 226 "y": 166
}, },
"width": 95, "width": 95,
"height": 115, "height": 115,
@ -44,13 +44,13 @@
}, },
{ {
"id": "a", "id": "a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 21,
"y": 0 "y": 0
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -77,21 +77,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "b", "id": "b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 21,
"y": 441 "y": 381
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -118,8 +118,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
@ -152,20 +152,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 56.5, "x": 47.5,
"y": 66
},
{
"x": 47.5,
"y": 106
},
{
"x": 47.5,
"y": 126 "y": 126
}, },
{ {
"x": 56.5, "x": 47.5,
"y": 166 "y": 166
},
{
"x": 56.5,
"y": 186
},
{
"x": 56.5,
"y": 226
} }
], ],
"isCurve": true, "isCurve": true,
@ -200,20 +200,20 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 56.5, "x": 47.5,
"y": 281
},
{
"x": 47.5,
"y": 321
},
{
"x": 47.5,
"y": 341 "y": 341
}, },
{ {
"x": 56.5, "x": 47.5,
"y": 381 "y": 381
},
{
"x": 56.5,
"y": 401
},
{
"x": 56.5,
"y": 441
} }
], ],
"isCurve": true, "isCurve": true,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="317" height="771" viewBox="-102 -102 317 771"><style type="text/css"> width="299" height="651" viewBox="-102 -102 299 651"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -796,7 +796,7 @@ width="317" height="771" viewBox="-102 -102 317 771"><style type="text/css">
.md .contains-task-list:dir(rtl) .task-list-item-checkbox { .md .contains-task-list:dir(rtl) .task-list-item-checkbox {
margin: 0 -1.6em 0.25em 0.2em; margin: 0 -1.6em 0.25em 0.2em;
} }
</style><g id="md"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="9.000000" y="226.000000" width="95" height="115"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><h1>hey</h1> </style><g id="md"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="0.000000" y="166.000000" width="95" height="115"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><h1>hey</h1>
<ul> <ul>
<li>they <li>they
<ol> <ol>
@ -804,8 +804,8 @@ width="317" height="771" viewBox="-102 -102 317 771"><style type="text/css">
</ol> </ol>
</li> </li>
</ul> </ul>
</div></foreignObject></g></g><g id="a"><g class="shape" ><rect x="0" y="0" width="113" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="56.500000" y="66.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="b"><g class="shape" ><rect x="0" y="441" width="113" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="56.500000" y="507.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="(a -&gt; md)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 56.500000 128.000000 C 56.500000 166.000000 56.500000 186.000000 56.500000 222.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2837502795)"/></g><g id="(md -&gt; b)[0]"><path d="M 56.500000 343.000000 C 56.500000 381.000000 56.500000 401.000000 56.500000 437.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2837502795)"/></g><mask id="2837502795" maskUnits="userSpaceOnUse" x="-100" y="-100" width="317" height="771"> </div></foreignObject></g></g><g id="a"><g class="shape" ><rect x="21" y="0" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="47.500000" y="38.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="b"><g class="shape" ><rect x="21" y="381" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="47.500000" y="419.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="(a -&gt; md)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 47.500000 68.000000 C 47.500000 106.000000 47.500000 126.000000 47.500000 162.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#817120199)"/></g><g id="(md -&gt; b)[0]"><path d="M 47.500000 283.000000 C 47.500000 321.000000 47.500000 341.000000 47.500000 377.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#817120199)"/></g><mask id="817120199" maskUnits="userSpaceOnUse" x="-100" y="-100" width="299" height="651">
<rect x="-100" y="-100" width="317" height="771" fill="white"></rect> <rect x="-100" y="-100" width="299" height="651" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text { .text {

Before

Width:  |  Height:  |  Size: 661 KiB

After

Width:  |  Height:  |  Size: 661 KiB

View file

@ -6,8 +6,8 @@
"id": "md", "id": "md",
"type": "text", "type": "text",
"pos": { "pos": {
"x": 21, "x": 12,
"y": 238 "y": 178
}, },
"width": 95, "width": 95,
"height": 115, "height": 115,
@ -44,13 +44,13 @@
}, },
{ {
"id": "a", "id": "a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 33,
"y": 12 "y": 12
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -77,21 +77,21 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{ {
"id": "b", "id": "b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 33,
"y": 453 "y": 393
}, },
"width": 113, "width": 53,
"height": 126, "height": 66,
"opacity": 1, "opacity": 1,
"strokeDash": 0, "strokeDash": 0,
"strokeWidth": 2, "strokeWidth": 2,
@ -118,8 +118,8 @@
"italic": false, "italic": false,
"bold": true, "bold": true,
"underline": false, "underline": false,
"labelWidth": 13, "labelWidth": 8,
"labelHeight": 26, "labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER", "labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
@ -152,12 +152,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 68.5, "x": 59.5,
"y": 138 "y": 78
}, },
{ {
"x": 68.5, "x": 59.5,
"y": 238 "y": 178
} }
], ],
"animated": false, "animated": false,
@ -191,12 +191,12 @@
"labelPercentage": 0, "labelPercentage": 0,
"route": [ "route": [
{ {
"x": 68.5, "x": 59.5,
"y": 353 "y": 293
}, },
{ {
"x": 68.5, "x": 59.5,
"y": 453 "y": 393
} }
], ],
"animated": false, "animated": false,

View file

@ -3,7 +3,7 @@
id="d2-svg" id="d2-svg"
style="background: white;" style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="317" height="771" viewBox="-90 -90 317 771"><style type="text/css"> width="299" height="651" viewBox="-90 -90 299 651"><style type="text/css">
<![CDATA[ <![CDATA[
.shape { .shape {
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@ -796,7 +796,7 @@ width="317" height="771" viewBox="-90 -90 317 771"><style type="text/css">
.md .contains-task-list:dir(rtl) .task-list-item-checkbox { .md .contains-task-list:dir(rtl) .task-list-item-checkbox {
margin: 0 -1.6em 0.25em 0.2em; margin: 0 -1.6em 0.25em 0.2em;
} }
</style><g id="md"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="21.000000" y="238.000000" width="95" height="115"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><h1>hey</h1> </style><g id="md"><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="12.000000" y="178.000000" width="95" height="115"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><h1>hey</h1>
<ul> <ul>
<li>they <li>they
<ol> <ol>
@ -804,8 +804,8 @@ width="317" height="771" viewBox="-90 -90 317 771"><style type="text/css">
</ol> </ol>
</li> </li>
</ul> </ul>
</div></foreignObject></g></g><g id="a"><g class="shape" ><rect x="12" y="12" width="113" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="68.500000" y="78.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="b"><g class="shape" ><rect x="12" y="453" width="113" height="126" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="68.500000" y="519.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="(a -&gt; md)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 68.500000 140.000000 L 68.500000 234.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2378193313)"/></g><g id="(md -&gt; b)[0]"><path d="M 68.500000 355.000000 L 68.500000 449.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2378193313)"/></g><mask id="2378193313" maskUnits="userSpaceOnUse" x="-100" y="-100" width="317" height="771"> </div></foreignObject></g></g><g id="a"><g class="shape" ><rect x="33" y="12" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="59.500000" y="50.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="b"><g class="shape" ><rect x="33" y="393" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="59.500000" y="431.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="(a -&gt; md)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 59.500000 80.000000 L 59.500000 174.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#500331167)"/></g><g id="(md -&gt; b)[0]"><path d="M 59.500000 295.000000 L 59.500000 389.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#500331167)"/></g><mask id="500331167" maskUnits="userSpaceOnUse" x="-100" y="-100" width="299" height="651">
<rect x="-100" y="-100" width="317" height="771" fill="white"></rect> <rect x="-100" y="-100" width="299" height="651" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[
.text { .text {

Before

Width:  |  Height:  |  Size: 660 KiB

After

Width:  |  Height:  |  Size: 660 KiB

Some files were not shown because too many files have changed in this diff Show more