Merge branch 'master' into shape-specific-inner-boxes

This commit is contained in:
Gavin Nishizawa 2023-02-02 20:25:52 -08:00
commit 4bfb6af7e6
No known key found for this signature in database
GPG key ID: AE3B177777CE55CD
807 changed files with 43953 additions and 14663 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,6 +222,9 @@ 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-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)
- **CIL (C#, Visual Basic, F#, C++ CLR) to D2**: [https://github.com/HugoVG/AppDiagram](https://github.com/HugoVG/AppDiagram)
### Misc ### Misc

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

@ -7,6 +7,15 @@
- `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 🧹
- Reduces default padding of shapes. [#702](https://github.com/terrastruct/d2/pull/702) - Reduces default padding of shapes. [#702](https://github.com/terrastruct/d2/pull/702)

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)
} }

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"
@ -25,25 +26,26 @@ import (
const INNER_LABEL_PADDING int = 5 const INNER_LABEL_PADDING int = 5
const DEFAULT_SHAPE_SIZE = 100. const DEFAULT_SHAPE_SIZE = 100.
// 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 {
AST *d2ast.Map `json:"ast"` Name string `json:"name"`
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
} }
@ -83,7 +85,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,7 +108,8 @@ type Attributes struct {
// TODO: default to ShapeRectangle instead of empty string // TODO: default to ShapeRectangle instead of empty string
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
@ -117,9 +120,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 {
@ -501,10 +502,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,
@ -524,6 +528,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 {
@ -558,6 +565,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()
@ -638,34 +646,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] == "_" {
@ -850,7 +895,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"`
} }
@ -922,15 +967,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 {
@ -939,15 +975,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,
}, },
@ -957,10 +993,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
@ -1268,19 +1341,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": {},
@ -1347,15 +1418,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"})
@ -425,13 +425,15 @@ func TestSequenceToDescendant(t *testing.T) {
g.Edges = []*d2graph.Edge{ g.Edges = []*d2graph.Edge{
{ {
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

@ -231,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
@ -330,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
} }
d, err := compile(ctx, g, opts)
if err != nil {
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 { if len(g.Objects) > 0 {
err = g.SetDimensions(opts.MeasuredTexts, opts.Ruler, opts.FontFamily) err := g.SetDimensions(opts.MeasuredTexts, opts.Ruler, opts.FontFamily)
if err != nil { if err != nil {
return nil, nil, err 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())
sb.WriteByte('\n')
} }
for _, err := range pe.Errors { for i, err := range pe.Errors {
if pe.IOError != nil || i > 0 {
sb.WriteByte('\n')
}
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: 253 KiB

After

Width:  |  Height:  |  Size: 253 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 303 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: 246 KiB

After

Width:  |  Height:  |  Size: 246 KiB

View file

@ -809,9 +809,9 @@ width="1096" height="481" viewBox="-100 -102 1096 481"><style type="text/css">
</pattern> </pattern>
</defs><g id="x" style='opacity:0.400000'><g class="shape" ><path class="shape" transform="translate(162 3)" d="M-1.600310 -0.578379 L55.045551 1.811030 L54.253697 64.234072 L0.925556 67.532483" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /><path class="shape" transform="translate(162 3)" d="M0.857263 0.963884 C10.480488 0.944302, 21.040361 -1.949033, 53.206405 0.392335 M-0.648665 0.264598 C12.392454 0.347446, 23.992396 -0.222226, 53.419625 0.752815 M55.536704 -1.749433 C54.489431 15.585410, 55.180967 27.069513, 55.390547 65.130645 M54.297677 -0.799274 C54.657560 16.854002, 53.681091 35.455552, 54.406876 66.352243 M55.052801 65.786559 C43.384114 66.875371, 29.023779 66.331846, 1.836456 65.596476 M53.056573 65.856267 C33.612847 66.387434, 14.197363 66.115970, 0.938949 66.041844 M-0.720604 65.718532 C0.302797 45.542204, -1.429636 28.321166, 0.591800 -1.206080 M0.217956 66.998223 C-1.587850 41.337487, -1.081795 17.082362, 0.440740 0.988030" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /><rect class="sketch-overlay" transform="translate(162 3)" width="54" height="66" /></g><text class="text-bold" x="189.000000" y="41.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">x</text></g><g id="y" style='opacity:0.400000'><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="276.000000" y="24.000000" width="347" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>linux: because a PC is a terrible thing to waste</p> </defs><g id="x" style='opacity:0.400000'><g class="shape" ><path class="shape" transform="translate(162 3)" d="M-1.600310 -0.578379 L55.045551 1.811030 L54.253697 64.234072 L0.925556 67.532483" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /><path class="shape" transform="translate(162 3)" d="M0.857263 0.963884 C10.480488 0.944302, 21.040361 -1.949033, 53.206405 0.392335 M-0.648665 0.264598 C12.392454 0.347446, 23.992396 -0.222226, 53.419625 0.752815 M55.536704 -1.749433 C54.489431 15.585410, 55.180967 27.069513, 55.390547 65.130645 M54.297677 -0.799274 C54.657560 16.854002, 53.681091 35.455552, 54.406876 66.352243 M55.052801 65.786559 C43.384114 66.875371, 29.023779 66.331846, 1.836456 65.596476 M53.056573 65.856267 C33.612847 66.387434, 14.197363 66.115970, 0.938949 66.041844 M-0.720604 65.718532 C0.302797 45.542204, -1.429636 28.321166, 0.591800 -1.206080 M0.217956 66.998223 C-1.587850 41.337487, -1.081795 17.082362, 0.440740 0.988030" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /><rect class="sketch-overlay" transform="translate(162 3)" width="54" height="66" /></g><text class="text-bold" x="189.000000" y="41.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">x</text></g><g id="y" style='opacity:0.400000'><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="276.000000" y="24.000000" width="347" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>linux: because a PC is a terrible thing to waste</p>
</div></foreignObject></g></g><g id="users" style='opacity:0.400000'><g class="shape" ><path class="shape" transform="translate(683 0)" d="M-1.600310 -0.578379 L212.045551 1.811030 L211.253697 70.234072 L0.925556 73.532483" style="fill:#FFFFFF;stroke:#0A0F25;stroke-width:2;" /><path class="shape" transform="translate(683 0)" d="M0.755797 0.849798 C41.919041 0.271510, 83.908070 -2.279368, 210.300335 0.345898 M-0.571888 0.233280 C47.092687 -0.888816, 93.486665 -1.391062, 210.488319 0.663711 M212.536704 -1.749433 C211.434025 16.890424, 212.125561 29.679541, 212.390547 71.130645 M211.297677 -0.799274 C211.695335 18.464376, 210.718866 38.676301, 211.406876 72.352243 M211.928191 71.811822 C166.401573 75.510374, 118.501892 75.031181, 1.619092 71.644237 M210.168238 71.873280 C131.604972 72.658440, 53.066606 72.419106, 0.827814 72.036891 M-0.720604 71.718532 C0.215708 49.821348, -1.516724 30.879454, 0.591800 -1.206080 M0.217956 72.998223 C-1.661676 45.154890, -1.155622 18.717167, 0.440740 0.988030" style="fill:#FFFFFF;stroke:#0A0F25;stroke-width:2;" /><path class="class_header" transform="translate(683 0)" d="M-1.600310 -0.578379 L212.045551 1.811030 L211.253697 34.234072 L0.925556 37.532483" style="fill:#0A0F25" /><path class="class_header" transform="translate(683 0)" d="M0.755797 0.849798 C41.919041 0.271510, 83.908070 -2.279368, 210.300335 0.345898 M-0.571888 0.233280 C47.092687 -0.888816, 93.486665 -1.391062, 210.488319 0.663711 M212.536704 -1.749433 C211.766465 9.060341, 212.458000 14.019375, 212.390547 35.130645 M211.297677 -0.799274 C211.468683 8.802129, 210.492215 19.351806, 211.406876 36.352243 M211.928191 35.811822 C166.401573 39.510374, 118.501892 39.031181, 1.619092 35.644237 M210.168238 35.873280 C131.604972 36.658440, 53.066606 36.419106, 0.827814 36.036891 M-0.720604 35.718532 C0.738237 24.146483, -0.994195 15.529725, 0.591800 -1.206080 M0.217956 36.998223 C-1.218717 22.250475, -0.712663 8.908338, 0.440740 0.988030" style="fill:#0A0F25" /><text class="text" x="703.000000" y="27.000000" style="text-anchor:start;font-size:24px;fill:#FFFFFF">users</text><text class="text" x="693.000000" y="59.000000" style="text-anchor:start;font-size:20px;fill:#0D32B2">last_login</text> </div></foreignObject></g></g><g id="a"><g class="shape" ><path class="shape" transform="translate(162 211)" d="M-1.600310 -0.578379 L55.045551 1.811030 L54.253697 64.234072 L0.925556 67.532483" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /><path class="shape" transform="translate(162 211)" d="M0.857263 0.963884 C10.480488 0.944302, 21.040361 -1.949033, 53.206405 0.392335 M-0.648665 0.264598 C12.392454 0.347446, 23.992396 -0.222226, 53.419625 0.752815 M55.536704 -1.749433 C54.489431 15.585410, 55.180967 27.069513, 55.390547 65.130645 M54.297677 -0.799274 C54.657560 16.854002, 53.681091 35.455552, 54.406876 66.352243 M55.052801 65.786559 C43.384114 66.875371, 29.023779 66.331846, 1.836456 65.596476 M53.056573 65.856267 C33.612847 66.387434, 14.197363 66.115970, 0.938949 66.041844 M-0.720604 65.718532 C0.302797 45.542204, -1.429636 28.321166, 0.591800 -1.206080 M0.217956 66.998223 C-1.587850 41.337487, -1.081795 17.082362, 0.440740 0.988030" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /><rect class="sketch-overlay" transform="translate(162 211)" width="54" height="66" /></g><text class="text-bold" x="189.000000" y="249.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="users" style='opacity:0.400000'><g class="shape" ><path class="shape" transform="translate(683 0)" d="M-1.600310 -0.578379 L212.045551 1.811030 L211.253697 70.234072 L0.925556 73.532483" style="fill:#FFFFFF;stroke:#0A0F25;stroke-width:2;" /><path class="shape" transform="translate(683 0)" d="M0.755797 0.849798 C41.919041 0.271510, 83.908070 -2.279368, 210.300335 0.345898 M-0.571888 0.233280 C47.092687 -0.888816, 93.486665 -1.391062, 210.488319 0.663711 M212.536704 -1.749433 C211.434025 16.890424, 212.125561 29.679541, 212.390547 71.130645 M211.297677 -0.799274 C211.695335 18.464376, 210.718866 38.676301, 211.406876 72.352243 M211.928191 71.811822 C166.401573 75.510374, 118.501892 75.031181, 1.619092 71.644237 M210.168238 71.873280 C131.604972 72.658440, 53.066606 72.419106, 0.827814 72.036891 M-0.720604 71.718532 C0.215708 49.821348, -1.516724 30.879454, 0.591800 -1.206080 M0.217956 72.998223 C-1.661676 45.154890, -1.155622 18.717167, 0.440740 0.988030" style="fill:#FFFFFF;stroke:#0A0F25;stroke-width:2;" /><path class="class_header" transform="translate(683 0)" d="M-1.600310 -0.578379 L212.045551 1.811030 L211.253697 34.234072 L0.925556 37.532483" style="fill:#0A0F25" /><path class="class_header" transform="translate(683 0)" d="M0.755797 0.849798 C41.919041 0.271510, 83.908070 -2.279368, 210.300335 0.345898 M-0.571888 0.233280 C47.092687 -0.888816, 93.486665 -1.391062, 210.488319 0.663711 M212.536704 -1.749433 C211.766465 9.060341, 212.458000 14.019375, 212.390547 35.130645 M211.297677 -0.799274 C211.468683 8.802129, 210.492215 19.351806, 211.406876 36.352243 M211.928191 35.811822 C166.401573 39.510374, 118.501892 39.031181, 1.619092 35.644237 M210.168238 35.873280 C131.604972 36.658440, 53.066606 36.419106, 0.827814 36.036891 M-0.720604 35.718532 C0.738237 24.146483, -0.994195 15.529725, 0.591800 -1.206080 M0.217956 36.998223 C-1.218717 22.250475, -0.712663 8.908338, 0.440740 0.988030" style="fill:#0A0F25" /><text class="text" x="703.000000" y="27.000000" style="text-anchor:start;font-size:24px;fill:#FFFFFF">users</text><text class="text" x="693.000000" y="59.000000" style="text-anchor:start;font-size:20px;fill:#0D32B2">last_login</text>
<text class="text" x="796.000000" y="59.000000" style="text-anchor:start;font-size:20px;fill:#676C7E">datetime</text> <text class="text" x="796.000000" y="59.000000" style="text-anchor:start;font-size:20px;fill:#676C7E">datetime</text>
<text class="text" x="874.000000" y="59.000000" style="text-anchor:end;font-size:20px;fill:#4A6FF3;letter-spacing:2px;"></text><path d="M683.755797 72.849798 C724.919041 72.271510, 766.908070 69.720631, 893.300335 72.345898 M682.428111 72.233280 C730.092687 71.111183, 776.486665 70.608937, 893.488319 72.663711" style="fill:#0A0F25" /><rect class="sketch-overlay" transform="translate(683 0)" width="211" height="72" /></g></g><g id="a"><g class="shape" ><path class="shape" transform="translate(162 211)" d="M-1.600310 -0.578379 L55.045551 1.811030 L54.253697 64.234072 L0.925556 67.532483" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /><path class="shape" transform="translate(162 211)" d="M0.857263 0.963884 C10.480488 0.944302, 21.040361 -1.949033, 53.206405 0.392335 M-0.648665 0.264598 C12.392454 0.347446, 23.992396 -0.222226, 53.419625 0.752815 M55.536704 -1.749433 C54.489431 15.585410, 55.180967 27.069513, 55.390547 65.130645 M54.297677 -0.799274 C54.657560 16.854002, 53.681091 35.455552, 54.406876 66.352243 M55.052801 65.786559 C43.384114 66.875371, 29.023779 66.331846, 1.836456 65.596476 M53.056573 65.856267 C33.612847 66.387434, 14.197363 66.115970, 0.938949 66.041844 M-0.720604 65.718532 C0.302797 45.542204, -1.429636 28.321166, 0.591800 -1.206080 M0.217956 66.998223 C-1.587850 41.337487, -1.081795 17.082362, 0.440740 0.988030" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /><rect class="sketch-overlay" transform="translate(162 211)" width="54" height="66" /></g><text class="text-bold" x="189.000000" y="249.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="(x -&gt; a)[0]" style='opacity:0.400000'><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 class="connection" fill="none" d="M187.000089 69.340129 M187.000089 69.340129 C189.963884 126.680246, 190.163171 154.939876, 189.405312 208.357263 M185.269924 68.546535 C188.429286 128.079289, 187.378336 156.161496, 189.490419 205.533797" style="stroke:#0D32B2;stroke-width:2;" mask="url(#2347379850)"/><path class="connection" d="M-8.527627 -3.097061 L1.749550 0.558791 L-8.562935 4.521533" style="fill:#0D32B2;stroke:none;stroke-width:0;" transform="translate(189.000000 207.500000) rotate(90)"/> <path class="connection" d="M-10.153731 -4.038897 C-7.293657 -2.964754, -5.552453 -3.126871, 0.222305 -0.654474 M-10.160117 -4.253535 C-7.616436 -2.677663, -5.569656 -2.320404, -0.086565 0.272291 M0.578048 -0.807164 C-2.240460 1.133634, -3.845699 1.135504, -9.579367 4.140709 M-0.217907 -0.322328 C-3.660571 0.941126, -7.003142 2.167050, -10.100296 3.840861 M-9.957758 4.629247 C-9.937438 2.794817, -10.508655 0.509238, -9.330834 -3.522818 M-10.354741 4.285014 C-9.712366 0.996453, -9.805329 -1.235319, -9.648840 -4.366524" style="fill:none;stroke:#0D32B2;stroke-width:2;" transform="translate(189.000000 207.500000) rotate(90)"/><text class="text-italic" x="189.000000" y="137.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E"><tspan x="189.000000" dy="0.000000">You don&#39;t have to know how the computer works,</tspan><tspan x="189.000000" dy="19.500000">just how to work the computer.</tspan></text></g><mask id="2347379850" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1096" height="481"> <text class="text" x="874.000000" y="59.000000" style="text-anchor:end;font-size:20px;fill:#4A6FF3;letter-spacing:2px;"></text><path d="M683.755797 72.849798 C724.919041 72.271510, 766.908070 69.720631, 893.300335 72.345898 M682.428111 72.233280 C730.092687 71.111183, 776.486665 70.608937, 893.488319 72.663711" style="fill:#0A0F25" /><rect class="sketch-overlay" transform="translate(683 0)" width="211" height="72" /></g></g><g id="(x -&gt; a)[0]" style='opacity:0.400000'><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 class="connection" fill="none" d="M187.000089 69.340129 M187.000089 69.340129 C189.963884 126.680246, 190.163171 154.939876, 189.405312 208.357263 M185.269924 68.546535 C188.429286 128.079289, 187.378336 156.161496, 189.490419 205.533797" style="stroke:#0D32B2;stroke-width:2;" mask="url(#3274774736)"/><path class="connection" d="M-8.527627 -3.097061 L1.749550 0.558791 L-8.562935 4.521533" style="fill:#0D32B2;stroke:none;stroke-width:0;" transform="translate(189.000000 207.500000) rotate(90)"/> <path class="connection" d="M-10.153731 -4.038897 C-7.293657 -2.964754, -5.552453 -3.126871, 0.222305 -0.654474 M-10.160117 -4.253535 C-7.616436 -2.677663, -5.569656 -2.320404, -0.086565 0.272291 M0.578048 -0.807164 C-2.240460 1.133634, -3.845699 1.135504, -9.579367 4.140709 M-0.217907 -0.322328 C-3.660571 0.941126, -7.003142 2.167050, -10.100296 3.840861 M-9.957758 4.629247 C-9.937438 2.794817, -10.508655 0.509238, -9.330834 -3.522818 M-10.354741 4.285014 C-9.712366 0.996453, -9.805329 -1.235319, -9.648840 -4.366524" style="fill:none;stroke:#0D32B2;stroke-width:2;" transform="translate(189.000000 207.500000) rotate(90)"/><text class="text-italic" x="189.000000" y="137.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E"><tspan x="189.000000" dy="0.000000">You don&#39;t have to know how the computer works,</tspan><tspan x="189.000000" dy="19.500000">just how to work the computer.</tspan></text></g><mask id="3274774736" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1096" height="481">
<rect x="-100" y="-100" width="1096" height="481" fill="white"></rect> <rect x="-100" y="-100" width="1096" height="481" fill="white"></rect>
<rect x="0.000000" y="121.000000" width="378" height="39" fill="black"></rect> <rect x="0.000000" y="121.000000" width="378" height="39" fill="black"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 309 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: 387 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

View file

@ -40,7 +40,7 @@ width="565" height="683" viewBox="-102 -118 565 683"><style type="text/css">
} }
}); });
]]></script><a href="https://d2lang.com" xlink:href="https://d2lang.com"><g id="x"><g class="shape" ><rect x="17" y="0" width="85" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="59.500000" y="38.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">x</text><g transform="translate(86 -16)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">1</text></g></g></a><a href="https://terrastruct.com" xlink:href="https://terrastruct.com"><g id="y"><g class="shape" ><rect x="0" y="166" width="118" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="59.000000" y="204.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">y</text><g transform="translate(102 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">2</text></g><title>Gee, I feel kind of LIGHT in the head now, ]]></script><a href="https://d2lang.com" xlink:href="https://d2lang.com"><g id="x"><g class="shape" ><rect x="17" y="0" width="85" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="59.500000" y="38.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">x</text><g transform="translate(86 -16)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">1</text></g></g></a><a href="https://terrastruct.com" xlink:href="https://terrastruct.com"><g id="y"><g class="shape" ><rect x="0" y="166" width="118" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="59.000000" y="204.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">y</text><g transform="translate(102 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">2</text></g><title>Gee, I feel kind of LIGHT in the head now,
knowing I can't make my satellite dish PAYMENTS!</title><g transform="translate(70 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">3</text></g></g></a><g id="(x -&gt; y)[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.000000 68.000000 C 59.000000 106.000000 59.000000 126.000000 59.000000 162.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3445686545)"/></g><mask id="3445686545" maskUnits="userSpaceOnUse" x="-100" y="-100" width="338" height="452"> knowing I can't make my satellite dish PAYMENTS!</title><g transform="translate(70 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">3</text></g></g></a><g id="(x -&gt; y)[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.000000 68.000000 C 59.000000 106.000000 59.000000 126.000000 59.000000 162.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2533877225)"/></g><mask id="2533877225" maskUnits="userSpaceOnUse" x="-100" y="-100" width="338" height="452">
<rect x="-100" y="-100" width="338" height="452" fill="white"></rect> <rect x="-100" y="-100" width="338" height="452" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 651 KiB

After

Width:  |  Height:  |  Size: 651 KiB

View file

@ -40,7 +40,7 @@ width="566" height="631" viewBox="-102 -118 566 631"><style type="text/css">
} }
}); });
]]></script><g id="x"><g class="shape" ><rect x="1" y="0" width="85" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="43.500000" y="38.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">x</text><g transform="translate(70 -16)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">1</text></g><title>Total abstinence is easier than perfect moderation</title></g><g id="y"><g class="shape" ><rect x="0" y="166" width="86" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="43.000000" y="204.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">y</text><g transform="translate(70 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">2</text></g><title>Gee, I feel kind of LIGHT in the head now, ]]></script><g id="x"><g class="shape" ><rect x="1" y="0" width="85" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="43.500000" y="38.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">x</text><g transform="translate(70 -16)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">1</text></g><title>Total abstinence is easier than perfect moderation</title></g><g id="y"><g class="shape" ><rect x="0" y="166" width="86" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="43.000000" y="204.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">y</text><g transform="translate(70 150)" class="appendix-icon"><circle cx="16" cy="16" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="21" style="font-size: 16px;text-anchor:middle;">2</text></g><title>Gee, I feel kind of LIGHT in the head now,
knowing I can't make my satellite dish PAYMENTS!</title></g><g id="(x -&gt; y)[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 43.000000 68.000000 C 43.000000 106.000000 43.000000 126.000000 43.000000 162.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#4166705528)"/></g><mask id="4166705528" maskUnits="userSpaceOnUse" x="-100" y="-100" width="306" height="452"> knowing I can't make my satellite dish PAYMENTS!</title></g><g id="(x -&gt; y)[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 43.000000 68.000000 C 43.000000 106.000000 43.000000 126.000000 43.000000 162.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3642077342)"/></g><mask id="3642077342" maskUnits="userSpaceOnUse" x="-100" y="-100" width="306" height="452">
<rect x="-100" y="-100" width="306" height="452" fill="white"></rect> <rect x="-100" y="-100" width="306" height="452" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 650 KiB

After

Width:  |  Height:  |  Size: 650 KiB

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) {

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)
}
if forReport {
os.Remove(pathGotSVG)
} }
assert.Success(t, err)
assert.Success(t, err2)
} }
} }

View file

@ -444,6 +444,27 @@ group 11: {
} }
b -> c b -> c
`,
},
{
name: "sequence_diagram_ambiguous_edge_group",
script: `
Office chatter: {
shape: sequence_diagram
alice: Alice
bob: Bobby
awkward small talk: {
awkward small talk.ok
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
}
}
}
`, `,
}, },
} }

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,18 +54,20 @@ func main() {
testDir = "./e2etests" testDir = "./e2etests"
} }
ctx := log.Stderr(context.Background()) if !*skipTests {
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) ctx := log.Stderr(context.Background())
defer cancel() ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
cmd := exec.CommandContext(ctx, "go", "test", testDir, "-run", testMatchString, vString) defer cancel()
cmd.Env = os.Environ() cmd := exec.CommandContext(ctx, "go", "test", testDir, "-run", testMatchString, vString)
cmd.Env = append(cmd.Env, "FORCE_COLOR=1") cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "DEBUG=1") cmd.Env = append(cmd.Env, "FORCE_COLOR=1")
cmd.Env = append(cmd.Env, "TEST_MODE=on") cmd.Env = append(cmd.Env, "DEBUG=1")
cmd.Stdout = os.Stdout cmd.Env = append(cmd.Env, "TEST_MODE=on")
cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout
log.Debug(ctx, cmd.String()) cmd.Stderr = os.Stderr
_ = cmd.Run() log.Debug(ctx, cmd.String())
_ = 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
@ -1912,6 +1912,62 @@ g: ----------------------------------------------------------------
5.width: 32 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

@ -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

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "a", "id": "a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0
@ -43,91 +43,9 @@
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{
"id": "a.c",
"type": "",
"pos": {
"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": 15,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "a.c.d",
"type": "",
"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": 14,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
},
{ {
"id": "a.b", "id": "a.b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 94, "x": 94,
"y": 55 "y": 55
@ -166,9 +84,50 @@
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{
"id": "a.c",
"type": "rectangle",
"pos": {
"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": 15,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 2
},
{ {
"id": "a.1", "id": "a.1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 207, "x": 207,
"y": 55 "y": 55
@ -209,7 +168,7 @@
}, },
{ {
"id": "a.2", "id": "a.2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 319, "x": 319,
"y": 55 "y": 55
@ -247,6 +206,47 @@
"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": 14,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
} }
], ],
"connections": [ "connections": [

View file

@ -39,7 +39,7 @@ width="629" height="732" viewBox="-102 -102 629 732"><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="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.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.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.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(#712860972)"/><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(#712860972)"/></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(#712860972)"/></g><mask id="712860972" maskUnits="userSpaceOnUse" x="-100" y="-100" width="629" height="732"> ]]></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(#2904929206)"/><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(#2904929206)"/></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(#2904929206)"/></g><mask id="2904929206" maskUnits="userSpaceOnUse" x="-100" y="-100" width="629" height="732">
<rect x="-100" y="-100" width="629" height="732" fill="white"></rect> <rect x="-100" y="-100" width="629" height="732" fill="white"></rect>
<rect x="102.000000" y="176.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[

Before

Width:  |  Height:  |  Size: 794 KiB

After

Width:  |  Height:  |  Size: 794 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "a", "id": "a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12
@ -43,91 +43,9 @@
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{
"id": "a.c",
"type": "",
"pos": {
"x": 87,
"y": 422
},
"width": 204,
"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": 15,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "a.c.d",
"type": "",
"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": 14,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
},
{ {
"id": "a.b", "id": "a.b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 97, "x": 97,
"y": 87 "y": 87
@ -166,9 +84,50 @@
"zIndex": 0, "zIndex": 0,
"level": 2 "level": 2
}, },
{
"id": "a.c",
"type": "rectangle",
"pos": {
"x": 87,
"y": 422
},
"width": 204,
"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": 15,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 2
},
{ {
"id": "a.1", "id": "a.1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 163, "x": 163,
"y": 256 "y": 256
@ -209,7 +168,7 @@
}, },
{ {
"id": "a.2", "id": "a.2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 235, "x": 235,
"y": 256 "y": 256
@ -247,6 +206,47 @@
"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": 14,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 3
} }
], ],
"connections": [ "connections": [

View file

@ -39,7 +39,7 @@ width="558" height="905" viewBox="-90 -90 558 905"><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="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.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.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.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(#4088816423)"/><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(#4088816423)"/></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(#4088816423)"/></g><mask id="4088816423" maskUnits="userSpaceOnUse" x="-100" y="-100" width="558" height="905"> ]]></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(#2233071275)"/><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(#2233071275)"/></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(#2233071275)"/></g><mask id="2233071275" maskUnits="userSpaceOnUse" x="-100" y="-100" width="558" height="905">
<rect x="-100" y="-100" width="558" height="905" fill="white"></rect> <rect x="-100" y="-100" width="558" height="905" fill="white"></rect>
<rect x="106.000000" y="260.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[

Before

Width:  |  Height:  |  Size: 794 KiB

After

Width:  |  Height:  |  Size: 794 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "build_workflow", "id": "build_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0
@ -45,7 +45,7 @@
}, },
{ {
"id": "build_workflow.push", "id": "build_workflow.push",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 105, "x": 105,
"y": 50 "y": 50
@ -86,7 +86,7 @@
}, },
{ {
"id": "build_workflow.GHA", "id": "build_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 638, "x": 638,
"y": 50 "y": 50
@ -127,7 +127,7 @@
}, },
{ {
"id": "build_workflow.S3", "id": "build_workflow.S3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1194, "x": 1194,
"y": 50 "y": 50
@ -168,7 +168,7 @@
}, },
{ {
"id": "build_workflow.Terraform", "id": "build_workflow.Terraform",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1593, "x": 1593,
"y": 50 "y": 50
@ -209,7 +209,7 @@
}, },
{ {
"id": "build_workflow.AWS", "id": "build_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 2129, "x": 2129,
"y": 50 "y": 50

View file

@ -39,7 +39,7 @@ width="2532" height="381" viewBox="-102 -102 2532 381"><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="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(#3498243834)"/><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(#3498243834)"/><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(#3498243834)"/><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(#3498243834)"/><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="3498243834" maskUnits="userSpaceOnUse" x="-100" y="-100" width="2532" height="381"> ]]></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(#3706810236)"/><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(#3706810236)"/><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(#3706810236)"/><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(#3706810236)"/><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="3706810236" maskUnits="userSpaceOnUse" x="-100" y="-100" width="2532" height="381">
<rect x="-100" y="-100" width="2532" height="381" fill="white"></rect> <rect x="-100" y="-100" width="2532" height="381" fill="white"></rect>
<rect x="480.000000" y="78.000000" width="54" height="21" fill="black"></rect> <rect x="480.000000" y="78.000000" width="54" height="21" fill="black"></rect>
<rect x="951.000000" y="78.000000" width="138" height="21" fill="black"></rect> <rect x="951.000000" y="78.000000" width="138" height="21" fill="black"></rect>

Before

Width:  |  Height:  |  Size: 795 KiB

After

Width:  |  Height:  |  Size: 795 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "build_workflow", "id": "build_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12
@ -45,7 +45,7 @@
}, },
{ {
"id": "build_workflow.push", "id": "build_workflow.push",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 87, "x": 87,
"y": 87 "y": 87
@ -86,7 +86,7 @@
}, },
{ {
"id": "build_workflow.GHA", "id": "build_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 611, "x": 611,
"y": 87 "y": 87
@ -127,7 +127,7 @@
}, },
{ {
"id": "build_workflow.S3", "id": "build_workflow.S3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1158, "x": 1158,
"y": 87 "y": 87
@ -168,7 +168,7 @@
}, },
{ {
"id": "build_workflow.Terraform", "id": "build_workflow.Terraform",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1548, "x": 1548,
"y": 87 "y": 87
@ -209,7 +209,7 @@
}, },
{ {
"id": "build_workflow.AWS", "id": "build_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 2075, "x": 2075,
"y": 87 "y": 87

View file

@ -39,7 +39,7 @@ width="2437" height="431" viewBox="-90 -90 2437 431"><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="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(#3270735161)"/><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(#3270735161)"/><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(#3270735161)"/><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(#3270735161)"/><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="3270735161" maskUnits="userSpaceOnUse" x="-100" y="-100" width="2437" height="431"> ]]></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(#3642427155)"/><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(#3642427155)"/><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(#3642427155)"/><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(#3642427155)"/><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="3642427155" maskUnits="userSpaceOnUse" x="-100" y="-100" width="2437" height="431">
<rect x="-100" y="-100" width="2437" height="431" fill="white"></rect> <rect x="-100" y="-100" width="2437" height="431" fill="white"></rect>
<rect x="457.000000" y="115.000000" width="54" height="21" fill="black"></rect> <rect x="457.000000" y="115.000000" width="54" height="21" fill="black"></rect>
<rect x="920.000000" y="115.000000" width="138" height="21" fill="black"></rect> <rect x="920.000000" y="115.000000" width="138" height="21" fill="black"></rect>

Before

Width:  |  Height:  |  Size: 795 KiB

After

Width:  |  Height:  |  Size: 795 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "\"ninety\\nnine\"", "id": "\"ninety\\nnine\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0
@ -45,7 +45,7 @@
}, },
{ {
"id": "eighty\reight", "id": "eighty\reight",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 151, "x": 151,
"y": 8 "y": 8
@ -86,7 +86,7 @@
}, },
{ {
"id": "\"seventy\r\\nseven\"", "id": "\"seventy\r\\nseven\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 302, "x": 302,
"y": 0 "y": 0
@ -127,7 +127,7 @@
}, },
{ {
"id": "\"a\\\\yode\"", "id": "\"a\\\\yode\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 464, "x": 464,
"y": 8 "y": 8
@ -168,7 +168,7 @@
}, },
{ {
"id": "there", "id": "there",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 624, "x": 624,
"y": 182 "y": 182
@ -209,7 +209,7 @@
}, },
{ {
"id": "'a\\\"ode'", "id": "'a\\\"ode'",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 618, "x": 618,
"y": 8 "y": 8
@ -250,7 +250,7 @@
}, },
{ {
"id": "\"a\\\\node\"", "id": "\"a\\\\node\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 772, "x": 772,
"y": 8 "y": 8

View file

@ -39,7 +39,7 @@ width="1071" height="452" viewBox="-102 -102 1071 452"><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="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="21.000000">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="21.000000">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(#1972783858)"/></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(#1972783858)"/></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(#1972783858)"/></g><mask id="1972783858" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1071" height="452"> ]]></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="21.000000">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="21.000000">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(#2061254223)"/></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(#2061254223)"/></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(#2061254223)"/></g><mask id="2061254223" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1071" height="452">
<rect x="-100" y="-100" width="1071" height="452" 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[

Before

Width:  |  Height:  |  Size: 327 KiB

After

Width:  |  Height:  |  Size: 327 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "\"ninety\\nnine\"", "id": "\"ninety\\nnine\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12
@ -45,7 +45,7 @@
}, },
{ {
"id": "eighty\reight", "id": "eighty\reight",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 123, "x": 123,
"y": 20 "y": 20
@ -86,7 +86,7 @@
}, },
{ {
"id": "\"seventy\r\\nseven\"", "id": "\"seventy\r\\nseven\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 234, "x": 234,
"y": 12 "y": 12
@ -127,7 +127,7 @@
}, },
{ {
"id": "\"a\\\\yode\"", "id": "\"a\\\\yode\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 356, "x": 356,
"y": 28 "y": 28
@ -168,7 +168,7 @@
}, },
{ {
"id": "there", "id": "there",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 475, "x": 475,
"y": 194 "y": 194
@ -209,7 +209,7 @@
}, },
{ {
"id": "'a\\\"ode'", "id": "'a\\\"ode'",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 470, "x": 470,
"y": 28 "y": 28
@ -250,7 +250,7 @@
}, },
{ {
"id": "\"a\\\\node\"", "id": "\"a\\\\node\"",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 584, "x": 584,
"y": 28 "y": 28

View file

@ -39,7 +39,7 @@ width="871" height="452" viewBox="-90 -90 871 452"><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="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="21.000000">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="21.000000">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(#2887150407)"/></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(#2887150407)"/></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(#2887150407)"/></g><mask id="2887150407" maskUnits="userSpaceOnUse" x="-100" y="-100" width="871" height="452"> ]]></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="21.000000">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="21.000000">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(#1853895674)"/></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(#1853895674)"/></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(#1853895674)"/></g><mask id="1853895674" maskUnits="userSpaceOnUse" x="-100" y="-100" width="871" height="452">
<rect x="-100" y="-100" width="871" height="452" 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[

Before

Width:  |  Height:  |  Size: 327 KiB

After

Width:  |  Height:  |  Size: 327 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "build_workflow", "id": "build_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0
@ -45,7 +45,7 @@
}, },
{ {
"id": "build_workflow.push", "id": "build_workflow.push",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 50, "x": 50,
"y": 73 "y": 73
@ -86,7 +86,7 @@
}, },
{ {
"id": "build_workflow.GHA", "id": "build_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 81, "x": 81,
"y": 322 "y": 322
@ -127,7 +127,7 @@
}, },
{ {
"id": "build_workflow.S3", "id": "build_workflow.S3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 150, "x": 150,
"y": 651 "y": 651
@ -168,7 +168,7 @@
}, },
{ {
"id": "build_workflow.Terraform", "id": "build_workflow.Terraform",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 106, "x": 106,
"y": 973 "y": 973
@ -209,7 +209,7 @@
}, },
{ {
"id": "build_workflow.AWS", "id": "build_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 138, "x": 138,
"y": 1222 "y": 1222
@ -250,7 +250,7 @@
}, },
{ {
"id": "deploy_workflow", "id": "deploy_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 410, "x": 410,
"y": 0 "y": 0
@ -291,7 +291,7 @@
}, },
{ {
"id": "deploy_workflow.manual", "id": "deploy_workflow.manual",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 460, "x": 460,
"y": 73 "y": 73
@ -332,7 +332,7 @@
}, },
{ {
"id": "deploy_workflow.GHA", "id": "deploy_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 461, "x": 461,
"y": 322 "y": 322
@ -373,7 +373,7 @@
}, },
{ {
"id": "deploy_workflow.AWS", "id": "deploy_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 518, "x": 518,
"y": 651 "y": 651
@ -414,7 +414,7 @@
}, },
{ {
"id": "apollo_workflow", "id": "apollo_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 761, "x": 761,
"y": 0 "y": 0
@ -455,7 +455,7 @@
}, },
{ {
"id": "apollo_workflow.apollo", "id": "apollo_workflow.apollo",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 979, "x": 979,
"y": 73 "y": 73
@ -496,7 +496,7 @@
}, },
{ {
"id": "apollo_workflow.GHA", "id": "apollo_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 963, "x": 963,
"y": 322 "y": 322
@ -537,7 +537,7 @@
}, },
{ {
"id": "apollo_workflow.AWS", "id": "apollo_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1020, "x": 1020,
"y": 651 "y": 651

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,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "build_workflow", "id": "build_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12
@ -45,7 +45,7 @@
}, },
{ {
"id": "build_workflow.push", "id": "build_workflow.push",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 87, "x": 87,
"y": 87 "y": 87
@ -86,7 +86,7 @@
}, },
{ {
"id": "build_workflow.GHA", "id": "build_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 117, "x": 117,
"y": 390 "y": 390
@ -127,7 +127,7 @@
}, },
{ {
"id": "build_workflow.S3", "id": "build_workflow.S3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 186, "x": 186,
"y": 693 "y": 693
@ -168,7 +168,7 @@
}, },
{ {
"id": "build_workflow.Terraform", "id": "build_workflow.Terraform",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 143, "x": 143,
"y": 996 "y": 996
@ -209,7 +209,7 @@
}, },
{ {
"id": "build_workflow.AWS", "id": "build_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 174, "x": 174,
"y": 1299 "y": 1299
@ -250,7 +250,7 @@
}, },
{ {
"id": "deploy_workflow", "id": "deploy_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 452, "x": 452,
"y": 275 "y": 275
@ -291,7 +291,7 @@
}, },
{ {
"id": "deploy_workflow.manual", "id": "deploy_workflow.manual",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 527, "x": 527,
"y": 350 "y": 350
@ -332,7 +332,7 @@
}, },
{ {
"id": "deploy_workflow.GHA", "id": "deploy_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 528, "x": 528,
"y": 653 "y": 653
@ -373,7 +373,7 @@
}, },
{ {
"id": "deploy_workflow.AWS", "id": "deploy_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 585, "x": 585,
"y": 1036 "y": 1036
@ -414,7 +414,7 @@
}, },
{ {
"id": "apollo_workflow", "id": "apollo_workflow",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 833, "x": 833,
"y": 315 "y": 315
@ -455,7 +455,7 @@
}, },
{ {
"id": "apollo_workflow.apollo", "id": "apollo_workflow.apollo",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1085, "x": 1085,
"y": 390 "y": 390
@ -496,7 +496,7 @@
}, },
{ {
"id": "apollo_workflow.GHA", "id": "apollo_workflow.GHA",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1070, "x": 1070,
"y": 693 "y": 693
@ -537,7 +537,7 @@
}, },
{ {
"id": "apollo_workflow.AWS", "id": "apollo_workflow.AWS",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1127, "x": 1127,
"y": 996 "y": 996

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,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "x", "id": "x",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0
@ -45,7 +45,7 @@
}, },
{ {
"id": "x.a", "id": "x.a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 50, "x": 50,
"y": 50 "y": 50
@ -86,7 +86,7 @@
}, },
{ {
"id": "x.b", "id": "x.b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 203, "x": 203,
"y": 50 "y": 50

View file

@ -39,7 +39,7 @@ width="510" height="370" viewBox="-102 -102 510 370"><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="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(#1792923588)"/></g><mask id="1792923588" maskUnits="userSpaceOnUse" x="-100" y="-100" width="510" height="370"> ]]></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(#3389512895)"/></g><mask id="3389512895" maskUnits="userSpaceOnUse" x="-100" y="-100" width="510" height="370">
<rect x="-100" y="-100" width="510" height="370" 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[

Before

Width:  |  Height:  |  Size: 649 KiB

After

Width:  |  Height:  |  Size: 649 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "x", "id": "x",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12
@ -45,7 +45,7 @@
}, },
{ {
"id": "x.a", "id": "x.a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 137, "x": 137,
"y": 87 "y": 87
@ -86,7 +86,7 @@
}, },
{ {
"id": "x.b", "id": "x.b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 210, "x": 210,
"y": 87 "y": 87

View file

@ -39,7 +39,7 @@ width="530" height="420" viewBox="-90 -90 530 420"><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="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(#2596520073)"/></g><mask id="2596520073" maskUnits="userSpaceOnUse" x="-100" y="-100" width="530" height="420"> ]]></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(#2790431130)"/></g><mask id="2790431130" maskUnits="userSpaceOnUse" x="-100" y="-100" width="530" height="420">
<rect x="-100" y="-100" width="530" height="420" 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[

Before

Width:  |  Height:  |  Size: 649 KiB

After

Width:  |  Height:  |  Size: 649 KiB

View file

@ -44,7 +44,7 @@
}, },
{ {
"id": "queue.M0", "id": "queue.M0",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 50, "x": 50,
"y": 198 "y": 198
@ -85,7 +85,7 @@
}, },
{ {
"id": "queue.M1", "id": "queue.M1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 175, "x": 175,
"y": 198 "y": 198
@ -126,7 +126,7 @@
}, },
{ {
"id": "queue.M2", "id": "queue.M2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 300, "x": 300,
"y": 198 "y": 198
@ -167,7 +167,7 @@
}, },
{ {
"id": "queue.M3", "id": "queue.M3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 425, "x": 425,
"y": 198 "y": 198
@ -208,7 +208,7 @@
}, },
{ {
"id": "queue.M4", "id": "queue.M4",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 550, "x": 550,
"y": 198 "y": 198
@ -249,7 +249,7 @@
}, },
{ {
"id": "queue.M5", "id": "queue.M5",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 676, "x": 676,
"y": 198 "y": 198
@ -290,7 +290,7 @@
}, },
{ {
"id": "queue.M6", "id": "queue.M6",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 851, "x": 851,
"y": 198 "y": 198

View file

@ -801,7 +801,7 @@ width="1170" height="518" viewBox="-102 -102 1170 518"><style type="text/css">
</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="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="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 /> </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="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(#3538168118)"/></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(#3538168118)"/></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(#3538168118)"/></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(#3538168118)"/></g><mask id="3538168118" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1170" height="518"> </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(#1789757279)"/></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(#1789757279)"/></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(#1789757279)"/></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(#1789757279)"/></g><mask id="1789757279" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1170" height="518">
<rect x="-100" y="-100" width="1170" height="518" 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[

Before

Width:  |  Height:  |  Size: 664 KiB

After

Width:  |  Height:  |  Size: 664 KiB

View file

@ -44,7 +44,7 @@
}, },
{ {
"id": "queue.M0", "id": "queue.M0",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 87, "x": 87,
"y": 240 "y": 240
@ -85,7 +85,7 @@
}, },
{ {
"id": "queue.M1", "id": "queue.M1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 172, "x": 172,
"y": 240 "y": 240
@ -126,7 +126,7 @@
}, },
{ {
"id": "queue.M2", "id": "queue.M2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 257, "x": 257,
"y": 240 "y": 240
@ -167,7 +167,7 @@
}, },
{ {
"id": "queue.M3", "id": "queue.M3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 342, "x": 342,
"y": 240 "y": 240
@ -208,7 +208,7 @@
}, },
{ {
"id": "queue.M4", "id": "queue.M4",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 427, "x": 427,
"y": 240 "y": 240
@ -249,7 +249,7 @@
}, },
{ {
"id": "queue.M5", "id": "queue.M5",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 513, "x": 513,
"y": 240 "y": 240
@ -290,7 +290,7 @@
}, },
{ {
"id": "queue.M6", "id": "queue.M6",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 598, "x": 598,
"y": 240 "y": 240

View file

@ -801,7 +801,7 @@ width="930" height="573" viewBox="-90 -90 930 573"><style type="text/css">
</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="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="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 /> </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="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(#3356935207)"/></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(#3356935207)"/></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(#3356935207)"/></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(#3356935207)"/></g><mask id="3356935207" maskUnits="userSpaceOnUse" x="-100" y="-100" width="930" height="573"> </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(#3419810882)"/></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(#3419810882)"/></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(#3419810882)"/></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(#3419810882)"/></g><mask id="3419810882" maskUnits="userSpaceOnUse" x="-100" y="-100" width="930" height="573">
<rect x="-100" y="-100" width="930" height="573" 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[

Before

Width:  |  Height:  |  Size: 664 KiB

After

Width:  |  Height:  |  Size: 664 KiB

View file

@ -44,7 +44,7 @@
}, },
{ {
"id": "a", "id": "a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 21, "x": 21,
"y": 0 "y": 0
@ -85,7 +85,7 @@
}, },
{ {
"id": "b", "id": "b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 21, "x": 21,
"y": 381 "y": 381

View file

@ -804,7 +804,7 @@ width="299" height="651" viewBox="-102 -102 299 651"><style type="text/css">
</ol> </ol>
</li> </li>
</ul> </ul>
</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(#4487205)"/></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(#4487205)"/></g><mask id="4487205" maskUnits="userSpaceOnUse" x="-100" y="-100" width="299" height="651"> </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(#3448031561)"/></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(#3448031561)"/></g><mask id="3448031561" maskUnits="userSpaceOnUse" x="-100" y="-100" width="299" height="651">
<rect x="-100" y="-100" width="299" height="651" 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[

Before

Width:  |  Height:  |  Size: 661 KiB

After

Width:  |  Height:  |  Size: 661 KiB

View file

@ -44,7 +44,7 @@
}, },
{ {
"id": "a", "id": "a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 33, "x": 33,
"y": 12 "y": 12
@ -85,7 +85,7 @@
}, },
{ {
"id": "b", "id": "b",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 33, "x": 33,
"y": 393 "y": 393

View file

@ -804,7 +804,7 @@ width="299" height="651" viewBox="-90 -90 299 651"><style type="text/css">
</ol> </ol>
</li> </li>
</ul> </ul>
</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(#4035722895)"/></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(#4035722895)"/></g><mask id="4035722895" maskUnits="userSpaceOnUse" x="-100" y="-100" width="299" height="651"> </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(#2150364153)"/></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(#2150364153)"/></g><mask id="2150364153" maskUnits="userSpaceOnUse" x="-100" y="-100" width="299" height="651">
<rect x="-100" y="-100" width="299" height="651" 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[

Before

Width:  |  Height:  |  Size: 660 KiB

After

Width:  |  Height:  |  Size: 660 KiB

View file

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

View file

@ -797,7 +797,7 @@ width="754" height="473" viewBox="-100 -102 754 473"><style type="text/css">
margin: 0 -1.6em 0.25em 0.2em; margin: 0 -1.6em 0.25em 0.2em;
} }
</style><g id="x" style='opacity:0.400000'><g class="shape" ><rect x="135" y="0" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="161.500000" y="38.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">x</text></g><g id="y" style='opacity:0.400000'><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="248.000000" y="21.000000" width="304" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>linux: because a PC is a terrible thing to waste</p> </style><g id="x" style='opacity:0.400000'><g class="shape" ><rect x="135" y="0" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="161.500000" y="38.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">x</text></g><g id="y" style='opacity:0.400000'><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="248.000000" y="21.000000" width="304" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>linux: because a PC is a terrible thing to waste</p>
</div></foreignObject></g></g><g id="a"><g class="shape" ><rect x="135" y="203" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="161.500000" y="241.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="(x -&gt; a)[0]" style='opacity:0.400000'><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 161.000000 68.000000 C 161.000000 120.800000 161.000000 148.300000 161.000000 199.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1451849267)"/><text class="text-italic" x="161.000000" y="132.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E"><tspan x="161.000000" dy="0.000000">You don&#39;t have to know how the computer works,</tspan><tspan x="161.000000" dy="18.500000">just how to work the computer.</tspan></text></g><mask id="1451849267" maskUnits="userSpaceOnUse" x="-100" y="-100" width="754" height="473"> </div></foreignObject></g></g><g id="a"><g class="shape" ><rect x="135" y="203" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="161.500000" y="241.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="(x -&gt; a)[0]" style='opacity:0.400000'><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 161.000000 68.000000 C 161.000000 120.800000 161.000000 148.300000 161.000000 199.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1403192671)"/><text class="text-italic" x="161.000000" y="132.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E"><tspan x="161.000000" dy="0.000000">You don&#39;t have to know how the computer works,</tspan><tspan x="161.000000" dy="18.500000">just how to work the computer.</tspan></text></g><mask id="1403192671" maskUnits="userSpaceOnUse" x="-100" y="-100" width="754" height="473">
<rect x="-100" y="-100" width="754" height="473" fill="white"></rect> <rect x="-100" y="-100" width="754" height="473" fill="white"></rect>
<rect x="0.000000" y="116.000000" width="322" height="37" fill="black"></rect> <rect x="0.000000" y="116.000000" width="322" height="37" fill="black"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 804 KiB

After

Width:  |  Height:  |  Size: 804 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "x", "id": "x",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 146, "x": 146,
"y": 12 "y": 12
@ -85,7 +85,7 @@
}, },
{ {
"id": "a", "id": "a",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 146, "x": 146,
"y": 315 "y": 315

View file

@ -797,7 +797,7 @@ width="713" height="573" viewBox="-88 -90 713 573"><style type="text/css">
margin: 0 -1.6em 0.25em 0.2em; margin: 0 -1.6em 0.25em 0.2em;
} }
</style><g id="x" style='opacity:0.400000'><g class="shape" ><rect x="146" y="12" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="172.500000" y="50.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">x</text></g><g id="y" style='opacity:0.400000'><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="219.000000" y="33.000000" width="304" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>linux: because a PC is a terrible thing to waste</p> </style><g id="x" style='opacity:0.400000'><g class="shape" ><rect x="146" y="12" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="172.500000" y="50.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">x</text></g><g id="y" style='opacity:0.400000'><g class="shape" ></g><g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="219.000000" y="33.000000" width="304" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="md" style="background-color:transparent;color:#0A0F25;"><p>linux: because a PC is a terrible thing to waste</p>
</div></foreignObject></g></g><g id="a"><g class="shape" ><rect x="146" y="315" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="172.500000" y="353.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="(x -&gt; a)[0]" style='opacity:0.400000'><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 173.000000 80.000000 L 173.000000 311.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2351959814)"/><text class="text-italic" x="173.000000" y="194.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E"><tspan x="173.000000" dy="0.000000">You don&#39;t have to know how the computer works,</tspan><tspan x="173.000000" dy="18.500000">just how to work the computer.</tspan></text></g><mask id="2351959814" maskUnits="userSpaceOnUse" x="-100" y="-100" width="713" height="573"> </div></foreignObject></g></g><g id="a"><g class="shape" ><rect x="146" y="315" width="53" height="66" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="172.500000" y="353.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="(x -&gt; a)[0]" style='opacity:0.400000'><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 173.000000 80.000000 L 173.000000 311.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2224882124)"/><text class="text-italic" x="173.000000" y="194.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E"><tspan x="173.000000" dy="0.000000">You don&#39;t have to know how the computer works,</tspan><tspan x="173.000000" dy="18.500000">just how to work the computer.</tspan></text></g><mask id="2224882124" maskUnits="userSpaceOnUse" x="-100" y="-100" width="713" height="573">
<rect x="-100" y="-100" width="713" height="573" fill="white"></rect> <rect x="-100" y="-100" width="713" height="573" fill="white"></rect>
<rect x="12.000000" y="178.000000" width="322" height="37" fill="black"></rect> <rect x="12.000000" y="178.000000" width="322" height="37" fill="black"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 804 KiB

After

Width:  |  Height:  |  Size: 804 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "k8s", "id": "k8s",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 0 "y": 0
@ -45,7 +45,7 @@
}, },
{ {
"id": "k8s.m1", "id": "k8s.m1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 131, "x": 131,
"y": 50 "y": 50
@ -86,7 +86,7 @@
}, },
{ {
"id": "k8s.m2", "id": "k8s.m2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 323, "x": 323,
"y": 50 "y": 50
@ -127,7 +127,7 @@
}, },
{ {
"id": "k8s.m3", "id": "k8s.m3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 515, "x": 515,
"y": 50 "y": 50
@ -168,7 +168,7 @@
}, },
{ {
"id": "k8s.w1", "id": "k8s.w1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 707, "x": 707,
"y": 50 "y": 50
@ -209,7 +209,7 @@
}, },
{ {
"id": "k8s.w2", "id": "k8s.w2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 900, "x": 900,
"y": 50 "y": 50
@ -250,7 +250,7 @@
}, },
{ {
"id": "k8s.w3", "id": "k8s.w3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 1093, "x": 1093,
"y": 50 "y": 50
@ -291,7 +291,7 @@
}, },
{ {
"id": "osvc", "id": "osvc",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 0, "x": 0,
"y": 287 "y": 287
@ -332,7 +332,7 @@
}, },
{ {
"id": "osvc.vm1", "id": "osvc.vm1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 186, "x": 186,
"y": 337 "y": 337
@ -373,7 +373,7 @@
}, },
{ {
"id": "osvc.vm2", "id": "osvc.vm2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 369, "x": 369,
"y": 337 "y": 337

View file

@ -39,7 +39,7 @@ width="1480" height="657" viewBox="-102 -102 1480 657"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="k8s"><g class="shape" ><rect x="0" y="0" width="1276" height="166" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="638.000000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">Kubernetes</text></g><g id="osvc"><g class="shape" ><rect x="0" y="287" width="495" height="166" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="247.500000" y="320.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">opensvc</text></g><g id="k8s.m1"><g class="shape" ><rect x="131" y="50" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="197.000000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master1</text></g><g id="k8s.m2"><g class="shape" ><rect x="323" y="50" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="389.000000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master2</text></g><g id="k8s.m3"><g class="shape" ><rect x="515" y="50" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="581.000000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master3</text></g><g id="k8s.w1"><g class="shape" ><rect x="707" y="50" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="773.500000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker1</text></g><g id="k8s.w2"><g class="shape" ><rect x="900" y="50" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="966.500000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker2</text></g><g id="k8s.w3"><g class="shape" ><rect x="1093" y="50" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1159.500000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker3</text></g><g id="osvc.vm1"><g class="shape" ><rect x="186" y="337" width="76" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="224.000000" y="375.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">VM1</text></g><g id="osvc.vm2"><g class="shape" ><rect x="369" y="337" width="76" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="407.000000" y="375.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">VM2</text></g><g id="(k8s -&gt; osvc)[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 84.000000 168.000000 C 84.000000 214.400000 84.000000 238.700000 84.000000 283.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1114596525)"/><text class="text-italic" x="84.500000" y="232.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">keycloak</text></g><g id="(k8s -&gt; osvc)[1]"><path d="M 186.000000 168.000000 C 186.000000 214.400000 186.000000 238.700000 186.000000 283.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1114596525)"/><text class="text-italic" x="186.500000" y="232.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">heptapod</text></g><g id="(k8s -&gt; osvc)[2]"><path d="M 282.000000 168.000000 C 282.000000 214.400000 282.000000 238.700000 282.000000 283.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1114596525)"/><text class="text-italic" x="282.500000" y="232.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">harbor</text></g><g id="(k8s -&gt; osvc)[3]"><path d="M 363.000000 168.000000 C 363.000000 214.400000 363.000000 238.700000 363.000000 283.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1114596525)"/><text class="text-italic" x="363.500000" y="232.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">vault</text></g><mask id="1114596525" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1480" height="657"> ]]></script><g id="k8s"><g class="shape" ><rect x="0" y="0" width="1276" height="166" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="638.000000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">Kubernetes</text></g><g id="osvc"><g class="shape" ><rect x="0" y="287" width="495" height="166" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="247.500000" y="320.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">opensvc</text></g><g id="k8s.m1"><g class="shape" ><rect x="131" y="50" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="197.000000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master1</text></g><g id="k8s.m2"><g class="shape" ><rect x="323" y="50" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="389.000000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master2</text></g><g id="k8s.m3"><g class="shape" ><rect x="515" y="50" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="581.000000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master3</text></g><g id="k8s.w1"><g class="shape" ><rect x="707" y="50" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="773.500000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker1</text></g><g id="k8s.w2"><g class="shape" ><rect x="900" y="50" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="966.500000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker2</text></g><g id="k8s.w3"><g class="shape" ><rect x="1093" y="50" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="1159.500000" y="88.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker3</text></g><g id="osvc.vm1"><g class="shape" ><rect x="186" y="337" width="76" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="224.000000" y="375.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">VM1</text></g><g id="osvc.vm2"><g class="shape" ><rect x="369" y="337" width="76" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="407.000000" y="375.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">VM2</text></g><g id="(k8s -&gt; osvc)[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 84.000000 168.000000 C 84.000000 214.400000 84.000000 238.700000 84.000000 283.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3083444197)"/><text class="text-italic" x="84.500000" y="232.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">keycloak</text></g><g id="(k8s -&gt; osvc)[1]"><path d="M 186.000000 168.000000 C 186.000000 214.400000 186.000000 238.700000 186.000000 283.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3083444197)"/><text class="text-italic" x="186.500000" y="232.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">heptapod</text></g><g id="(k8s -&gt; osvc)[2]"><path d="M 282.000000 168.000000 C 282.000000 214.400000 282.000000 238.700000 282.000000 283.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3083444197)"/><text class="text-italic" x="282.500000" y="232.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">harbor</text></g><g id="(k8s -&gt; osvc)[3]"><path d="M 363.000000 168.000000 C 363.000000 214.400000 363.000000 238.700000 363.000000 283.500000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3083444197)"/><text class="text-italic" x="363.500000" y="232.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">vault</text></g><mask id="3083444197" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1480" height="657">
<rect x="-100" y="-100" width="1480" height="657" fill="white"></rect> <rect x="-100" y="-100" width="1480" height="657" fill="white"></rect>
<rect x="55.000000" y="216.000000" width="59" height="21" fill="black"></rect> <rect x="55.000000" y="216.000000" width="59" height="21" fill="black"></rect>
<rect x="154.000000" y="216.000000" width="65" height="21" fill="black"></rect> <rect x="154.000000" y="216.000000" width="65" height="21" fill="black"></rect>

Before

Width:  |  Height:  |  Size: 795 KiB

After

Width:  |  Height:  |  Size: 795 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "k8s", "id": "k8s",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12
@ -45,7 +45,7 @@
}, },
{ {
"id": "k8s.m1", "id": "k8s.m1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 87, "x": 87,
"y": 87 "y": 87
@ -86,7 +86,7 @@
}, },
{ {
"id": "k8s.m2", "id": "k8s.m2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 239, "x": 239,
"y": 87 "y": 87
@ -127,7 +127,7 @@
}, },
{ {
"id": "k8s.m3", "id": "k8s.m3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 391, "x": 391,
"y": 87 "y": 87
@ -168,7 +168,7 @@
}, },
{ {
"id": "k8s.w1", "id": "k8s.w1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 543, "x": 543,
"y": 87 "y": 87
@ -209,7 +209,7 @@
}, },
{ {
"id": "k8s.w2", "id": "k8s.w2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 696, "x": 696,
"y": 87 "y": 87
@ -250,7 +250,7 @@
}, },
{ {
"id": "k8s.w3", "id": "k8s.w3",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 849, "x": 849,
"y": 87 "y": 87
@ -291,7 +291,7 @@
}, },
{ {
"id": "osvc", "id": "osvc",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 301, "x": 301,
"y": 499 "y": 499
@ -332,7 +332,7 @@
}, },
{ {
"id": "osvc.vm1", "id": "osvc.vm1",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 376, "x": 376,
"y": 574 "y": 574
@ -373,7 +373,7 @@
}, },
{ {
"id": "osvc.vm2", "id": "osvc.vm2",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 472, "x": 472,
"y": 574 "y": 574

View file

@ -39,7 +39,7 @@ width="1249" height="907" viewBox="-90 -90 1249 907"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="k8s"><g class="shape" ><rect x="12" y="12" width="1045" height="216" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="534.500000" y="45.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">Kubernetes</text></g><g id="osvc"><g class="shape" ><rect x="301" y="499" width="322" height="216" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="462.000000" y="532.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">opensvc</text></g><g id="k8s.m1"><g class="shape" ><rect x="87" y="87" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="153.000000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master1</text></g><g id="k8s.m2"><g class="shape" ><rect x="239" y="87" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="305.000000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master2</text></g><g id="k8s.m3"><g class="shape" ><rect x="391" y="87" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="457.000000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master3</text></g><g id="k8s.w1"><g class="shape" ><rect x="543" y="87" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="609.500000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker1</text></g><g id="k8s.w2"><g class="shape" ><rect x="696" y="87" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="762.500000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker2</text></g><g id="k8s.w3"><g class="shape" ><rect x="849" y="87" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="915.500000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker3</text></g><g id="osvc.vm1"><g class="shape" ><rect x="376" y="574" width="76" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="414.000000" y="612.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">VM1</text></g><g id="osvc.vm2"><g class="shape" ><rect x="472" y="574" width="76" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="510.000000" y="612.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">VM2</text></g><g id="(k8s -&gt; osvc)[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 221.000000 230.000000 L 221.000000 389.000000 S 221.000000 399.000000 231.000000 399.000000 L 355.600000 399.000000 S 365.600000 399.000000 365.600000 409.000000 L 365.600000 495.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1423726321)"/><text class="text-italic" x="257.500000" y="405.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">keycloak</text></g><g id="(k8s -&gt; osvc)[1]"><path d="M 430.000000 230.000000 L 430.000000 495.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1423726321)"/><text class="text-italic" x="430.500000" y="369.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">heptapod</text></g><g id="(k8s -&gt; osvc)[2]"><path d="M 639.000000 230.000000 L 639.000000 389.000000 S 639.000000 399.000000 629.000000 399.000000 L 504.400000 399.000000 S 494.400000 399.000000 494.400000 409.000000 L 494.400000 495.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1423726321)"/><text class="text-italic" x="602.500000" y="405.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">harbor</text></g><g id="(k8s -&gt; osvc)[3]"><path d="M 848.000000 230.000000 L 848.000000 439.000000 S 848.000000 449.000000 838.000000 449.000000 L 568.800000 449.000000 S 558.800000 449.000000 558.800000 459.000000 L 558.800000 495.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#1423726321)"/><text class="text-italic" x="788.500000" y="455.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">vault</text></g><mask id="1423726321" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1249" height="907"> ]]></script><g id="k8s"><g class="shape" ><rect x="12" y="12" width="1045" height="216" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="534.500000" y="45.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">Kubernetes</text></g><g id="osvc"><g class="shape" ><rect x="301" y="499" width="322" height="216" style="fill:#E3E9FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="462.000000" y="532.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">opensvc</text></g><g id="k8s.m1"><g class="shape" ><rect x="87" y="87" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="153.000000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master1</text></g><g id="k8s.m2"><g class="shape" ><rect x="239" y="87" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="305.000000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master2</text></g><g id="k8s.m3"><g class="shape" ><rect x="391" y="87" width="132" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="457.000000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-master3</text></g><g id="k8s.w1"><g class="shape" ><rect x="543" y="87" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="609.500000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker1</text></g><g id="k8s.w2"><g class="shape" ><rect x="696" y="87" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="762.500000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker2</text></g><g id="k8s.w3"><g class="shape" ><rect x="849" y="87" width="133" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="915.500000" y="125.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">k8s-worker3</text></g><g id="osvc.vm1"><g class="shape" ><rect x="376" y="574" width="76" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="414.000000" y="612.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">VM1</text></g><g id="osvc.vm2"><g class="shape" ><rect x="472" y="574" width="76" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text-bold" x="510.000000" y="612.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">VM2</text></g><g id="(k8s -&gt; osvc)[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 221.000000 230.000000 L 221.000000 389.000000 S 221.000000 399.000000 231.000000 399.000000 L 355.600000 399.000000 S 365.600000 399.000000 365.600000 409.000000 L 365.600000 495.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2732539159)"/><text class="text-italic" x="257.500000" y="405.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">keycloak</text></g><g id="(k8s -&gt; osvc)[1]"><path d="M 430.000000 230.000000 L 430.000000 495.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2732539159)"/><text class="text-italic" x="430.500000" y="369.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">heptapod</text></g><g id="(k8s -&gt; osvc)[2]"><path d="M 639.000000 230.000000 L 639.000000 389.000000 S 639.000000 399.000000 629.000000 399.000000 L 504.400000 399.000000 S 494.400000 399.000000 494.400000 409.000000 L 494.400000 495.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2732539159)"/><text class="text-italic" x="602.500000" y="405.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">harbor</text></g><g id="(k8s -&gt; osvc)[3]"><path d="M 848.000000 230.000000 L 848.000000 439.000000 S 848.000000 449.000000 838.000000 449.000000 L 568.800000 449.000000 S 558.800000 449.000000 558.800000 459.000000 L 558.800000 495.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#2732539159)"/><text class="text-italic" x="788.500000" y="455.000000" style="text-anchor:middle;font-size:16px;fill:#676C7E">vault</text></g><mask id="2732539159" maskUnits="userSpaceOnUse" x="-100" y="-100" width="1249" height="907">
<rect x="-100" y="-100" width="1249" height="907" fill="white"></rect> <rect x="-100" y="-100" width="1249" height="907" fill="white"></rect>
<rect x="228.000000" y="389.000000" width="59" height="21" fill="black"></rect> <rect x="228.000000" y="389.000000" width="59" height="21" fill="black"></rect>
<rect x="398.000000" y="353.000000" width="65" height="21" fill="black"></rect> <rect x="398.000000" y="353.000000" width="65" height="21" fill="black"></rect>

Before

Width:  |  Height:  |  Size: 796 KiB

After

Width:  |  Height:  |  Size: 796 KiB

View file

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

View file

@ -39,7 +39,7 @@ width="360" height="322" viewBox="-102 -102 360 322"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="my network"><g class="shape" ><rect x="0" y="0" width="156" height="118" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><image href="https://icons.terrastruct.com/infra/019-network.svg?fuga=1&amp;hoge" x="48.500000" y="29.500000" width="59" height="59" /><text class="text-bold" x="78.000000" y="21.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">my network</text></g><mask id="1587779201" maskUnits="userSpaceOnUse" x="-100" y="-100" width="360" height="322"> ]]></script><g id="my network"><g class="shape" ><rect x="0" y="0" width="156" height="118" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><image href="https://icons.terrastruct.com/infra/019-network.svg?fuga=1&amp;hoge" x="48.500000" y="29.500000" width="59" height="59" /><text class="text-bold" x="78.000000" y="21.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">my network</text></g><mask id="3753597530" maskUnits="userSpaceOnUse" x="-100" y="-100" width="360" height="322">
<rect x="-100" y="-100" width="360" height="322" fill="white"></rect> <rect x="-100" y="-100" width="360" height="322" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 324 KiB

After

Width:  |  Height:  |  Size: 324 KiB

View file

@ -4,7 +4,7 @@
"shapes": [ "shapes": [
{ {
"id": "my network", "id": "my network",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 12, "x": 12,
"y": 12 "y": 12

View file

@ -39,7 +39,7 @@ width="360" height="322" viewBox="-90 -90 360 322"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="my network"><g class="shape" ><rect x="12" y="12" width="156" height="118" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><image href="https://icons.terrastruct.com/infra/019-network.svg?fuga=1&amp;hoge" x="60.500000" y="41.500000" width="59" height="59" /><text class="text-bold" x="90.000000" y="33.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">my network</text></g><mask id="1136491689" maskUnits="userSpaceOnUse" x="-100" y="-100" width="360" height="322"> ]]></script><g id="my network"><g class="shape" ><rect x="12" y="12" width="156" height="118" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g><image href="https://icons.terrastruct.com/infra/019-network.svg?fuga=1&amp;hoge" x="60.500000" y="41.500000" width="59" height="59" /><text class="text-bold" x="90.000000" y="33.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">my network</text></g><mask id="2433954194" maskUnits="userSpaceOnUse" x="-100" y="-100" width="360" height="322">
<rect x="-100" y="-100" width="360" height="322" fill="white"></rect> <rect x="-100" y="-100" width="360" height="322" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 324 KiB

After

Width:  |  Height:  |  Size: 324 KiB

View file

@ -0,0 +1,606 @@
{
"name": "",
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "Office chatter",
"type": "sequence_diagram",
"pos": {
"x": 0,
"y": 0
},
"width": 711,
"height": 1046,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "#FFFFFF",
"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": "Office chatter",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 164,
"labelHeight": 41,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "Office chatter.alice",
"type": "rectangle",
"pos": {
"x": 24,
"y": 110
},
"width": 150,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"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": "Alice",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 38,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "Office chatter.bob",
"type": "rectangle",
"pos": {
"x": 274,
"y": 110
},
"width": 150,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"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": "Bobby",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 48,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "Office chatter.awkward small talk",
"type": "rectangle",
"pos": {
"x": 512,
"y": 110
},
"width": 175,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"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": "awkward small talk",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 135,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "Office chatter.awkward small talk.awkward small talk",
"type": "rectangle",
"pos": {
"x": 593,
"y": 290
},
"width": 12,
"height": 98,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"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": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 135,
"labelHeight": 26,
"zIndex": 2,
"level": 3
},
{
"id": "Office chatter.awkward small talk.awkward small talk.ok",
"type": "page",
"pos": {
"x": 568,
"y": 306
},
"width": 62,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"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": "ok",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 22,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 5,
"level": 4
},
{
"id": "Office chatter.awkward small talk.icebreaker attempt",
"type": "rectangle",
"pos": {
"x": 593,
"y": 9223372036854775807
},
"width": 12,
"height": 80,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "#DEE1EB",
"stroke": "#0D32B2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": true,
"fields": null,
"methods": null,
"columns": null,
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 134,
"labelHeight": 26,
"zIndex": 2,
"level": 3
},
{
"id": "Office chatter.awkward small talk.unfortunate outcome",
"type": "rectangle",
"pos": {
"x": 593,
"y": 9223372036854775807
},
"width": 12,
"height": 80,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "#DEE1EB",
"stroke": "#0D32B2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": true,
"fields": null,
"methods": null,
"columns": null,
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 148,
"labelHeight": 26,
"zIndex": 2,
"level": 3
}
],
"connections": [
{
"id": "Office chatter.(alice -> bob)[1]",
"src": "Office chatter.alice",
"srcArrow": "none",
"srcLabel": "",
"dst": "Office chatter.bob",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "uhm, hi",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 50,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 99,
"y": 502
},
{
"x": 349,
"y": 502
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 4
},
{
"id": "Office chatter.(bob -> alice)[1]",
"src": "Office chatter.bob",
"srcArrow": "none",
"srcLabel": "",
"dst": "Office chatter.alice",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "oh, hello",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 56,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 349,
"y": 632
},
{
"x": 99,
"y": 632
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 4
},
{
"id": "Office chatter.(alice -> bob)[0]",
"src": "Office chatter.alice",
"srcArrow": "none",
"srcLabel": "",
"dst": "Office chatter.bob",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "what did you have for lunch?",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 187,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 99,
"y": 762
},
{
"x": 349,
"y": 762
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 4
},
{
"id": "Office chatter.(bob -> alice)[0]",
"src": "Office chatter.bob",
"srcArrow": "none",
"srcLabel": "",
"dst": "Office chatter.alice",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "that's personal",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 99,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 349,
"y": 892
},
{
"x": 99,
"y": 892
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 4
},
{
"id": "(Office chatter.alice -- )[0]",
"src": "Office chatter.alice",
"srcArrow": "none",
"srcLabel": "",
"dst": "alice-lifeline-end-3851299086",
"dstArrow": "none",
"dstLabel": "",
"opacity": 1,
"strokeDash": 6,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 99,
"y": 176
},
{
"x": 99,
"y": 1022
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 1
},
{
"id": "(Office chatter.bob -- )[0]",
"src": "Office chatter.bob",
"srcArrow": "none",
"srcLabel": "",
"dst": "bob-lifeline-end-3036726343",
"dstArrow": "none",
"dstLabel": "",
"opacity": 1,
"strokeDash": 6,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 349,
"y": 176
},
{
"x": 349,
"y": 1022
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 1
},
{
"id": "(Office chatter.awkward small talk -- )[0]",
"src": "Office chatter.awkward small talk",
"srcArrow": "none",
"srcLabel": "",
"dst": "awkward small talk-lifeline-end-861194358",
"dstArrow": "none",
"dstLabel": "",
"opacity": 1,
"strokeDash": 6,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 599.5,
"y": 176
},
{
"x": 599.5,
"y": 1022
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 1
}
]
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 473 KiB

View file

@ -0,0 +1,606 @@
{
"name": "",
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "Office chatter",
"type": "sequence_diagram",
"pos": {
"x": 12,
"y": 12
},
"width": 711,
"height": 1046,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "#FFFFFF",
"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": "Office chatter",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 164,
"labelHeight": 41,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "Office chatter.alice",
"type": "rectangle",
"pos": {
"x": 36,
"y": 122
},
"width": 150,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"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": "Alice",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 38,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "Office chatter.bob",
"type": "rectangle",
"pos": {
"x": 286,
"y": 122
},
"width": 150,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"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": "Bobby",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 48,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "Office chatter.awkward small talk",
"type": "rectangle",
"pos": {
"x": 524,
"y": 122
},
"width": 175,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"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": "awkward small talk",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 135,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "Office chatter.awkward small talk.awkward small talk",
"type": "rectangle",
"pos": {
"x": 605,
"y": 302
},
"width": 12,
"height": 98,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"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": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 135,
"labelHeight": 26,
"zIndex": 2,
"level": 3
},
{
"id": "Office chatter.awkward small talk.awkward small talk.ok",
"type": "page",
"pos": {
"x": 580,
"y": 318
},
"width": 62,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"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": "ok",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 22,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 5,
"level": 4
},
{
"id": "Office chatter.awkward small talk.icebreaker attempt",
"type": "rectangle",
"pos": {
"x": 605,
"y": 9223372036854775807
},
"width": 12,
"height": 80,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "#DEE1EB",
"stroke": "#0D32B2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": true,
"fields": null,
"methods": null,
"columns": null,
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 134,
"labelHeight": 26,
"zIndex": 2,
"level": 3
},
{
"id": "Office chatter.awkward small talk.unfortunate outcome",
"type": "rectangle",
"pos": {
"x": 605,
"y": 9223372036854775807
},
"width": 12,
"height": 80,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "#DEE1EB",
"stroke": "#0D32B2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": true,
"fields": null,
"methods": null,
"columns": null,
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 148,
"labelHeight": 26,
"zIndex": 2,
"level": 3
}
],
"connections": [
{
"id": "Office chatter.(alice -> bob)[1]",
"src": "Office chatter.alice",
"srcArrow": "none",
"srcLabel": "",
"dst": "Office chatter.bob",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "uhm, hi",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 50,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 111,
"y": 514
},
{
"x": 361,
"y": 514
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 4
},
{
"id": "Office chatter.(bob -> alice)[1]",
"src": "Office chatter.bob",
"srcArrow": "none",
"srcLabel": "",
"dst": "Office chatter.alice",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "oh, hello",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 56,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 361,
"y": 644
},
{
"x": 111,
"y": 644
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 4
},
{
"id": "Office chatter.(alice -> bob)[0]",
"src": "Office chatter.alice",
"srcArrow": "none",
"srcLabel": "",
"dst": "Office chatter.bob",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "what did you have for lunch?",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 187,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 111,
"y": 774
},
{
"x": 361,
"y": 774
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 4
},
{
"id": "Office chatter.(bob -> alice)[0]",
"src": "Office chatter.bob",
"srcArrow": "none",
"srcLabel": "",
"dst": "Office chatter.alice",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "that's personal",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 99,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 361,
"y": 904
},
{
"x": 111,
"y": 904
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 4
},
{
"id": "(Office chatter.alice -- )[0]",
"src": "Office chatter.alice",
"srcArrow": "none",
"srcLabel": "",
"dst": "alice-lifeline-end-3851299086",
"dstArrow": "none",
"dstLabel": "",
"opacity": 1,
"strokeDash": 6,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 111,
"y": 188
},
{
"x": 111,
"y": 1034
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 1
},
{
"id": "(Office chatter.bob -- )[0]",
"src": "Office chatter.bob",
"srcArrow": "none",
"srcLabel": "",
"dst": "bob-lifeline-end-3036726343",
"dstArrow": "none",
"dstLabel": "",
"opacity": 1,
"strokeDash": 6,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 361,
"y": 188
},
{
"x": 361,
"y": 1034
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 1
},
{
"id": "(Office chatter.awkward small talk -- )[0]",
"src": "Office chatter.awkward small talk",
"srcArrow": "none",
"srcLabel": "",
"dst": "awkward small talk-lifeline-end-861194358",
"dstArrow": "none",
"dstLabel": "",
"opacity": 1,
"strokeDash": 6,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 611.5,
"y": 188
},
{
"x": 611.5,
"y": 1034
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 1
}
]
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 473 KiB

View file

@ -43,6 +43,88 @@
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{
"id": "foo.a",
"type": "rectangle",
"pos": {
"x": 24,
"y": 110
},
"width": 150,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"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": "a",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 12,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "foo.b",
"type": "rectangle",
"pos": {
"x": 274,
"y": 110
},
"width": 150,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"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": "b",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 13,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{ {
"id": "foobar", "id": "foobar",
"type": "sequence_diagram", "type": "sequence_diagram",
@ -84,91 +166,9 @@
"zIndex": 0, "zIndex": 0,
"level": 1 "level": 1
}, },
{
"id": "foo.a",
"type": "",
"pos": {
"x": 24,
"y": 110
},
"width": 150,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"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": "a",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 12,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "foo.b",
"type": "",
"pos": {
"x": 274,
"y": 110
},
"width": 150,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"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": "b",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 13,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{ {
"id": "foobar.c", "id": "foobar.c",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 24, "x": 24,
"y": 670 "y": 670
@ -209,7 +209,7 @@
}, },
{ {
"id": "foobar.d", "id": "foobar.d",
"type": "", "type": "rectangle",
"pos": { "pos": {
"x": 274, "x": 274,
"y": 670 "y": 670

View file

@ -39,7 +39,7 @@ width="648" height="1220" viewBox="-100 -100 648 1220"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16); svgEl.setAttribute("height", height * ratio - 16);
} }
}); });
]]></script><g id="foo"><g class="shape" ><rect x="0" y="0" width="448" height="460" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text" x="224.000000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">foo</text></g><g id="foobar"><g class="shape" ><rect x="0" y="560" width="448" height="460" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text" x="224.000000" y="593.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">foobar</text></g><g id="foo.a"><g class="shape" ><rect x="24" y="110" width="150" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="99.000000" y="148.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="foo.b"><g class="shape" ><rect x="274" y="110" width="150" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="349.000000" y="148.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="foobar.c"><g class="shape" ><rect x="24" y="670" width="150" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="99.000000" y="708.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">c</text></g><g id="foobar.d"><g class="shape" ><rect x="274" y="670" width="150" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="349.000000" y="708.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">d</text></g><g id="(foo -&gt; foobar)[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 224.000000 461.000000 C 224.000000 500.000000 224.000000 520.000000 224.000000 557.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3317118462)"/></g><g id="(foo.a -- )[0]"><path d="M 99.000000 178.000000 L 99.000000 435.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#3317118462)"/></g><g id="(foo.b -- )[0]"><path d="M 349.000000 178.000000 L 349.000000 435.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#3317118462)"/></g><g id="(foobar.c -- )[0]"><path d="M 99.000000 738.000000 L 99.000000 995.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#3317118462)"/></g><g id="(foobar.d -- )[0]"><path d="M 349.000000 738.000000 L 349.000000 995.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#3317118462)"/></g><g id="foo.(a -&gt; b)[0]"><path d="M 101.000000 306.000000 L 345.000000 306.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3317118462)"/></g><g id="foobar.(c -&gt; d)[0]"><path d="M 101.000000 866.000000 L 345.000000 866.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3317118462)"/></g><mask id="3317118462" maskUnits="userSpaceOnUse" x="-100" y="-100" width="648" height="1220"> ]]></script><g id="foo"><g class="shape" ><rect x="0" y="0" width="448" height="460" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text" x="224.000000" y="33.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">foo</text></g><g id="foobar"><g class="shape" ><rect x="0" y="560" width="448" height="460" style="fill:#FFFFFF;stroke:#0D32B2;stroke-width:0;" /></g><text class="text" x="224.000000" y="593.000000" style="text-anchor:middle;font-size:28px;fill:#0A0F25">foobar</text></g><g id="foo.a"><g class="shape" ><rect x="24" y="110" width="150" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="99.000000" y="148.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="foo.b"><g class="shape" ><rect x="274" y="110" width="150" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="349.000000" y="148.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="foobar.c"><g class="shape" ><rect x="24" y="670" width="150" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="99.000000" y="708.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">c</text></g><g id="foobar.d"><g class="shape" ><rect x="274" y="670" width="150" height="66" style="fill:#EDF0FD;stroke:#0D32B2;stroke-width:2;" /></g><text class="text" x="349.000000" y="708.500000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">d</text></g><g id="(foo -&gt; foobar)[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 224.000000 461.000000 C 224.000000 500.000000 224.000000 520.000000 224.000000 557.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3099438012)"/></g><g id="(foo.a -- )[0]"><path d="M 99.000000 178.000000 L 99.000000 435.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#3099438012)"/></g><g id="(foo.b -- )[0]"><path d="M 349.000000 178.000000 L 349.000000 435.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#3099438012)"/></g><g id="(foobar.c -- )[0]"><path d="M 99.000000 738.000000 L 99.000000 995.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#3099438012)"/></g><g id="(foobar.d -- )[0]"><path d="M 349.000000 738.000000 L 349.000000 995.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#3099438012)"/></g><g id="foo.(a -&gt; b)[0]"><path d="M 101.000000 306.000000 L 345.000000 306.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3099438012)"/></g><g id="foobar.(c -&gt; d)[0]"><path d="M 101.000000 866.000000 L 345.000000 866.000000" class="connection" style="fill:none;stroke:#0D32B2;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#3099438012)"/></g><mask id="3099438012" maskUnits="userSpaceOnUse" x="-100" y="-100" width="648" height="1220">
<rect x="-100" y="-100" width="648" height="1220" fill="white"></rect> <rect x="-100" y="-100" width="648" height="1220" fill="white"></rect>
</mask><style type="text/css"><![CDATA[ </mask><style type="text/css"><![CDATA[

Before

Width:  |  Height:  |  Size: 328 KiB

After

Width:  |  Height:  |  Size: 328 KiB

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