Merge branch 'terrastruct:master' into master

This commit is contained in:
Barry Nolte 2023-12-16 14:40:33 -08:00 committed by GitHub
commit 82849a231e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
718 changed files with 30268 additions and 14619 deletions

View file

@ -1,31 +1,14 @@
#### Features 🚀
- ELK now routes `sql_table` edges to the exact columns (ty @landmaj) [#1681](https://github.com/terrastruct/d2/pull/1681)
- Adds new unfilled triangle arrowhead. [#1711](https://github.com/terrastruct/d2/pull/1711)
- Grid containers can now have custom label positions. [#1715](https://github.com/terrastruct/d2/pull/1715)
- Themes can be customized via `d2-config` vars. [#1777](https://github.com/terrastruct/d2/pull/1777)
- Icons can be added for special objects (sql_table, class, code, markdown, latex). [#1774](https://github.com/terrastruct/d2/pull/1774)
#### Improvements 🧹
- Grid cells can now contain nested edges [#1629](https://github.com/terrastruct/d2/pull/1629)
- Edges can now go across constant nears, sequence diagrams, and grids including nested ones. [#1631](https://github.com/terrastruct/d2/pull/1631)
- All vars defined in a scope are accessible everywhere in that scope, i.e., an object can use a var defined after itself. [#1695](https://github.com/terrastruct/d2/pull/1695)
- Encoding API switches to standard zlib encoding so that decoding doesn't depend on source. [#1709](https://github.com/terrastruct/d2/pull/1709)
- `currentcolor` is accepted as a color option to inherit parent colors. (ty @hboomsma) [#1700](https://github.com/terrastruct/d2/pull/1700)
- grid containers can now be sized with `width`/`height` even when using a layout plugin without that feature. [#1731](https://github.com/terrastruct/d2/pull/1731)
- Watch mode watches for changes in both the input file and imported files [#1720](https://github.com/terrastruct/d2/pull/1720)
#### Bugfixes ⛑️
- Fixes a bug calculating grid height with only grid-rows and different horizontal-gap and vertical-gap values. [#1646](https://github.com/terrastruct/d2/pull/1646)
- Grid layout now accounts for each cell's outside labels and icons [#1624](https://github.com/terrastruct/d2/pull/1624)
- Grid layout now accounts for labels wider or taller than the shape and fixes default label positions for image grid cells. [#1670](https://github.com/terrastruct/d2/pull/1670)
- Fixes a panic with a spread substitution in a glob map [#1643](https://github.com/terrastruct/d2/pull/1643)
- Fixes use of `null` in `sql_table` constraints (ty @landmaj) [#1660](https://github.com/terrastruct/d2/pull/1660)
- Fixes elk growing shapes with width/height set [#1679](https://github.com/terrastruct/d2/pull/1679)
- Adds a compiler error when accidentally using an arrowhead on a shape [#1686](https://github.com/terrastruct/d2/pull/1686)
- Correctly reports errors from invalid values set by globs. [#1691](https://github.com/terrastruct/d2/pull/1691)
- Fixes panic when spread substitution referenced a nonexistant var. [#1695](https://github.com/terrastruct/d2/pull/1695)
- Fixes incorrect appendix icon numbering. [#1704](https://github.com/terrastruct/d2/pull/1704)
- Fixes crash when using `--watch` and navigating to an invalid board path [#1693](https://github.com/terrastruct/d2/pull/1693)
- Fixes edge case where nested edge globs were creating excess shapes [#1713](https://github.com/terrastruct/d2/pull/1713)
- Fixes a panic with a connection to a grid cell that is a container in TALA [#1729](https://github.com/terrastruct/d2/pull/1729)
- Fix importing files that override an existing value with an array. [#1762](https://github.com/terrastruct/d2/pull/1762)
- Fixes missing unfilled triangle arrowheads when sketch flag is on. [#1763](https://github.com/terrastruct/d2/pull/1763)
- Fixes a bug where the render target could be incorrect if the target path contains "index". [#1764](https://github.com/terrastruct/d2/pull/1764)
- Fixes ELK layout with outside labels/icons. [#1776](https://github.com/terrastruct/d2/pull/1776)
- Fixes a bug where an edge could become disconnected with dagre layout and direction right. [#1778](https://github.com/terrastruct/d2/pull/1778)

View file

@ -0,0 +1,54 @@
D2 0.6.2 makes grid diagrams significantly more powerful. Namely, connections can now be made from grid elements to other grid elements. This enables diagrams like the following.
![vector-grid](https://raw.githubusercontent.com/terrastruct/d2/af841720b48864f5240ae4fb9cb0cb87bcfef038/docs/examples/vector-grid/vector-grid.svg)
> [Source code](https://github.com/terrastruct/d2/blob/master/docs/examples/vector-grid/vector-grid.d2)
> [Playground link](https://play.d2lang.com/?script=xFVNb9swDL37VxDqTgVs-CMfjTAMaJt5p12GYXfFVhOjthTIzNKuyH8fLEu27DpYGxTYoaj5KJHUI_mSlayueU3hxQPg1R6f20-Akm14SYEQbdX4XHLrAngoypICKibqPVNcoMFrVPKR-8cixx2FUKMnr_1D_oQ2wgeEy8pDjVxdFjFn9Y7CbABSIFf3i3WyTskg0VYVuQ3cfPuZLA-VqClEbyXquCuQv-FNSh4HmZQ8vifNewg8ed5vpkzjS_6A_ohQm0_4dfGH5_CLZyhVm11PDbUt0FB4HeiagrYUcrVOv6bpLRk6LdObkmWP0-_UwJbtbbm6jkBwpijIA9ZFzn2Ue7-p2dMnSBgsYmI_o3n7qYc5Ckyp2tK4sFAzj_3J-PVJEgarqIs7uyGekwM--yDA_9Kf0g0struzTFYXMrmM03ma_lcmn3GCyerjmKxGTJ48z3lO7HlNnd12mPhKHq1ojVO2oBn7KArDJuEPJnJZwXeGqniCb1xwxVB2bTKnk7Bla8ebXlKIlmG_ccGDFKjbSCEe4KZXt8u7u_vU2dGJRrX4RqqcK1-xvDg0LQvtwzcSUVZnXqs31VUk422gltSIwqcXd6FPGo6n4WQKPjWRcol-JgWyQvSj_KqzU4J4bvNyiRTWEmGvZH7IsFOv8RgBZIXKGn0jpDsEUO_YnlPj61GH_57jMf9DCXTaHfeI7XgHncz_qcUxXcq4sHvbMVfpAbuQvPYyhZ9MbTlCXlRc1IUUxtHRcW6ZnYIGkjBzIUcUAK67PQl7qJt-BxtOehqli3RFRt7X096ufER6I4kdY-UaUWKUQVvLmeuaO8Y8cYw4ci-tlo5r5l6K3BrCuXtp4bqWboT5yjFuEjLs9IT2dD8C_17SwY-Fs6UTeDKJT05bo6R9BY2gGO0Mzuhfc6HXnGAczwDe3wAAAP__&sketch=1&)
>
> Credit: this diagram is based off of a manually-drawn one from a [blog post](https://github.com/terrastruct/d2/issues/1299)
In addition, another significant feature is that using the ELK layout engine will now route SQL diagrams to their exact columns.
<img width="576" alt="Screen Shot 2023-12-06 at 3 26 39 PM" src="https://github.com/terrastruct/d2/assets/3120367/5b153748-22ed-4bad-bd05-70dfd6e7d3e0">
> [Playground link](https://play.d2lang.com/?script=pI9BroMwDAX3PsW7wOcAWfyrIJdYYDUJaWxaIcTdKyrYV-rS0jzNeJjNlywWsBFgE1cJsEfqnW9JCNAYoMWxDXMxb6zFA2rTzG3t77Lux0xT0iJmH5SAfLDSrjOxeb_UyC4xwDWLOedKO9FJ_ubP81OPmTctIwEv0XHyL-zX992Zgb__q906jfQOAAD__w%3D%3D&sketch=1&layout=elk&)
**Note** that all previous playground links will be broken given the encoding change. The encoding before 0.6.2 used the keyword set as compression dictionary, but it no longer does, so this will be the last time playground links break.
#### Features 🚀
- ELK routes `sql_table` edges to the exact columns (ty @landmaj) [#1681](https://github.com/terrastruct/d2/pull/1681)
- Unfilled triangle arrowhead is available. [#1711](https://github.com/terrastruct/d2/pull/1711)
- Grid containers customize label positions. [#1715](https://github.com/terrastruct/d2/pull/1715)
- A single board from a multi-board diagram can be rendered with `--target` flag. [#1725](https://github.com/terrastruct/d2/pull/1725)
#### Improvements 🧹
- Grid cells can contain nested edges [#1629](https://github.com/terrastruct/d2/pull/1629)
- Edges can go across constant `near`s, sequence diagrams, and grids, including nested ones. [#1631](https://github.com/terrastruct/d2/pull/1631)
- All vars defined in a scope are accessible everywhere in that scope, i.e., an object can use a var defined after itself. [#1695](https://github.com/terrastruct/d2/pull/1695)
- Encoding API switches to standard zlib encoding so that decoding doesn't depend on source. [#1709](https://github.com/terrastruct/d2/pull/1709)
- `currentcolor` is accepted as a color option to inherit parent colors. (ty @hboomsma) [#1700](https://github.com/terrastruct/d2/pull/1700)
- Grid containers can be sized with `width`/`height` even when using a layout plugin without that feature. [#1731](https://github.com/terrastruct/d2/pull/1731)
- Watch mode watches for changes in both the input file and imported files [#1720](https://github.com/terrastruct/d2/pull/1720)
#### Bugfixes ⛑️
- Fixes a bug calculating grid height with only grid-rows and different horizontal-gap and vertical-gap values. [#1646](https://github.com/terrastruct/d2/pull/1646)
- Grid layout accounts for each cell's outside labels and icons [#1624](https://github.com/terrastruct/d2/pull/1624)
- Grid layout accounts for labels wider or taller than the shape and fixes default label positions for image grid cells. [#1670](https://github.com/terrastruct/d2/pull/1670)
- Fixes a panic with a spread substitution in a glob map [#1643](https://github.com/terrastruct/d2/pull/1643)
- Fixes use of `null` in `sql_table` constraints (ty @landmaj) [#1660](https://github.com/terrastruct/d2/pull/1660)
- Fixes ELK growing shapes with width/height set [#1679](https://github.com/terrastruct/d2/pull/1679)
- Adds a compiler error when accidentally using an arrowhead on a shape [#1686](https://github.com/terrastruct/d2/pull/1686)
- Correctly reports errors from invalid values set by globs. [#1691](https://github.com/terrastruct/d2/pull/1691)
- Fixes panic when spread substitution referenced a nonexistant var. [#1695](https://github.com/terrastruct/d2/pull/1695)
- Fixes incorrect appendix icon numbering. [#1704](https://github.com/terrastruct/d2/pull/1704)
- Fixes crash when using `--watch` and navigating to an invalid board path [#1693](https://github.com/terrastruct/d2/pull/1693)
- Fixes edge case where nested edge globs were creating excess shapes [#1713](https://github.com/terrastruct/d2/pull/1713)
- Fixes a panic with a connection to a grid cell that is a container in TALA [#1729](https://github.com/terrastruct/d2/pull/1729)
- Fixes incorrect grid cell positioning when the grid has a shape set and fixes content sometimes escaping circle shapes. [#1734](https://github.com/terrastruct/d2/pull/1734)
- Fixes content sometimes escaping cloud shapes. [#1736](https://github.com/terrastruct/d2/pull/1736)
- Fixes panic using a glob filter (e.g. `&a`) outside globs. [#1748](https://github.com/terrastruct/d2/pull/1748)
- Fixes glob keys with import values (e.g. `user*: @lib/user`). [#1755](https://github.com/terrastruct/d2/pull/1755)

View file

@ -111,6 +111,11 @@ Bundle all assets and layers into the output svg
.It Fl -force-appendix Ar false
An appendix for tooltips and links is added to PNG exports since they are not interactive. Setting this to true adds an appendix to SVG exports as well
.Ns .
.It Fl -target
Target board to render. Pass an empty string to target root board. If target ends with '*', it will be rendered
with all of its scenarios, steps, and layers. Otherwise, only the target board will be rendered. E.g. --target=''
to render root board only or --target='layers.x.*' to render layer 'x' with all of its children
.Ns .
.It Fl d , -debug
Print debug logs
.Ns .

View file

@ -2,6 +2,7 @@ package d2cli
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
@ -21,6 +22,7 @@ import (
"oss.terrastruct.com/util-go/go2"
"oss.terrastruct.com/util-go/xmain"
"oss.terrastruct.com/d2/d2ast"
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2lib"
"oss.terrastruct.com/d2/d2parser"
@ -115,6 +117,7 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
if err != nil {
return err
}
targetFlag := ms.Opts.String("", "target", "", "*", "target board to render. Pass an empty string to target root board. If target ends with '*', it will be rendered with all of its scenarios, steps, and layers. Otherwise, only the target board will be rendered. E.g. --target='' to render root board only or --target='layers.x.*' to render layer 'x' with all of its children.")
fontRegularFlag := ms.Opts.String("D2_FONT_REGULAR", "font-regular", "", "", "path to .ttf file to use for the regular font. If none provided, Source Sans Pro Regular is used.")
fontItalicFlag := ms.Opts.String("D2_FONT_ITALIC", "font-italic", "", "", "path to .ttf file to use for the italic font. If none provided, Source Sans Pro Regular-Italic is used.")
@ -310,6 +313,9 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
if inputPath == "-" {
return xmain.UsageErrorf("-w[atch] cannot be combined with reading input from stdin")
}
if *targetFlag != "*" {
return xmain.UsageErrorf("-w[atch] cannot be combined with --target")
}
w, err := newWatcher(ctx, ms, watcherOpts{
plugins: plugins,
layout: layoutFlag,
@ -330,10 +336,30 @@ func Run(ctx context.Context, ms *xmain.State) (err error) {
return w.run()
}
var boardPath []string
var noChildren bool
switch *targetFlag {
case "*":
case "":
noChildren = true
default:
target := *targetFlag
if strings.HasSuffix(target, ".*") {
target = target[:len(target)-2]
} else {
noChildren = true
}
key, err := d2parser.ParseKey(target)
if err != nil {
return xmain.UsageErrorf("invalid target: %s", *targetFlag)
}
boardPath = key.IDA()
}
ctx, cancel := timelib.WithTimeout(ctx, time.Minute*2)
defer cancel()
_, written, err := compile(ctx, ms, plugins, nil, layoutFlag, renderOpts, fontFamily, *animateIntervalFlag, inputPath, outputPath, "", *bundleFlag, *forceAppendixFlag, pw.Page)
_, written, err := compile(ctx, ms, plugins, nil, layoutFlag, renderOpts, fontFamily, *animateIntervalFlag, inputPath, outputPath, boardPath, noChildren, *bundleFlag, *forceAppendixFlag, pw.Page)
if err != nil {
if written {
return fmt.Errorf("failed to fully compile (partial render written) %s: %w", ms.HumanPath(inputPath), err)
@ -368,7 +394,47 @@ func LayoutResolver(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plu
}
}
func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs fs.FS, layout *string, renderOpts d2svg.RenderOpts, fontFamily *d2fonts.FontFamily, animateInterval int64, inputPath, outputPath, boardPath string, bundle, forceAppendix bool, page playwright.Page) (_ []byte, written bool, _ error) {
func RouterResolver(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin) func(engine string) (d2graph.RouteEdges, error) {
cached := make(map[string]d2graph.RouteEdges)
return func(engine string) (d2graph.RouteEdges, error) {
if c, ok := cached[engine]; ok {
return c, nil
}
plugin, err := d2plugin.FindPlugin(ctx, plugins, engine)
if err != nil {
if errors.Is(err, exec.ErrNotFound) {
return nil, layoutNotFound(ctx, plugins, engine)
}
return nil, err
}
pluginInfo, err := plugin.Info(ctx)
if err != nil {
return nil, err
}
hasRouter := false
for _, feat := range pluginInfo.Features {
if feat == d2plugin.ROUTES_EDGES {
hasRouter = true
break
}
}
if !hasRouter {
return nil, nil
}
routingPlugin, ok := plugin.(d2plugin.RoutingPlugin)
if !ok {
return nil, fmt.Errorf("plugin has routing feature but does not implement RoutingPlugin")
}
routeEdges := d2graph.RouteEdges(routingPlugin.RouteEdges)
cached[engine] = routeEdges
return routeEdges, nil
}
}
func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs fs.FS, layout *string, renderOpts d2svg.RenderOpts, fontFamily *d2fonts.FontFamily, animateInterval int64, inputPath, outputPath string, boardPath []string, noChildren, bundle, forceAppendix bool, page playwright.Page) (_ []byte, written bool, _ error) {
start := time.Now()
input, err := ms.ReadPath(inputPath)
if err != nil {
@ -386,9 +452,30 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs
InputPath: inputPath,
LayoutResolver: LayoutResolver(ctx, ms, plugins),
Layout: layout,
RouterResolver: RouterResolver(ctx, ms, plugins),
FS: fs,
}
if os.Getenv("D2_LSP_MODE") == "1" {
// only the parse result is needed if running d2 for lsp
ast, err := d2lib.Parse(ctx, string(input), opts)
if err != nil {
return nil, false, err
}
type LspOutputData struct {
Ast *d2ast.Map
Err error
}
jsonOutput, err := json.Marshal(LspOutputData{Ast: ast, Err: err})
if err != nil {
return nil, false, err
}
fmt.Print(string(jsonOutput))
os.Exit(42)
return nil, false, nil
}
cancel := background.Repeat(func() {
ms.Log.Info.Printf("compiling & running layout algorithms...")
}, time.Second*5)
@ -400,6 +487,16 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs
}
cancel()
diagram = diagram.GetBoard(boardPath)
if diagram == nil {
return nil, false, fmt.Errorf(`render target "%s" not found`, strings.Join(boardPath, "."))
}
if noChildren {
diagram.Layers = nil
diagram.Scenarios = nil
diagram.Steps = nil
}
plugin, _ := d2plugin.FindPlugin(ctx, plugins, *opts.Layout)
if animateInterval > 0 {
@ -455,9 +552,9 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs
case PDF:
pageMap := buildBoardIDToIndex(diagram, nil, nil)
path := []pdf.BoardTitle{
{Name: "root", BoardID: "root"},
{Name: diagram.Root.Label, BoardID: "root"},
}
pdf, err := renderPDF(ctx, ms, plugin, renderOpts, outputPath, page, ruler, diagram, nil, path, pageMap)
pdf, err := renderPDF(ctx, ms, plugin, renderOpts, outputPath, page, ruler, diagram, nil, path, pageMap, diagram.Root.Label != "")
if err != nil {
return pdf, false, err
}
@ -469,10 +566,10 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs
if user, err := user.Current(); err == nil {
username = user.Username
}
description := "Presentation generated with D2 - https://d2lang.com/"
description := "Presentation generated with D2 - https://d2lang.com"
rootName := getFileName(outputPath)
// version must be only numbers to avoid issues with PowerPoint
p := pptx.NewPresentation(rootName, description, rootName, username, version.OnlyNumbers())
p := pptx.NewPresentation(rootName, description, rootName, username, version.OnlyNumbers(), diagram.Root.Label != "")
boardIdToIndex := buildBoardIDToIndex(diagram, nil, nil)
path := []pptx.BoardTitle{
@ -503,12 +600,13 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs
}
}
board := diagram.GetBoard(boardPath)
if board == nil {
return nil, false, fmt.Errorf(`Diagram with path "%s" not found. Did you mean to specify a board like "layers.%s"?`, boardPath, boardPath)
var boards [][]byte
var err error
if noChildren {
boards, err = renderSingle(ctx, ms, compileDur, plugin, renderOpts, inputPath, outputPath, bundle, forceAppendix, page, ruler, diagram)
} else {
boards, err = render(ctx, ms, compileDur, plugin, renderOpts, inputPath, outputPath, bundle, forceAppendix, page, ruler, diagram)
}
boards, err := render(ctx, ms, compileDur, plugin, renderOpts, inputPath, outputPath, bundle, forceAppendix, page, ruler, board)
if err != nil {
return nil, false, err
}
@ -725,6 +823,19 @@ func render(ctx context.Context, ms *xmain.State, compileDur time.Duration, plug
return boards, nil
}
func renderSingle(ctx context.Context, ms *xmain.State, compileDur time.Duration, plugin d2plugin.Plugin, opts d2svg.RenderOpts, inputPath, outputPath string, bundle, forceAppendix bool, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram) ([][]byte, error) {
start := time.Now()
out, err := _render(ctx, ms, plugin, opts, outputPath, bundle, forceAppendix, page, ruler, diagram)
if err != nil {
return [][]byte{}, err
}
dur := compileDur + time.Since(start)
if opts.MasterID == "" {
ms.Log.Success.Printf("successfully compiled %s to %s in %s", ms.HumanPath(inputPath), ms.HumanPath(outputPath), dur)
}
return [][]byte{out}, nil
}
func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, outputPath string, bundle, forceAppendix bool, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram) ([]byte, error) {
toPNG := getExportExtension(outputPath) == PNG
var scale *float64
@ -740,6 +851,8 @@ func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts
ThemeID: opts.ThemeID,
DarkThemeID: opts.DarkThemeID,
MasterID: opts.MasterID,
ThemeOverrides: opts.ThemeOverrides,
DarkThemeOverrides: opts.DarkThemeOverrides,
Scale: scale,
})
if err != nil {
@ -803,7 +916,7 @@ func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts
return svg, nil
}
func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, outputPath string, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram, doc *pdf.GoFPDF, boardPath []pdf.BoardTitle, pageMap map[string]int) (svg []byte, err error) {
func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, outputPath string, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram, doc *pdf.GoFPDF, boardPath []pdf.BoardTitle, pageMap map[string]int, includeNav bool) (svg []byte, err error) {
var isRoot bool
if doc == nil {
doc = pdf.Init()
@ -862,7 +975,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt
if err != nil {
return svg, err
}
err = doc.AddPDFPage(pngImg, boardPath, *opts.ThemeID, rootFill, diagram.Shapes, *opts.Pad, viewboxX, viewboxY, pageMap)
err = doc.AddPDFPage(pngImg, boardPath, *opts.ThemeID, rootFill, diagram.Shapes, *opts.Pad, viewboxX, viewboxY, pageMap, includeNav)
if err != nil {
return svg, err
}
@ -870,30 +983,30 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt
for _, dl := range diagram.Layers {
path := append(boardPath, pdf.BoardTitle{
Name: dl.Name,
Name: dl.Root.Label,
BoardID: strings.Join([]string{boardPath[len(boardPath)-1].BoardID, LAYERS, dl.Name}, "."),
})
_, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, doc, path, pageMap)
_, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, doc, path, pageMap, includeNav)
if err != nil {
return nil, err
}
}
for _, dl := range diagram.Scenarios {
path := append(boardPath, pdf.BoardTitle{
Name: dl.Name,
Name: dl.Root.Label,
BoardID: strings.Join([]string{boardPath[len(boardPath)-1].BoardID, SCENARIOS, dl.Name}, "."),
})
_, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, doc, path, pageMap)
_, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, doc, path, pageMap, includeNav)
if err != nil {
return nil, err
}
}
for _, dl := range diagram.Steps {
path := append(boardPath, pdf.BoardTitle{
Name: dl.Name,
Name: dl.Root.Label,
BoardID: strings.Join([]string{boardPath[len(boardPath)-1].BoardID, STEPS, dl.Name}, "."),
})
_, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, doc, path, pageMap)
_, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, doc, path, pageMap, includeNav)
if err != nil {
return nil, err
}
@ -1247,3 +1360,7 @@ func AnimatePNGs(ms *xmain.State, pngs [][]byte, animIntervalMs int) ([]byte, er
return xgif.AnimatePNGs(pngs, animIntervalMs)
}
func init() {
ctxlog.Init()
}

View file

@ -292,15 +292,15 @@ func (w *watcher) watchLoop(ctx context.Context) error {
var changedList []string
for k := range changed {
changedList = append(changedList, k)
delete(changed, k)
}
sort.Strings(changedList)
changedStr := w.ms.HumanPath(changedList[0])
for i := 1; i < len(changed); i++ {
for i := 1; i < len(changedList); i++ {
changedStr += fmt.Sprintf(", %s", w.ms.HumanPath(changedList[i]))
}
w.ms.Log.Info.Printf("detected change in %s: recompiling...", changedStr)
w.requestCompile()
changed = make(map[string]struct{})
case err, ok := <-w.fw.Errors:
if !ok {
return errors.New("fsnotify watcher closed")
@ -426,7 +426,11 @@ func (w *watcher) compileLoop(ctx context.Context) error {
fs := trackedFS{}
w.boardpathMu.Lock()
svg, _, err := compile(ctx, w.ms, w.plugins, &fs, w.layout, w.renderOpts, w.fontFamily, w.animateInterval, w.inputPath, w.outputPath, w.boardPath, w.bundle, w.forceAppendix, w.pw.Page)
var boardPath []string
if w.boardPath != "" {
boardPath = strings.Split(w.boardPath, string(os.PathSeparator))
}
svg, _, err := compile(ctx, w.ms, w.plugins, &fs, w.layout, w.renderOpts, w.fontFamily, w.animateInterval, w.inputPath, w.outputPath, boardPath, false, w.bundle, w.forceAppendix, w.pw.Page)
w.boardpathMu.Unlock()
errs := ""
if err != nil {

View file

@ -17,6 +17,7 @@ import (
"oss.terrastruct.com/d2/d2ir"
"oss.terrastruct.com/d2/d2parser"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/lib/color"
"oss.terrastruct.com/d2/lib/textmeasure"
)
@ -54,7 +55,11 @@ func Compile(p string, r io.Reader, opts *CompileOptions) (*d2graph.Graph, *d2ta
g.FS = opts.FS
g.SortObjectsByAST()
g.SortEdgesByAST()
return g, compileConfig(ir), nil
config, err := compileConfig(ir)
if err != nil {
return nil, nil, err
}
return g, config, nil
}
func compileIR(ast *d2ast.Map, m *d2ir.Map) (*d2graph.Graph, error) {
@ -1336,10 +1341,10 @@ func parentSeqDiagram(n d2ir.Node) *d2ir.Map {
}
}
func compileConfig(ir *d2ir.Map) *d2target.Config {
func compileConfig(ir *d2ir.Map) (*d2target.Config, error) {
f := ir.GetField("vars", "d2-config")
if f == nil || f.Map() == nil {
return nil
return nil, nil
}
configMap := f.Map()
@ -1375,5 +1380,87 @@ func compileConfig(ir *d2ir.Map) *d2target.Config {
config.LayoutEngine = go2.Pointer(f.Primary().Value.ScalarString())
}
return config
f = configMap.GetField("theme-overrides")
if f != nil {
overrides, err := compileThemeOverrides(f.Map())
if err != nil {
return nil, err
}
config.ThemeOverrides = overrides
}
f = configMap.GetField("dark-theme-overrides")
if f != nil {
overrides, err := compileThemeOverrides(f.Map())
if err != nil {
return nil, err
}
config.DarkThemeOverrides = overrides
}
return config, nil
}
func compileThemeOverrides(m *d2ir.Map) (*d2target.ThemeOverrides, error) {
if m == nil {
return nil, nil
}
themeOverrides := d2target.ThemeOverrides{}
err := &d2parser.ParseError{}
FOR:
for _, f := range m.Fields {
switch strings.ToUpper(f.Name) {
case "N1":
themeOverrides.N1 = go2.Pointer(f.Primary().Value.ScalarString())
case "N2":
themeOverrides.N2 = go2.Pointer(f.Primary().Value.ScalarString())
case "N3":
themeOverrides.N3 = go2.Pointer(f.Primary().Value.ScalarString())
case "N4":
themeOverrides.N4 = go2.Pointer(f.Primary().Value.ScalarString())
case "N5":
themeOverrides.N5 = go2.Pointer(f.Primary().Value.ScalarString())
case "N6":
themeOverrides.N6 = go2.Pointer(f.Primary().Value.ScalarString())
case "N7":
themeOverrides.N7 = go2.Pointer(f.Primary().Value.ScalarString())
case "B1":
themeOverrides.B1 = go2.Pointer(f.Primary().Value.ScalarString())
case "B2":
themeOverrides.B2 = go2.Pointer(f.Primary().Value.ScalarString())
case "B3":
themeOverrides.B3 = go2.Pointer(f.Primary().Value.ScalarString())
case "B4":
themeOverrides.B4 = go2.Pointer(f.Primary().Value.ScalarString())
case "B5":
themeOverrides.B5 = go2.Pointer(f.Primary().Value.ScalarString())
case "B6":
themeOverrides.B6 = go2.Pointer(f.Primary().Value.ScalarString())
case "AA2":
themeOverrides.AA2 = go2.Pointer(f.Primary().Value.ScalarString())
case "AA4":
themeOverrides.AA4 = go2.Pointer(f.Primary().Value.ScalarString())
case "AA5":
themeOverrides.AA5 = go2.Pointer(f.Primary().Value.ScalarString())
case "AB4":
themeOverrides.AB4 = go2.Pointer(f.Primary().Value.ScalarString())
case "AB5":
themeOverrides.AB5 = go2.Pointer(f.Primary().Value.ScalarString())
default:
err.Errors = append(err.Errors, d2parser.Errorf(f.LastPrimaryKey(), fmt.Sprintf(`"%s" is not a valid theme code`, f.Name)).(d2ast.Error))
continue FOR
}
if !go2.Contains(color.NamedColors, strings.ToLower(f.Primary().Value.ScalarString())) && !color.ColorHexRegex.MatchString(f.Primary().Value.ScalarString()) {
err.Errors = append(err.Errors, d2parser.Errorf(f.LastPrimaryKey(), fmt.Sprintf(`expected "%s" to be a valid named color ("orange") or a hex code ("#f0ff3a")`, f.Name)).(d2ast.Error))
}
}
if !err.Empty() {
return nil, err
}
if themeOverrides != (d2target.ThemeOverrides{}) {
return &themeOverrides, nil
}
return nil, nil
}

View file

@ -2812,6 +2812,21 @@ g: |md
d2/testdata/d2compiler/TestCompile/text_no_label.d2:15:1: block string cannot be empty
d2/testdata/d2compiler/TestCompile/text_no_label.d2:4:1: shape text must have a non-empty label
d2/testdata/d2compiler/TestCompile/text_no_label.d2:7:1: shape text must have a non-empty label`,
},
{
name: "var-not-color",
text: `vars: {
d2-config: {
theme-overrides: {
B1: potato
potato: B1
}
}
}
a
`,
expErr: `d2/testdata/d2compiler/TestCompile/var-not-color.d2:4:7: expected "B1" to be a valid named color ("orange") or a hex code ("#f0ff3a")
d2/testdata/d2compiler/TestCompile/var-not-color.d2:5:4: "potato" is not a valid theme code`,
},
{
name: "no_arrowheads_in_shape",

View file

@ -2,11 +2,14 @@ package d2exporter
import (
"context"
"net/url"
"strconv"
"strings"
"oss.terrastruct.com/util-go/go2"
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2parser"
"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes"
@ -17,6 +20,11 @@ import (
func Export(ctx context.Context, g *d2graph.Graph, fontFamily *d2fonts.FontFamily) (*d2target.Diagram, error) {
diagram := d2target.NewDiagram()
applyStyles(&diagram.Root, g.Root)
if g.Root.Label.MapKey == nil {
diagram.Root.Label = g.Name
} else {
diagram.Root.Label = g.Root.Label.Value
}
diagram.Name = g.Name
diagram.IsFolderOnly = g.IsFolderOnly
if fontFamily == nil {
@ -29,7 +37,7 @@ func Export(ctx context.Context, g *d2graph.Graph, fontFamily *d2fonts.FontFamil
diagram.Shapes = make([]d2target.Shape, len(g.Objects))
for i := range g.Objects {
diagram.Shapes[i] = toShape(g.Objects[i], g.Theme)
diagram.Shapes[i] = toShape(g.Objects[i], g)
}
diagram.Connections = make([]d2target.Connection, len(g.Edges))
@ -126,7 +134,7 @@ func applyStyles(shape *d2target.Shape, obj *d2graph.Object) {
}
}
func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
func toShape(obj *d2graph.Object, g *d2graph.Graph) d2target.Shape {
shape := d2target.BaseShape()
shape.SetType(obj.Shape.Value)
shape.ID = obj.AbsID()
@ -152,7 +160,7 @@ func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
}
applyStyles(shape, obj)
applyTheme(shape, obj, theme)
applyTheme(shape, obj, g.Theme)
shape.Color = text.GetColor(shape.Italic)
applyStyles(shape, obj)
@ -167,6 +175,10 @@ func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
case d2target.ShapeSQLTable:
shape.SQLTable = *obj.SQLTable
shape.FontSize -= d2target.HeaderFontAdd
case d2target.ShapeCloud:
if obj.ContentAspectRatio != nil {
shape.ContentAspectRatio = go2.Pointer(*obj.ContentAspectRatio)
}
}
shape.Label = text.Text
shape.LabelWidth = text.Dimensions.Width
@ -184,6 +196,7 @@ func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
}
if obj.Link != nil {
shape.Link = obj.Link.Value
shape.PrettyLink = toPrettyLink(g, obj.Link.Value)
}
shape.Icon = obj.Icon
if obj.IconPosition != nil {
@ -193,6 +206,50 @@ func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
return *shape
}
func toPrettyLink(g *d2graph.Graph, link string) string {
u, err := url.ParseRequestURI(link)
if err == nil && u.Host != "" && len(u.RawPath) > 30 {
return u.Scheme + "://" + u.Host + u.RawPath[:10] + "..." + u.RawPath[len(u.RawPath)-10:]
} else if err != nil {
linkKey, err := d2parser.ParseKey(link)
if err != nil {
return link
}
rootG := g
for rootG.Parent != nil {
rootG = rootG.Parent
}
var prettyLink []string
FOR:
for i := 0; i < len(linkKey.Path); i++ {
p := linkKey.Path[i].Unbox().ScalarString()
if i > 0 {
switch p {
case "layers", "scenarios", "steps":
continue FOR
}
rootG = rootG.GetBoard(p)
if rootG == nil {
return link
}
}
if rootG.Root.Label.MapKey != nil {
prettyLink = append(prettyLink, rootG.Root.Label.Value)
} else {
prettyLink = append(prettyLink, rootG.Name)
}
}
for _, l := range prettyLink {
// If any part of it is blank, "x > > y" looks stupid, so just use the last
if l == "" {
return prettyLink[len(prettyLink)-1]
}
}
return strings.Join(prettyLink, " > ")
}
return link
}
func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection {
connection := d2target.BaseConnection()
connection.ID = edge.AbsID()

View file

@ -235,7 +235,7 @@ func run(t *testing.T, tc testCase) {
assert.JSON(t, nil, err)
graphInfo := d2layouts.NestedGraphInfo(g.Root)
err = d2layouts.LayoutNested(ctx, g, graphInfo, d2dagrelayout.DefaultLayout)
err = d2layouts.LayoutNested(ctx, g, graphInfo, d2dagrelayout.DefaultLayout, d2layouts.DefaultRouter)
if err != nil {
t.Fatal(err)
}

View file

@ -1,159 +0,0 @@
package d2graph
import "regexp"
// namedColors is a list of valid CSS colors
var namedColors = []string{
"currentcolor",
"transparent",
"aliceblue",
"antiquewhite",
"aqua",
"aquamarine",
"azure",
"beige",
"bisque",
"black",
"blanchedalmond",
"blue",
"blueviolet",
"brown",
"burlywood",
"cadetblue",
"chartreuse",
"chocolate",
"coral",
"cornflowerblue",
"cornsilk",
"crimson",
"cyan",
"darkblue",
"darkcyan",
"darkgoldenrod",
"darkgray",
"darkgrey",
"darkgreen",
"darkkhaki",
"darkmagenta",
"darkolivegreen",
"darkorange",
"darkorchid",
"darkred",
"darksalmon",
"darkseagreen",
"darkslateblue",
"darkslategray",
"darkslategrey",
"darkturquoise",
"darkviolet",
"deeppink",
"deepskyblue",
"dimgray",
"dimgrey",
"dodgerblue",
"firebrick",
"floralwhite",
"forestgreen",
"fuchsia",
"gainsboro",
"ghostwhite",
"gold",
"goldenrod",
"gray",
"grey",
"green",
"greenyellow",
"honeydew",
"hotpink",
"indianred",
"indigo",
"ivory",
"khaki",
"lavender",
"lavenderblush",
"lawngreen",
"lemonchiffon",
"lightblue",
"lightcoral",
"lightcyan",
"lightgoldenrodyellow",
"lightgray",
"lightgrey",
"lightgreen",
"lightpink",
"lightsalmon",
"lightseagreen",
"lightskyblue",
"lightslategray",
"lightslategrey",
"lightsteelblue",
"lightyellow",
"lime",
"limegreen",
"linen",
"magenta",
"maroon",
"mediumaquamarine",
"mediumblue",
"mediumorchid",
"mediumpurple",
"mediumseagreen",
"mediumslateblue",
"mediumspringgreen",
"mediumturquoise",
"mediumvioletred",
"midnightblue",
"mintcream",
"mistyrose",
"moccasin",
"navajowhite",
"navy",
"oldlace",
"olive",
"olivedrab",
"orange",
"orangered",
"orchid",
"palegoldenrod",
"palegreen",
"paleturquoise",
"palevioletred",
"papayawhip",
"peachpuff",
"peru",
"pink",
"plum",
"powderblue",
"purple",
"rebeccapurple",
"red",
"rosybrown",
"royalblue",
"saddlebrown",
"salmon",
"sandybrown",
"seagreen",
"seashell",
"sienna",
"silver",
"skyblue",
"slateblue",
"slategray",
"slategrey",
"snow",
"springgreen",
"steelblue",
"tan",
"teal",
"thistle",
"tomato",
"turquoise",
"violet",
"wheat",
"white",
"whitesmoke",
"yellow",
"yellowgreen",
}
var colorHexRegex = regexp.MustCompile(`^#(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$`)

View file

@ -80,6 +80,7 @@ func (g *Graph) RootBoard() *Graph {
}
type LayoutGraph func(context.Context, *Graph) error
type RouteEdges func(context.Context, *Graph, []*Edge) error
// TODO consider having different Scalar types
// Right now we'll hold any types in Value and just convert, e.g. floats
@ -107,6 +108,8 @@ type Object struct {
LabelPosition *string `json:"labelPosition,omitempty"`
IconPosition *string `json:"iconPosition,omitempty"`
ContentAspectRatio *float64 `json:"contentAspectRatio,omitempty"`
Class *d2target.Class `json:"class,omitempty"`
SQLTable *d2target.SQLTable `json:"sql_table,omitempty"`
@ -249,7 +252,7 @@ func (s *Style) Apply(key, value string) error {
if s.Stroke == nil {
break
}
if !go2.Contains(namedColors, strings.ToLower(value)) && !colorHexRegex.MatchString(value) {
if !go2.Contains(color.NamedColors, strings.ToLower(value)) && !color.ColorHexRegex.MatchString(value) {
return errors.New(`expected "stroke" to be a valid named color ("orange") or a hex code ("#f0ff3a")`)
}
s.Stroke.Value = value
@ -257,7 +260,7 @@ func (s *Style) Apply(key, value string) error {
if s.Fill == nil {
break
}
if !go2.Contains(namedColors, strings.ToLower(value)) && !colorHexRegex.MatchString(value) {
if !go2.Contains(color.NamedColors, strings.ToLower(value)) && !color.ColorHexRegex.MatchString(value) {
return errors.New(`expected "fill" to be a valid named color ("orange") or a hex code ("#f0ff3a")`)
}
s.Fill.Value = value
@ -344,7 +347,7 @@ func (s *Style) Apply(key, value string) error {
if s.FontColor == nil {
break
}
if !go2.Contains(namedColors, strings.ToLower(value)) && !colorHexRegex.MatchString(value) {
if !go2.Contains(color.NamedColors, strings.ToLower(value)) && !color.ColorHexRegex.MatchString(value) {
return errors.New(`expected "font-color" to be a valid named color ("orange") or a hex code ("#f0ff3a")`)
}
s.FontColor.Value = value
@ -562,6 +565,10 @@ func (obj *Object) HasLabel() bool {
}
}
func (obj *Object) HasIcon() bool {
return obj.Icon != nil && obj.Shape.Value != d2target.ShapeImage
}
func (obj *Object) AbsID() string {
if obj.Parent != nil && obj.Parent.ID != "" {
return obj.Parent.AbsID() + "." + obj.ID
@ -1068,13 +1075,17 @@ func (obj *Object) SizeToContent(contentWidth, contentHeight, paddingX, paddingY
obj.Width = sideLength
obj.Height = sideLength
} else if desiredHeight == 0 || desiredWidth == 0 {
switch s.GetType() {
switch shapeType {
case shape.PERSON_TYPE:
obj.Width, obj.Height = shape.LimitAR(obj.Width, obj.Height, shape.PERSON_AR_LIMIT)
case shape.OVAL_TYPE:
obj.Width, obj.Height = shape.LimitAR(obj.Width, obj.Height, shape.OVAL_AR_LIMIT)
}
}
if shapeType == shape.CLOUD_TYPE {
innerBox := s.GetInnerBoxForContent(contentWidth, contentHeight)
obj.ContentAspectRatio = go2.Pointer(innerBox.Width / innerBox.Height)
}
}
func (obj *Object) OuterNearContainer() *Object {
@ -1499,6 +1510,9 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
// give shapes with icons extra padding to fit their label
if obj.Icon != nil {
switch shapeType {
case shape.TABLE_TYPE, shape.CLASS_TYPE, shape.CODE_TYPE, shape.TEXT_TYPE:
default:
labelHeight := float64(labelDims.Height + INNER_LABEL_PADDING)
// Evenly pad enough to fit label above icon
if desiredWidth == 0 {
@ -1508,9 +1522,10 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
paddingY += labelHeight
}
}
}
if desiredWidth == 0 {
switch shapeType {
case shape.TABLE_TYPE, shape.CLASS_TYPE, shape.CODE_TYPE, shape.IMAGE_TYPE:
case shape.TABLE_TYPE, shape.CLASS_TYPE, shape.CODE_TYPE:
default:
if obj.Link != nil {
paddingX += 32
@ -1940,6 +1955,10 @@ func (obj *Object) Is3D() bool {
}
func (obj *Object) Spacing() (margin, padding geo.Spacing) {
return obj.SpacingOpt(2*label.PADDING, 2*label.PADDING, true)
}
func (obj *Object) SpacingOpt(labelPadding, iconPadding float64, maxIconSize bool) (margin, padding geo.Spacing) {
if obj.HasLabel() {
var position label.Position
if obj.LabelPosition != nil {
@ -1948,10 +1967,10 @@ func (obj *Object) Spacing() (margin, padding geo.Spacing) {
var labelWidth, labelHeight float64
if obj.LabelDimensions.Width > 0 {
labelWidth = float64(obj.LabelDimensions.Width) + 2*label.PADDING
labelWidth = float64(obj.LabelDimensions.Width) + labelPadding
}
if obj.LabelDimensions.Height > 0 {
labelHeight = float64(obj.LabelDimensions.Height) + 2*label.PADDING
labelHeight = float64(obj.LabelDimensions.Height) + labelPadding
}
switch position {
@ -1974,13 +1993,16 @@ func (obj *Object) Spacing() (margin, padding geo.Spacing) {
}
}
if obj.Icon != nil && obj.Shape.Value != d2target.ShapeImage {
if obj.HasIcon() {
var position label.Position
if obj.IconPosition != nil {
position = label.FromString(*obj.IconPosition)
}
iconSize := float64(d2target.MAX_ICON_SIZE + 2*label.PADDING)
iconSize := float64(d2target.MAX_ICON_SIZE + iconPadding)
if !maxIconSize {
iconSize = float64(d2target.GetIconSize(obj.Box, position.String())) + iconPadding
}
switch position {
case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight:
margin.Top = math.Max(margin.Top, iconSize)

View file

@ -334,7 +334,7 @@ func (obj *Object) GetMargin() geo.Spacing {
}
}
if obj.Icon != nil && obj.IconPosition != nil && obj.Shape.Value != d2target.ShapeImage {
if obj.HasIcon() && obj.IconPosition != nil {
position := label.FromString(*obj.IconPosition)
iconSize := float64(d2target.MAX_ICON_SIZE + label.PADDING)
@ -364,7 +364,11 @@ func (obj *Object) ToShape() shape.Shape {
dslShape := strings.ToLower(obj.Shape.Value)
shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[dslShape]
contentBox := geo.NewBox(tl, obj.Width, obj.Height)
return shape.NewShape(shapeType, contentBox)
s := shape.NewShape(shapeType, contentBox)
if shapeType == shape.CLOUD_TYPE && obj.ContentAspectRatio != nil {
s.SetInnerBoxAspectRatio(*obj.ContentAspectRatio)
}
return s
}
func (obj *Object) GetLabelTopLeft() *geo.Point {
@ -413,7 +417,7 @@ func (edge *Edge) TraceToShape(points []*geo.Point, startIndex, endIndex int) (n
startingSegment := geo.Segment{Start: points[startIndex+1], End: points[startIndex]}
// if an edge runs into an outside label, stop the edge at the label instead
overlapsOutsideLabel := false
var overlapsOutsideLabel, overlapsOutsideIcon bool
if edge.Src.HasLabel() {
// assumes LabelPosition, LabelWidth, LabelHeight are all set if there is a label
labelPosition := label.FromString(*edge.Src.LabelPosition)
@ -449,7 +453,38 @@ func (edge *Edge) TraceToShape(points []*geo.Point, startIndex, endIndex int) (n
}
}
}
if !overlapsOutsideLabel {
if !overlapsOutsideLabel && edge.Src.HasIcon() {
// assumes IconPosition is set if there is an Icon
iconPosition := label.FromString(*edge.Src.IconPosition)
if iconPosition.IsOutside() {
iconWidth := float64(d2target.MAX_ICON_SIZE)
iconHeight := float64(d2target.MAX_ICON_SIZE)
iconTL := iconPosition.GetPointOnBox(edge.Src.Box, label.PADDING, iconWidth, iconHeight)
iconBox := geo.NewBox(iconTL, iconWidth, iconHeight)
for iconBox.Contains(startingSegment.End) && startIndex+1 > endIndex {
startingSegment.Start = startingSegment.End
startingSegment.End = points[startIndex+2]
startIndex++
}
if intersections := iconBox.Intersections(startingSegment); len(intersections) > 0 {
overlapsOutsideIcon = true
p := intersections[0]
if len(intersections) > 1 {
p = findOuterIntersection(iconPosition, intersections)
}
// move starting segment to icon intersection point
points[startIndex] = p
startingSegment.End = p
// if the segment becomes too short, just merge it with the next segment
if startIndex+1 < endIndex && startingSegment.Length() < MIN_SEGMENT_LEN {
points[startIndex+1] = points[startIndex]
startIndex++
}
}
}
}
if !overlapsOutsideLabel && !overlapsOutsideIcon {
if intersections := edge.Src.Intersections(startingSegment); len(intersections) > 0 {
// move starting segment to intersection point
points[startIndex] = intersections[0]
@ -465,6 +500,7 @@ func (edge *Edge) TraceToShape(points []*geo.Point, startIndex, endIndex int) (n
}
endingSegment := geo.Segment{Start: points[endIndex-1], End: points[endIndex]}
overlapsOutsideLabel = false
overlapsOutsideIcon = false
if edge.Dst.HasLabel() {
// assumes LabelPosition, LabelWidth, LabelHeight are all set if there is a label
labelPosition := label.FromString(*edge.Dst.LabelPosition)
@ -499,7 +535,39 @@ func (edge *Edge) TraceToShape(points []*geo.Point, startIndex, endIndex int) (n
}
}
}
if !overlapsOutsideLabel {
if !overlapsOutsideLabel && edge.Dst.HasIcon() {
// assumes IconPosition is set if there is an Icon
iconPosition := label.FromString(*edge.Dst.IconPosition)
if iconPosition.IsOutside() {
iconSize := d2target.GetIconSize(edge.Dst.Box, iconPosition.String())
iconWidth := float64(iconSize)
iconHeight := float64(iconSize)
labelTL := iconPosition.GetPointOnBox(edge.Dst.Box, label.PADDING, iconWidth, iconHeight)
iconBox := geo.NewBox(labelTL, iconWidth, iconHeight)
for iconBox.Contains(endingSegment.Start) && endIndex-1 > startIndex {
endingSegment.End = endingSegment.Start
endingSegment.Start = points[endIndex-2]
endIndex--
}
if intersections := iconBox.Intersections(endingSegment); len(intersections) > 0 {
overlapsOutsideIcon = true
p := intersections[0]
if len(intersections) > 1 {
p = findOuterIntersection(iconPosition, intersections)
}
// move ending segment to icon intersection point
points[endIndex] = p
endingSegment.End = p
// if the segment becomes too short, just merge it with the previous segment
if endIndex-1 > startIndex && endingSegment.Length() < MIN_SEGMENT_LEN {
points[endIndex-1] = points[endIndex]
endIndex--
}
}
}
}
if !overlapsOutsideLabel && !overlapsOutsideIcon {
if intersections := edge.Dst.Intersections(endingSegment); len(intersections) > 0 {
// move ending segment to intersection point
points[endIndex] = intersections[0]

View file

@ -169,7 +169,7 @@ func (c *compiler) validateConfigs(configs *Field) {
for _, f := range configs.Map().Fields {
var val string
if f.Primary() == nil {
if f.Name != "theme-colors" {
if f.Name != "theme-overrides" && f.Name != "dark-theme-overrides" {
c.errorf(f.LastRef().AST(), `"%s" needs a value`, f.Name)
continue
}
@ -184,7 +184,7 @@ func (c *compiler) validateConfigs(configs *Field) {
c.errorf(f.LastRef().AST(), `expected a boolean for "%s", got "%s"`, f.Name, val)
continue
}
case "theme-colors":
case "theme-overrides", "dark-theme-overrides":
if f.Map() == nil {
c.errorf(f.LastRef().AST(), `"%s" needs a map`, f.Name)
continue
@ -394,6 +394,9 @@ func (c *compiler) ampersandFilterMap(dst *Map, ast, scopeAST *d2ast.Map) bool {
ScopeAST: scopeAST,
})
if !ok {
if len(c.mapRefContextStack) == 0 {
return false
}
// Unapply glob if appropriate.
gctx := c.getGlobContext(c.mapRefContextStack[len(c.mapRefContextStack)-1])
if gctx == nil {
@ -416,8 +419,10 @@ func (c *compiler) ampersandFilterMap(dst *Map, ast, scopeAST *d2ast.Map) bool {
func (c *compiler) compileMap(dst *Map, ast, scopeAST *d2ast.Map) {
var globs []*globContext
if len(c.globContextStack) > 0 {
previousGlobs := c.globContextStack[len(c.globContextStack)-1]
if NodeBoardKind(dst) == BoardLayer {
previousGlobs := c.globContexts()
// A root layer with existing glob context stack implies it's an import
// In which case, the previous globs should be inherited (the else block)
if NodeBoardKind(dst) == BoardLayer && !dst.Root() {
for _, g := range previousGlobs {
if g.refctx.Key.HasTripleGlob() {
globs = append(globs, g.prefixed(dst))

View file

@ -233,6 +233,18 @@ classes: {
TestCompile/filters/errors/bad-syntax.d2:9:1: unexpected map termination character } in file map`)
},
},
{
name: "outside-glob",
run: func(t testing.TB) {
_, err := compile(t, `jacob.style: {
fill: red
multiple: true
}
&a
`)
assert.ErrorString(t, err, `TestCompile/filters/errors/outside-glob.d2:5:1: glob filters cannot be used outside globs`)
},
},
{
name: "no-glob",
run: func(t testing.TB) {

View file

@ -184,6 +184,33 @@ label: meow`,
assertQuery(t, m, 0, 0, 1, "hi")
},
},
{
name: "pattern-value",
run: func(t testing.TB) {
_, err := compileFS(t, "index.d2", map[string]string{
"index.d2": `userWebsite
userMobile
user*: @x
`,
"x.d2": `shape: person
label: meow`,
})
assert.Success(t, err)
},
},
{
name: "merge-arrays",
run: func(t testing.TB) {
_, err := compileFS(t, "index.d2", map[string]string{
"index.d2": `x.class: [a]
...@d
`,
"d.d2": `x.class: [b]`,
})
assert.Success(t, err)
},
},
}
runa(t, tca)

View file

@ -30,7 +30,7 @@ func OverlayField(bf, of *Field) {
if bf.Map() != nil && of.Map() != nil {
OverlayMap(bf.Map(), of.Map())
} else {
bf.Composite = of.Composite.Copy(bf).(*Map)
bf.Composite = of.Composite.Copy(bf).(Composite)
}
}

View file

@ -554,6 +554,8 @@ func positionLabelsIcons(obj *d2graph.Object) {
obj.LabelPosition = go2.Pointer(label.OutsideTopRight.String())
return
}
} else if obj.SQLTable != nil || obj.Class != nil || obj.Language != "" {
obj.IconPosition = go2.Pointer(label.OutsideTopLeft.String())
} else {
obj.IconPosition = go2.Pointer(label.InsideMiddleCenter.String())
}
@ -900,14 +902,27 @@ func shiftReachableDown(g *d2graph.Graph, obj *d2graph.Object, start, distance f
}
}
queue(e.Dst)
first := e.Route[0]
startIndex := 0
_, wasShifted := shifted[curr]
if isHorizontal {
for _, p := range e.Route {
if wasShifted && first.X < curr.TopLeft.X && first.X < start {
first.X += distance
startIndex++
}
for i := startIndex; i < len(e.Route); i++ {
p := e.Route[i]
if start <= p.X {
p.X += distance
}
}
} else {
for _, p := range e.Route {
if wasShifted && first.Y < curr.TopLeft.Y && first.Y < start {
first.Y += distance
startIndex++
}
for i := startIndex; i < len(e.Route); i++ {
p := e.Route[i]
if start <= p.Y {
p.Y += distance
}
@ -928,14 +943,27 @@ func shiftReachableDown(g *d2graph.Graph, obj *d2graph.Object, start, distance f
}
}
queue(e.Src)
last := e.Route[len(e.Route)-1]
endIndex := len(e.Route)
_, wasShifted := shifted[curr]
if isHorizontal {
for _, p := range e.Route {
if wasShifted && last.X < curr.TopLeft.X && last.X < start {
last.X += distance
endIndex--
}
for i := 0; i < endIndex; i++ {
p := e.Route[i]
if start <= p.X {
p.X += distance
}
}
} else {
for _, p := range e.Route {
if wasShifted && last.Y < curr.TopLeft.Y && last.Y < start {
last.Y += distance
endIndex--
}
for i := 0; i < endIndex; i++ {
p := e.Route[i]
if start <= p.Y {
p.Y += distance
}
@ -1349,7 +1377,7 @@ func fitPadding(obj *d2graph.Object) {
}
}
}
if obj.Icon != nil && shapeType != shape.IMAGE_TYPE && obj.IconPosition != nil {
if obj.HasIcon() && obj.IconPosition != nil {
iconPosition = label.FromString(*obj.IconPosition)
switch iconPosition {
case label.InsideTopLeft, label.InsideTopCenter, label.InsideTopRight,
@ -1384,7 +1412,7 @@ func fitPadding(obj *d2graph.Object) {
innerBoxes = append(innerBoxes, *childLabelBox)
}
}
if child.Icon != nil && child.Shape.Value != d2target.ShapeImage && child.IconPosition != nil {
if child.HasIcon() && child.IconPosition != nil {
childIconPosition = label.FromString(*child.IconPosition)
if childIconPosition.IsOutside() {
childIconTL := child.GetIconTopLeft()

View file

@ -218,6 +218,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
positionLabelsIcons(obj)
}
adjustments := make(map[*d2graph.Object]geo.Spacing)
elkNodes := make(map[*d2graph.Object]*ELKNode)
elkEdges := make(map[*d2graph.Edge]*ELKEdge)
@ -256,7 +257,15 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
}
}
width, height := adjustDimensions(obj)
if obj.HasLabel() && obj.HasIcon() {
// this gives shapes extra height for their label if they also have an icon
obj.Height += float64(obj.LabelDimensions.Height + label.PADDING)
}
margin, _ := obj.SpacingOpt(label.PADDING, label.PADDING, false)
width := margin.Left + obj.Width + margin.Right
height := margin.Top + obj.Height + margin.Bottom
adjustments[obj] = margin
n := &ELKNode{
ID: obj.AbsID(),
@ -348,41 +357,6 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
elkNodes[obj] = n
})
// adjust parent padding for children with outside positioned icons
for _, obj := range g.Objects {
if !obj.IsContainer() {
continue
}
var hasTop, hasBottom bool
for _, child := range obj.ChildrenArray {
if child.Shape.Value == d2target.ShapeImage || child.IconPosition == nil {
continue
}
switch label.FromString(*child.IconPosition) {
case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight:
hasTop = true
case label.OutsideBottomLeft, label.OutsideBottomCenter, label.OutsideBottomRight:
hasBottom = true
}
if hasTop && hasBottom {
break
}
}
if hasTop || hasBottom {
padding := parsePadding(elkNodes[obj].LayoutOptions.Padding)
if hasTop {
padding.top = go2.Max(padding.top, d2target.MAX_ICON_SIZE+2*label.PADDING)
}
if hasBottom {
padding.bottom = go2.Max(padding.bottom, d2target.MAX_ICON_SIZE+2*label.PADDING)
}
elkNodes[obj].LayoutOptions.Padding = padding.String()
}
}
var srcSide, dstSide PortSide
switch elkGraph.LayoutOptions.Direction {
case Up:
@ -571,8 +545,73 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
edge.Route = points
}
objEdges := make(map[*d2graph.Object][]*d2graph.Edge)
for _, e := range g.Edges {
objEdges[e.Src] = append(objEdges[e.Src], e)
if e.Dst != e.Src {
objEdges[e.Dst] = append(objEdges[e.Dst], e)
}
}
for _, obj := range g.Objects {
cleanupAdjustment(obj)
if margin, has := adjustments[obj]; has {
edges := objEdges[obj]
// also move edges with the shrinking sides
if margin.Left > 0 {
for _, e := range edges {
l := len(e.Route)
if e.Src == obj && e.Route[0].X == obj.TopLeft.X {
e.Route[0].X += margin.Left
}
if e.Dst == obj && e.Route[l-1].X == obj.TopLeft.X {
e.Route[l-1].X += margin.Left
}
}
obj.TopLeft.X += margin.Left
obj.ShiftDescendants(margin.Left/2, 0)
obj.Width -= margin.Left
}
if margin.Right > 0 {
for _, e := range edges {
l := len(e.Route)
if e.Src == obj && e.Route[0].X == obj.TopLeft.X+obj.Width {
e.Route[0].X -= margin.Right
}
if e.Dst == obj && e.Route[l-1].X == obj.TopLeft.X+obj.Width {
e.Route[l-1].X -= margin.Right
}
}
obj.ShiftDescendants(-margin.Right/2, 0)
obj.Width -= margin.Right
}
if margin.Top > 0 {
for _, e := range edges {
l := len(e.Route)
if e.Src == obj && e.Route[0].Y == obj.TopLeft.Y {
e.Route[0].Y += margin.Top
}
if e.Dst == obj && e.Route[l-1].Y == obj.TopLeft.Y {
e.Route[l-1].Y += margin.Top
}
}
obj.TopLeft.Y += margin.Top
obj.ShiftDescendants(0, margin.Top/2)
obj.Height -= margin.Top
}
if margin.Bottom > 0 {
for _, e := range edges {
l := len(e.Route)
if e.Src == obj && e.Route[0].Y == obj.TopLeft.Y+obj.Height {
e.Route[0].Y -= margin.Bottom
}
if e.Dst == obj && e.Route[l-1].Y == obj.TopLeft.Y+obj.Height {
e.Route[l-1].Y -= margin.Bottom
}
}
obj.ShiftDescendants(0, -margin.Bottom/2)
obj.Height -= margin.Bottom
}
}
}
for _, edge := range g.Edges {
@ -1015,7 +1054,7 @@ func adjustPadding(obj *d2graph.Object, width, height float64, padding shapePadd
extraRight = labelWidth
}
}
if obj.Icon != nil && obj.Shape.Value != d2target.ShapeImage && obj.IconPosition != nil {
if obj.HasIcon() && obj.IconPosition != nil {
iconSize := d2target.MAX_ICON_SIZE + 2*label.PADDING
switch label.FromString(*obj.IconPosition) {
case label.InsideTopLeft, label.InsideTopCenter, label.InsideTopRight:
@ -1085,120 +1124,6 @@ func adjustPadding(obj *d2graph.Object, width, height float64, padding shapePadd
return padding
}
func adjustDimensions(obj *d2graph.Object) (width, height float64) {
width = obj.Width
height = obj.Height
// reserve spacing for labels
if obj.HasLabel() {
var position label.Position
if obj.LabelPosition != nil {
position = label.FromString(*obj.LabelPosition)
} else if len(obj.ChildrenArray) == 0 && obj.HasOutsideBottomLabel() {
position = label.OutsideBottomCenter
}
if position.IsShapePosition() {
switch position {
case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom,
label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom:
width += float64(obj.LabelDimensions.Width) + label.PADDING
default:
// TODO labelWidth+2*label.PADDING
width = go2.Max(width, float64(obj.LabelDimensions.Width))
}
}
// special handling
if obj.HasOutsideBottomLabel() || obj.Icon != nil {
height += float64(obj.LabelDimensions.Height) + label.PADDING
}
}
if obj.Icon != nil && obj.Shape.Value != d2target.ShapeImage {
var position label.Position
if obj.IconPosition != nil {
position = label.FromString(*obj.IconPosition)
}
if position.IsShapePosition() {
switch position {
case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom,
label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom:
width += d2target.MAX_ICON_SIZE + label.PADDING
default:
width = go2.Max(width, d2target.MAX_ICON_SIZE+2*label.PADDING)
}
}
}
// reserve extra space for 3d/multiple by providing elk the larger dimensions
dx, dy := obj.GetModifierElementAdjustments()
width += dx
height += dy
return
}
func cleanupAdjustment(obj *d2graph.Object) {
// adjust size and position to account for space reserved for labels
if obj.HasLabel() {
position := label.FromString(*obj.LabelPosition)
if position.IsShapePosition() {
var labelWidth float64
switch position {
case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom,
label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom:
labelWidth = float64(obj.LabelDimensions.Width) + label.PADDING
obj.Width -= labelWidth
}
switch position {
case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom:
obj.TopLeft.X += labelWidth
obj.ShiftDescendants(labelWidth/2, 0)
case label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom:
obj.ShiftDescendants(-labelWidth/2, 0)
}
}
}
if obj.Icon != nil && obj.Shape.Value != d2target.ShapeImage {
position := label.FromString(*obj.IconPosition)
if position.IsShapePosition() {
var iconWidth float64
switch position {
case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom,
label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom:
iconWidth = d2target.MAX_ICON_SIZE + label.PADDING
obj.Width -= iconWidth
}
switch position {
case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom:
obj.TopLeft.X += iconWidth
obj.ShiftDescendants(iconWidth/2, 0)
case label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom:
obj.ShiftDescendants(-iconWidth/2, 0)
}
}
}
// special handling to start/end connections below label
if obj.HasOutsideBottomLabel() {
obj.Height -= float64(obj.LabelDimensions.Height) + label.PADDING
}
// remove the extra width/height we added for 3d/multiple after all objects/connections are placed
// and shift the shapes down accordingly
dx, dy := obj.GetModifierElementAdjustments()
if dx != 0 || dy != 0 {
obj.TopLeft.Y += dy
obj.ShiftDescendants(0, dy)
if !obj.IsContainer() {
obj.Width -= dx
obj.Height -= dy
}
}
}
func positionLabelsIcons(obj *d2graph.Object) {
if obj.Icon != nil && obj.IconPosition == nil {
if len(obj.ChildrenArray) > 0 {
@ -1207,6 +1132,8 @@ func positionLabelsIcons(obj *d2graph.Object) {
obj.LabelPosition = go2.Pointer(label.InsideTopRight.String())
return
}
} else if obj.SQLTable != nil || obj.Class != nil || obj.Language != "" {
obj.IconPosition = go2.Pointer(label.OutsideTopLeft.String())
} else {
obj.IconPosition = go2.Pointer(label.InsideMiddleCenter.String())
}

View file

@ -5,7 +5,6 @@ import (
"context"
"fmt"
"math"
"strconv"
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2target"
@ -69,7 +68,6 @@ func Layout(ctx context.Context, g *d2graph.Graph) error {
labelHeight = float64(obj.LabelDimensions.Height) + 2*label.PADDING
}
var dx, dy float64
if labelWidth > 0 {
switch labelPosition {
case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight,
@ -112,67 +110,33 @@ func Layout(ctx context.Context, g *d2graph.Graph) error {
}
}
overflowTop := padding.Top - float64(verticalPadding)
if overflowTop > 0 {
contentHeight += overflowTop
dy += overflowTop
}
overflowBottom := padding.Bottom - float64(verticalPadding)
if overflowBottom > 0 {
contentHeight += overflowBottom
}
overflowLeft := padding.Left - float64(horizontalPadding)
if overflowLeft > 0 {
contentWidth += overflowLeft
dx += overflowLeft
}
overflowRight := padding.Right - float64(horizontalPadding)
if overflowRight > 0 {
contentWidth += overflowRight
}
padding.Top = math.Max(padding.Top, float64(verticalPadding))
padding.Bottom = math.Max(padding.Bottom, float64(verticalPadding))
padding.Left = math.Max(padding.Left, float64(horizontalPadding))
padding.Right = math.Max(padding.Right, float64(horizontalPadding))
// manually handle desiredWidth/Height so we can center the grid
var desiredWidth, desiredHeight int
var originalWidthAttr, originalHeightAttr *d2graph.Scalar
if obj.WidthAttr != nil {
desiredWidth, _ = strconv.Atoi(obj.WidthAttr.Value)
// SizeToContent without desired width
originalWidthAttr = obj.WidthAttr
obj.WidthAttr = nil
}
if obj.HeightAttr != nil {
desiredHeight, _ = strconv.Atoi(obj.HeightAttr.Value)
originalHeightAttr = obj.HeightAttr
obj.HeightAttr = nil
}
// size shape according to grid
obj.SizeToContent(contentWidth, contentHeight, float64(2*horizontalPadding), float64(2*verticalPadding))
if originalWidthAttr != nil {
obj.WidthAttr = originalWidthAttr
}
if originalHeightAttr != nil {
obj.HeightAttr = originalHeightAttr
}
if desiredWidth > 0 {
ddx := float64(desiredWidth) - obj.Width
if ddx > 0 {
dx += ddx / 2
obj.Width = float64(desiredWidth)
}
}
if desiredHeight > 0 {
ddy := float64(desiredHeight) - obj.Height
if ddy > 0 {
dy += ddy / 2
obj.Height = float64(desiredHeight)
}
}
totalWidth := padding.Left + contentWidth + padding.Right
totalHeight := padding.Top + contentHeight + padding.Bottom
obj.SizeToContent(totalWidth, totalHeight, 0, 0)
// compute where the grid should be placed inside shape
innerBox := obj.ToShape().GetInnerBox()
dx = innerBox.TopLeft.X + dx
dy = innerBox.TopLeft.Y + dy
s := obj.ToShape()
innerTL := s.GetInsidePlacement(totalWidth, totalHeight, 0, 0)
// depending on the shape innerBox may be larger than totalWidth, totalHeight
// if this is the case, we want to center the cells within the larger innerBox
innerBox := s.GetInnerBox()
var resizeDx, resizeDy float64
if innerBox.Width > totalWidth {
resizeDx = (innerBox.Width - totalWidth) / 2
}
if innerBox.Height > totalHeight {
resizeDy = (innerBox.Height - totalHeight) / 2
}
// move from horizontalPadding,verticalPadding to innerTL.X+padding.Left, innerTL.Y+padding.Top
// and if innerBox is larger than content dimensions, adjust to center within innerBox
dx := -float64(horizontalPadding) + innerTL.X + padding.Left + resizeDx
dy := -float64(verticalPadding) + innerTL.Y + padding.Top + resizeDy
if dx != 0 || dy != 0 {
gd.shift(dx, dy)
}

View file

@ -76,13 +76,14 @@ func SaveOrder(g *d2graph.Graph) (restoreOrder func()) {
}
}
func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, coreLayout d2graph.LayoutGraph) error {
func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, coreLayout d2graph.LayoutGraph, edgeRouter d2graph.RouteEdges) error {
g.Root.Box = &geo.Box{}
// Before we can layout these nodes, we need to handle all nested diagrams first.
extracted := make(map[string]*d2graph.Graph)
var extractedOrder []string
var extractedEdges []*d2graph.Edge
var extractedEdgeIDs []edgeIDs
var constantNears []*d2graph.Graph
restoreOrder := SaveOrder(g)
@ -114,11 +115,11 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
// │ │ │ │ └──┘ └──┘ │ │ │ │ │ │
// │ └────┘ └───────────────┘ │ │ └────┘ │
// └───────────────────────────────┘ └───────────────────────────────┘
nestedGraph, externalEdges := ExtractSubgraph(curr, true)
nestedGraph, externalEdges, externalEdgeIDs := ExtractSubgraph(curr, true)
// Then we layout curr as a nested graph and re-inject it
id := curr.AbsID()
err := LayoutNested(ctx, nestedGraph, GraphInfo{}, coreLayout)
err := LayoutNested(ctx, nestedGraph, GraphInfo{}, coreLayout, edgeRouter)
if err != nil {
return err
}
@ -142,13 +143,13 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
if err != nil {
return err
}
for _, e := range externalEdges {
src, err := lookup(e.Src.AbsID())
for i, e := range externalEdges {
src, err := lookup(externalEdgeIDs[i].srcID)
if err != nil {
return err
}
e.Src = src
dst, err := lookup(e.Dst.AbsID())
dst, err := lookup(externalEdgeIDs[i].dstID)
if err != nil {
return err
}
@ -182,8 +183,9 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
// │ │ │ │ └──┘ └──┘ │ │ │ │ │ │ │ │
// │ └────┘ └───────────────┘ │ │ └────┘ └───────────────┘ │
// └───────────────────────────────┘ └───────────────────────────────┘
nestedGraph, externalEdges = ExtractSubgraph(curr, false)
nestedGraph, externalEdges, externalEdgeIDs = ExtractSubgraph(curr, false)
extractedEdges = append(extractedEdges, externalEdges...)
extractedEdgeIDs = append(extractedEdgeIDs, externalEdgeIDs...)
extracted[id] = nestedGraph
extractedOrder = append(extractedOrder, id)
@ -197,8 +199,9 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
}
// There is a nested diagram here, so extract its contents and process in the same way
nestedGraph, externalEdges := ExtractSubgraph(curr, gi.IsConstantNear)
nestedGraph, externalEdges, externalEdgeIDs := ExtractSubgraph(curr, gi.IsConstantNear)
extractedEdges = append(extractedEdges, externalEdges...)
extractedEdgeIDs = append(extractedEdgeIDs, externalEdgeIDs...)
log.Info(ctx, "layout nested", slog.F("level", curr.Level()), slog.F("child", curr.AbsID()), slog.F("gi", gi))
nestedInfo := gi
@ -209,7 +212,7 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
curr.NearKey = nil
}
err := LayoutNested(ctx, nestedGraph, nestedInfo, coreLayout)
err := LayoutNested(ctx, nestedGraph, nestedInfo, coreLayout, edgeRouter)
if err != nil {
return err
}
@ -291,6 +294,7 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
PositionNested(obj, nestedGraph)
}
if len(extractedEdges) > 0 {
// update map with injected objects
for _, o := range g.Objects {
idToObj[o.AbsID()] = o
@ -298,29 +302,55 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
// Restore cross-graph edges and route them
g.Edges = append(g.Edges, extractedEdges...)
for _, e := range extractedEdges {
for i, e := range extractedEdges {
ids := extractedEdgeIDs[i]
// update object references
src, exists := idToObj[e.Src.AbsID()]
src, exists := idToObj[ids.srcID]
if !exists {
return fmt.Errorf("could not find object %#v after layout", e.Src.AbsID())
return fmt.Errorf("could not find object %#v after layout", ids.srcID)
}
e.Src = src
dst, exists := idToObj[e.Dst.AbsID()]
dst, exists := idToObj[ids.dstID]
if !exists {
return fmt.Errorf("could not find object %#v after layout", e.Dst.AbsID())
return fmt.Errorf("could not find object %#v after layout", ids.dstID)
}
e.Dst = dst
}
// simple straight line edge routing when going across graphs
err = edgeRouter(ctx, g, extractedEdges)
if err != nil {
return err
}
// need to update pointers if plugin performs edge routing
for i, e := range extractedEdges {
ids := extractedEdgeIDs[i]
src, exists := idToObj[ids.srcID]
if !exists {
return fmt.Errorf("could not find object %#v after routing", ids.srcID)
}
e.Src = src
dst, exists := idToObj[ids.dstID]
if !exists {
return fmt.Errorf("could not find object %#v after routing", ids.dstID)
}
e.Dst = dst
}
}
log.Debug(ctx, "done", slog.F("rootlevel", g.RootLevel), slog.F("shapes", g.PrintString()))
return err
}
func DefaultRouter(ctx context.Context, graph *d2graph.Graph, edges []*d2graph.Edge) error {
for _, e := range edges {
// TODO replace simple straight line edge routing
e.Route = []*geo.Point{e.Src.Center(), e.Dst.Center()}
e.TraceToShape(e.Route, 0, 1)
if e.Label.Value != "" {
e.LabelPosition = go2.Pointer(label.InsideMiddleCenter.String())
}
}
log.Debug(ctx, "done", slog.F("rootlevel", g.RootLevel), slog.F("shapes", g.PrintString()))
return err
return nil
}
func NestedGraphInfo(obj *d2graph.Object) (gi GraphInfo) {
@ -335,7 +365,11 @@ func NestedGraphInfo(obj *d2graph.Object) (gi GraphInfo) {
return gi
}
func ExtractSubgraph(container *d2graph.Object, includeSelf bool) (nestedGraph *d2graph.Graph, externalEdges []*d2graph.Edge) {
type edgeIDs struct {
srcID, dstID string
}
func ExtractSubgraph(container *d2graph.Object, includeSelf bool) (nestedGraph *d2graph.Graph, externalEdges []*d2graph.Edge, externalEdgeIDs []edgeIDs) {
// includeSelf: when we have a constant near or a grid cell that is a container,
// we want to include itself in the nested graph, not just its descendants,
nestedGraph = d2graph.NewGraph()
@ -374,6 +408,11 @@ func ExtractSubgraph(container *d2graph.Object, includeSelf bool) (nestedGraph *
nestedGraph.Edges = append(nestedGraph.Edges, edge)
} else if srcIsNested || dstIsNested {
externalEdges = append(externalEdges, edge)
// we need these AbsIDs when reconnecting since parent references may become stale
externalEdgeIDs = append(externalEdgeIDs, edgeIDs{
srcID: edge.Src.AbsID(),
dstID: edge.Dst.AbsID(),
})
} else {
remainingEdges = append(remainingEdges, edge)
}
@ -421,7 +460,7 @@ func ExtractSubgraph(container *d2graph.Object, includeSelf bool) (nestedGraph *
container.ChildrenArray = nil
}
return nestedGraph, externalEdges
return nestedGraph, externalEdges, externalEdgeIDs
}
func InjectNested(container *d2graph.Object, nestedGraph *d2graph.Graph, isRoot bool) {

View file

@ -7,11 +7,13 @@ import (
"os"
"strings"
"oss.terrastruct.com/d2/d2ast"
"oss.terrastruct.com/d2/d2compiler"
"oss.terrastruct.com/d2/d2exporter"
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2layouts"
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
"oss.terrastruct.com/d2/d2parser"
"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2renderers/d2svg"
"oss.terrastruct.com/d2/d2target"
@ -25,6 +27,7 @@ type CompileOptions struct {
FS fs.FS
MeasuredTexts []*d2target.MText
Ruler *textmeasure.Ruler
RouterResolver func(engine string) (d2graph.RouteEdges, error)
LayoutResolver func(engine string) (d2graph.LayoutGraph, error)
Layout *string
@ -39,6 +42,17 @@ type CompileOptions struct {
InputPath string
}
func Parse(ctx context.Context, input string, compileOpts *CompileOptions) (*d2ast.Map, error) {
if compileOpts == nil {
compileOpts = &CompileOptions{}
}
ast, err := d2parser.Parse(compileOpts.InputPath, strings.NewReader(input), &d2parser.ParseOptions{
UTF16Pos: compileOpts.UTF16Pos,
})
return ast, err
}
func Compile(ctx context.Context, input string, compileOpts *CompileOptions, renderOpts *d2svg.RenderOpts) (*d2target.Diagram, *d2graph.Graph, error) {
if compileOpts == nil {
compileOpts = &CompileOptions{}
@ -81,9 +95,13 @@ func compile(ctx context.Context, g *d2graph.Graph, compileOpts *CompileOptions,
if err != nil {
return nil, err
}
edgeRouter, err := getEdgeRouter(compileOpts)
if err != nil {
return nil, err
}
graphInfo := d2layouts.NestedGraphInfo(g.Root)
err = d2layouts.LayoutNested(ctx, g, graphInfo, coreLayout)
err = d2layouts.LayoutNested(ctx, g, graphInfo, coreLayout, edgeRouter)
if err != nil {
return nil, err
}
@ -131,6 +149,19 @@ func getLayout(opts *CompileOptions) (d2graph.LayoutGraph, error) {
}
}
func getEdgeRouter(opts *CompileOptions) (d2graph.RouteEdges, error) {
if opts.Layout != nil && opts.RouterResolver != nil {
router, err := opts.RouterResolver(*opts.Layout)
if err != nil {
return nil, err
}
if router != nil {
return router, nil
}
}
return d2layouts.DefaultRouter, nil
}
// applyConfigs applies the configs read from D2 and applies it to passed in opts
// It will only write to opt fields that are nil, as passed-in opts have precedence
func applyConfigs(config *d2target.Config, compileOpts *CompileOptions, renderOpts *d2svg.RenderOpts) {
@ -157,6 +188,8 @@ func applyConfigs(config *d2target.Config, compileOpts *CompileOptions, renderOp
if renderOpts.Center == nil {
renderOpts.Center = config.Center
}
renderOpts.ThemeOverrides = config.ThemeOverrides
renderOpts.DarkThemeOverrides = config.DarkThemeOverrides
}
func applyDefaults(compileOpts *CompileOptions, renderOpts *d2svg.RenderOpts) {

View file

@ -80,6 +80,11 @@ type Plugin interface {
PostProcess(context.Context, []byte) ([]byte, error)
}
type RoutingPlugin interface {
// RouteEdges runs the plugin's edge routing algorithm for the given edges in the input graph
RouteEdges(context.Context, *d2graph.Graph, []*d2graph.Edge) error
}
// PluginInfo is the current info information of a plugin.
// note: The two fields Type and Path are not set by the plugin
// itself but only in ListPlugins.

View file

@ -21,6 +21,9 @@ const TOP_LEFT PluginFeature = "top_left"
// When this is true, containers can have connections to descendants
const DESCENDANT_EDGES PluginFeature = "descendant_edges"
// When this is true, the plugin also implements RoutingPlugin interface to route edges
const ROUTES_EDGES PluginFeature = "routes_edges"
func FeatureSupportCheck(info *PluginInfo, g *d2graph.Graph) error {
// Older version of plugin. Skip checking.
if info.Features == nil {

View file

@ -76,7 +76,7 @@ func Wrap(rootDiagram *d2target.Diagram, svgs [][]byte, renderOpts d2svg.RenderO
d2svg.EmbedFonts(buf, diagramHash, svgsStr, rootDiagram.FontFamily, rootDiagram.GetNestedCorpus())
themeStylesheet, err := d2svg.ThemeCSS(diagramHash, renderOpts.ThemeID, renderOpts.DarkThemeID)
themeStylesheet, err := d2svg.ThemeCSS(diagramHash, renderOpts.ThemeID, renderOpts.DarkThemeID, renderOpts.ThemeOverrides, renderOpts.DarkThemeOverrides)
if err != nil {
return nil, err
}

View file

@ -733,6 +733,14 @@ func ArrowheadJS(r *Runner, arrowhead d2target.Arrowhead, stroke string, strokeW
stroke,
stroke,
)
case d2target.UnfilledTriangleArrowhead:
arrowJS = fmt.Sprintf(
`node = rc.polygon(%s, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", seed: 2 })`,
`[[-10, -4], [0, 0], [-10, 4]]`,
strokeWidth,
stroke,
BG_COLOR,
)
case d2target.DiamondArrowhead:
arrowJS = fmt.Sprintf(
`node = rc.polygon(%s, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", seed: 1 })`,

View file

@ -3,7 +3,6 @@ package d2sketch_test
import (
"context"
"encoding/xml"
"io/ioutil"
"os"
"path/filepath"
"strings"
@ -1304,6 +1303,26 @@ a -> b: {
}
`,
},
{
name: "unfilled_triangle",
script: `
direction: right
A <-> B: default {
source-arrowhead.style.filled: false
target-arrowhead.style.filled: false
}
C <-> D: triangle {
source-arrowhead: {
shape: triangle
style.filled: false
}
target-arrowhead: {
shape: triangle
style.filled: false
}
}`,
},
}
runa(t, tcs)
}
@ -1367,7 +1386,7 @@ func run(t *testing.T, tc testCase) {
assert.Success(t, err)
err = os.MkdirAll(dataPath, 0755)
assert.Success(t, err)
err = ioutil.WriteFile(pathGotSVG, svgBytes, 0600)
err = os.WriteFile(pathGotSVG, svgBytes, 0600)
assert.Success(t, err)
defer os.Remove(pathGotSVG)

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 129 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 392 820"><svg id="d2-svg" class="d2-2916329547" width="392" height="820" viewBox="-91 -121 392 820"><rect x="-91.000000" y="-121.000000" width="392.000000" height="820.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 392 820"><svg id="d2-svg" class="d2-2916329547" width="392" height="820" viewBox="-91 -121 392 820"><rect x="-91.000000" y="-121.000000" width="392.000000" height="820.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2916329547 .text {
font-family: "d2-2916329547-font-regular";
}

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 392 820"><svg id="d2-svg" class="d2-2916329547" width="392" height="820" viewBox="-91 -121 392 820"><rect x="-91.000000" y="-121.000000" width="392.000000" height="820.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 392 820"><svg id="d2-svg" class="d2-2916329547" width="392" height="820" viewBox="-91 -121 392 820"><rect x="-91.000000" y="-121.000000" width="392.000000" height="820.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2916329547 .text {
font-family: "d2-2916329547-font-regular";
}

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-3148583989 .text-bold {
font-family: "d2-3148583989-font-bold";
}

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 130 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-3148583989 .text-bold {
font-family: "d2-3148583989-font-bold";
}

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 121 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-327680947 .text-bold {
font-family: "d2-327680947-font-bold";
}

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-327680947 .text-bold {
font-family: "d2-327680947-font-bold";
}

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-914436609 .text {
font-family: "d2-914436609-font-regular";
}

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-914436609 .text {
font-family: "d2-914436609-font-regular";
}

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2730605657 .text-mono {
font-family: "d2-2730605657-font-mono";
}

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1467 386"><svg id="d2-svg" class="d2-206057491" width="1467" height="386" viewBox="-101 -101 1467 386"><rect x="-101.000000" y="-101.000000" width="1467.000000" height="386.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1467 386"><svg id="d2-svg" class="d2-206057491" width="1467" height="386" viewBox="-101 -101 1467 386"><rect x="-101.000000" y="-101.000000" width="1467.000000" height="386.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-206057491 .text {
font-family: "d2-206057491-font-regular";
}

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2730605657 .text-mono {
font-family: "d2-2730605657-font-mono";
}

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2029734873 .text-bold {
font-family: "d2-2029734873-font-bold";
}

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2029734873 .text-bold {
font-family: "d2-2029734873-font-bold";
}

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1740 600"><svg id="d2-svg" class="d2-341527886" width="1740" height="600" viewBox="-101 -101 1740 600"><rect x="-101.000000" y="-101.000000" width="1740.000000" height="600.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1740 600"><svg id="d2-svg" class="d2-341527886" width="1740" height="600" viewBox="-101 -101 1740 600"><rect x="-101.000000" y="-101.000000" width="1740.000000" height="600.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-341527886 .text-bold {
font-family: "d2-341527886-font-bold";
}

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 163 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1740 600"><svg id="d2-svg" class="d2-341527886" width="1740" height="600" viewBox="-101 -101 1740 600"><rect x="-101.000000" y="-101.000000" width="1740.000000" height="600.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1740 600"><svg id="d2-svg" class="d2-341527886" width="1740" height="600" viewBox="-101 -101 1740 600"><rect x="-101.000000" y="-101.000000" width="1740.000000" height="600.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-341527886 .text-bold {
font-family: "d2-341527886-font-bold";
}

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 154 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 398 285"><svg id="d2-svg" class="d2-1379818723" width="398" height="285" viewBox="-101 -115 398 285"><rect x="-101.000000" y="-115.000000" width="398.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 398 285"><svg id="d2-svg" class="d2-1379818723" width="398" height="285" viewBox="-101 -115 398 285"><rect x="-101.000000" y="-115.000000" width="398.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-1379818723 .text-bold {
font-family: "d2-1379818723-font-bold";
}

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 164 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 167 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1052 863"><svg id="d2-svg" class="d2-611371411" width="1052" height="863" viewBox="-61 -1 1052 863"><rect x="-61.000000" y="-1.000000" width="1052.000000" height="863.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1052 863"><svg id="d2-svg" class="d2-611371411" width="1052" height="863" viewBox="-61 -1 1052 863"><rect x="-61.000000" y="-1.000000" width="1052.000000" height="863.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-611371411 .text-mono {
font-family: "d2-611371411-font-mono";
}

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 115 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 922 408"><svg id="d2-svg" class="d2-2864094478" width="922" height="408" viewBox="-91 -141 922 408"><rect x="-91.000000" y="-141.000000" width="922.000000" height="408.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 922 408"><svg id="d2-svg" class="d2-2864094478" width="922" height="408" viewBox="-91 -141 922 408"><rect x="-91.000000" y="-141.000000" width="922.000000" height="408.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2864094478 .text {
font-family: "d2-2864094478-font-regular";
}

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 337 560"><svg id="d2-svg" class="d2-2874225056" width="337" height="560" viewBox="-89 -89 337 560"><rect x="-89.000000" y="-89.000000" width="337.000000" height="560.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 337 560"><svg id="d2-svg" class="d2-2874225056" width="337" height="560" viewBox="-89 -89 337 560"><rect x="-89.000000" y="-89.000000" width="337.000000" height="560.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2874225056 .text-bold {
font-family: "d2-2874225056-font-bold";
}

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 676 434"><svg id="d2-svg" class="d2-2558489054" width="676" height="434" viewBox="-101 -101 676 434"><rect x="-101.000000" y="-101.000000" width="676.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 676 434"><svg id="d2-svg" class="d2-2558489054" width="676" height="434" viewBox="-101 -101 676 434"><rect x="-101.000000" y="-101.000000" width="676.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2558489054 .text-bold {
font-family: "d2-2558489054-font-bold";
}

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-1098532122 .text {
font-family: "d2-1098532122-font-regular";
}

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-1098532122 .text {
font-family: "d2-1098532122-font-regular";
}

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 758 268"><svg id="d2-svg" class="d2-4290168978" width="758" height="268" viewBox="-101 -101 758 268"><rect x="-101.000000" y="-101.000000" width="758.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 758 268"><svg id="d2-svg" class="d2-4290168978" width="758" height="268" viewBox="-101 -101 758 268"><rect x="-101.000000" y="-101.000000" width="758.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-4290168978 .text-bold {
font-family: "d2-4290168978-font-bold";
}

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 516 636"><svg id="d2-svg" class="d2-3736831304" width="516" height="636" viewBox="-78 -122 516 636"><rect x="-78.000000" y="-122.000000" width="516.000000" height="636.000000" rx="0.000000" fill="#947A6D" stroke-width="0" /><rect x="-78.000000" y="-122.000000" width="516.000000" height="636.000000" rx="0.000000" class="paper-overlay" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 516 636"><svg id="d2-svg" class="d2-3736831304" width="516" height="636" viewBox="-78 -122 516 636"><rect x="-78.000000" y="-122.000000" width="516.000000" height="636.000000" rx="0.000000" fill="#947A6D" stroke-width="0" /><rect x="-78.000000" y="-122.000000" width="516.000000" height="636.000000" rx="0.000000" class="paper-overlay" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-3736831304 .text-mono {
font-family: "d2-3736831304-font-mono";
}

Before

Width:  |  Height:  |  Size: 497 KiB

After

Width:  |  Height:  |  Size: 497 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1192 1156"><svg id="d2-svg" class="d2-1077382347" width="1192" height="1156" viewBox="-106 -157 1192 1156"><rect x="-106.000000" y="-157.000000" width="1192.000000" height="1156.000000" rx="0.000000" stroke="LightSteelBlue" fill="honeydew" stroke-width="0" /><rect x="-101.000000" y="-152.000000" width="1182.000000" height="1146.000000" rx="0.000000" stroke="LightSteelBlue" fill="transparent" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1192 1156"><svg id="d2-svg" class="d2-1077382347" width="1192" height="1156" viewBox="-106 -157 1192 1156"><rect x="-106.000000" y="-157.000000" width="1192.000000" height="1156.000000" rx="0.000000" stroke="LightSteelBlue" fill="honeydew" stroke-width="0" /><rect x="-101.000000" y="-152.000000" width="1182.000000" height="1146.000000" rx="0.000000" stroke="LightSteelBlue" fill="transparent" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-1077382347 .text {
font-family: "d2-1077382347-font-regular";
}

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 124 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2504113906 .text {
font-family: "d2-2504113906-font-regular";
}

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2504113906 .text {
font-family: "d2-2504113906-font-regular";
}

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 832 1627"><svg id="d2-svg" class="d2-790545213" width="832" height="1627" viewBox="-92 -101 832 1627"><rect x="-92.000000" y="-101.000000" width="832.000000" height="1627.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 832 1627"><svg id="d2-svg" class="d2-790545213" width="832" height="1627" viewBox="-92 -101 832 1627"><rect x="-92.000000" y="-101.000000" width="832.000000" height="1627.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-790545213 .text-mono {
font-family: "d2-790545213-font-mono";
}

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 113 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-103900560" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-103900560" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-103900560 .text {
font-family: "d2-103900560-font-regular";
}

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 216 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-103900560" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-103900560" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-103900560 .text {
font-family: "d2-103900560-font-regular";
}

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 216 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 70 KiB

View file

@ -12,7 +12,6 @@ import (
"strings"
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2parser"
"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2renderers/d2svg"
"oss.terrastruct.com/d2/d2target"
@ -193,31 +192,6 @@ func Append(diagram *d2target.Diagram, ruler *textmeasure.Ruler, in []byte) []by
return []byte(svg)
}
// transformInternalLink turns
// "root.layers.x.layers.y"
// into
// "root > x > y"
func transformInternalLink(link string) string {
if link == "" || !strings.HasPrefix(link, "root") {
return link
}
mk, err := d2parser.ParseMapKey(link)
if err != nil {
return ""
}
key := d2graph.Key(mk.Key)
if len(key) > 1 {
for i := 1; i < len(key); i += 2 {
key[i] = ">"
}
}
return strings.Join(key, " ")
}
func generateAppendix(diagram *d2target.Diagram, ruler *textmeasure.Ruler, svg string) (string, int, int) {
tl, br := diagram.BoundingBox()
@ -227,7 +201,7 @@ func generateAppendix(diagram *d2target.Diagram, ruler *textmeasure.Ruler, svg s
i := 1
for _, s := range diagram.Shapes {
for _, txt := range []string{s.Tooltip, transformInternalLink(s.Link)} {
for _, txt := range []string{s.Tooltip, s.PrettyLink} {
if txt != "" {
line, w, h := generateLine(i, br.Y+(PAD_TOP*2)+totalHeight, txt, ruler)
i++

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1431 1588"><svg id="d2-svg" class="d2-4070036272" width="1431" height="1588" viewBox="-192 -70 1431 1588"><rect x="-192.000000" y="-70.000000" width="1431" height="1588" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1431 1588"><svg id="d2-svg" class="d2-4070036272" width="1431" height="1588" viewBox="-192 -70 1431 1588"><rect x="-192.000000" y="-70.000000" width="1431" height="1588" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-4070036272 .text {
font-family: "d2-4070036272-font-regular";
}

Before

Width:  |  Height:  |  Size: 677 KiB

After

Width:  |  Height:  |  Size: 677 KiB

View file

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 304 407"><svg id="d2-svg" class="d2-3057089836" width="304" height="407" viewBox="-101 -118 304 407"><rect x="-101.000000" y="-118.000000" width="304" height="407" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 304 407"><svg id="d2-svg" class="d2-1118191387" width="304" height="407" viewBox="-101 -118 304 407"><rect x="-101.000000" y="-118.000000" width="304" height="407" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.appendix-icon {
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
}
.d2-3057089836 .text-bold {
font-family: "d2-3057089836-font-bold";
.d2-1118191387 .text-bold {
font-family: "d2-1118191387-font-bold";
}
@font-face {
font-family: d2-3057089836-font-bold;
font-family: d2-1118191387-font-bold;
src: url("data:application/font-woff;base64,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");
}]]></style><style type="text/css"><![CDATA[.shape {
shape-rendering: geometricPrecision;
@ -21,81 +21,81 @@
opacity: 0.5;
}
.d2-3057089836 .fill-N1{fill:#0A0F25;}
.d2-3057089836 .fill-N2{fill:#676C7E;}
.d2-3057089836 .fill-N3{fill:#9499AB;}
.d2-3057089836 .fill-N4{fill:#CFD2DD;}
.d2-3057089836 .fill-N5{fill:#DEE1EB;}
.d2-3057089836 .fill-N6{fill:#EEF1F8;}
.d2-3057089836 .fill-N7{fill:#FFFFFF;}
.d2-3057089836 .fill-B1{fill:#0D32B2;}
.d2-3057089836 .fill-B2{fill:#0D32B2;}
.d2-3057089836 .fill-B3{fill:#E3E9FD;}
.d2-3057089836 .fill-B4{fill:#E3E9FD;}
.d2-3057089836 .fill-B5{fill:#EDF0FD;}
.d2-3057089836 .fill-B6{fill:#F7F8FE;}
.d2-3057089836 .fill-AA2{fill:#4A6FF3;}
.d2-3057089836 .fill-AA4{fill:#EDF0FD;}
.d2-3057089836 .fill-AA5{fill:#F7F8FE;}
.d2-3057089836 .fill-AB4{fill:#EDF0FD;}
.d2-3057089836 .fill-AB5{fill:#F7F8FE;}
.d2-3057089836 .stroke-N1{stroke:#0A0F25;}
.d2-3057089836 .stroke-N2{stroke:#676C7E;}
.d2-3057089836 .stroke-N3{stroke:#9499AB;}
.d2-3057089836 .stroke-N4{stroke:#CFD2DD;}
.d2-3057089836 .stroke-N5{stroke:#DEE1EB;}
.d2-3057089836 .stroke-N6{stroke:#EEF1F8;}
.d2-3057089836 .stroke-N7{stroke:#FFFFFF;}
.d2-3057089836 .stroke-B1{stroke:#0D32B2;}
.d2-3057089836 .stroke-B2{stroke:#0D32B2;}
.d2-3057089836 .stroke-B3{stroke:#E3E9FD;}
.d2-3057089836 .stroke-B4{stroke:#E3E9FD;}
.d2-3057089836 .stroke-B5{stroke:#EDF0FD;}
.d2-3057089836 .stroke-B6{stroke:#F7F8FE;}
.d2-3057089836 .stroke-AA2{stroke:#4A6FF3;}
.d2-3057089836 .stroke-AA4{stroke:#EDF0FD;}
.d2-3057089836 .stroke-AA5{stroke:#F7F8FE;}
.d2-3057089836 .stroke-AB4{stroke:#EDF0FD;}
.d2-3057089836 .stroke-AB5{stroke:#F7F8FE;}
.d2-3057089836 .background-color-N1{background-color:#0A0F25;}
.d2-3057089836 .background-color-N2{background-color:#676C7E;}
.d2-3057089836 .background-color-N3{background-color:#9499AB;}
.d2-3057089836 .background-color-N4{background-color:#CFD2DD;}
.d2-3057089836 .background-color-N5{background-color:#DEE1EB;}
.d2-3057089836 .background-color-N6{background-color:#EEF1F8;}
.d2-3057089836 .background-color-N7{background-color:#FFFFFF;}
.d2-3057089836 .background-color-B1{background-color:#0D32B2;}
.d2-3057089836 .background-color-B2{background-color:#0D32B2;}
.d2-3057089836 .background-color-B3{background-color:#E3E9FD;}
.d2-3057089836 .background-color-B4{background-color:#E3E9FD;}
.d2-3057089836 .background-color-B5{background-color:#EDF0FD;}
.d2-3057089836 .background-color-B6{background-color:#F7F8FE;}
.d2-3057089836 .background-color-AA2{background-color:#4A6FF3;}
.d2-3057089836 .background-color-AA4{background-color:#EDF0FD;}
.d2-3057089836 .background-color-AA5{background-color:#F7F8FE;}
.d2-3057089836 .background-color-AB4{background-color:#EDF0FD;}
.d2-3057089836 .background-color-AB5{background-color:#F7F8FE;}
.d2-3057089836 .color-N1{color:#0A0F25;}
.d2-3057089836 .color-N2{color:#676C7E;}
.d2-3057089836 .color-N3{color:#9499AB;}
.d2-3057089836 .color-N4{color:#CFD2DD;}
.d2-3057089836 .color-N5{color:#DEE1EB;}
.d2-3057089836 .color-N6{color:#EEF1F8;}
.d2-3057089836 .color-N7{color:#FFFFFF;}
.d2-3057089836 .color-B1{color:#0D32B2;}
.d2-3057089836 .color-B2{color:#0D32B2;}
.d2-3057089836 .color-B3{color:#E3E9FD;}
.d2-3057089836 .color-B4{color:#E3E9FD;}
.d2-3057089836 .color-B5{color:#EDF0FD;}
.d2-3057089836 .color-B6{color:#F7F8FE;}
.d2-3057089836 .color-AA2{color:#4A6FF3;}
.d2-3057089836 .color-AA4{color:#EDF0FD;}
.d2-3057089836 .color-AA5{color:#F7F8FE;}
.d2-3057089836 .color-AB4{color:#EDF0FD;}
.d2-3057089836 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><a href="root.layers.x" xlink:href="root.layers.x"><g id="x"><g class="shape" ><rect x="0.000000" y="0.000000" width="85.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="42.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text></g></a><g transform="translate(69 -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><mask id="d2-3057089836" maskUnits="userSpaceOnUse" x="-101" y="-118" width="304" height="285">
.d2-1118191387 .fill-N1{fill:#0A0F25;}
.d2-1118191387 .fill-N2{fill:#676C7E;}
.d2-1118191387 .fill-N3{fill:#9499AB;}
.d2-1118191387 .fill-N4{fill:#CFD2DD;}
.d2-1118191387 .fill-N5{fill:#DEE1EB;}
.d2-1118191387 .fill-N6{fill:#EEF1F8;}
.d2-1118191387 .fill-N7{fill:#FFFFFF;}
.d2-1118191387 .fill-B1{fill:#0D32B2;}
.d2-1118191387 .fill-B2{fill:#0D32B2;}
.d2-1118191387 .fill-B3{fill:#E3E9FD;}
.d2-1118191387 .fill-B4{fill:#E3E9FD;}
.d2-1118191387 .fill-B5{fill:#EDF0FD;}
.d2-1118191387 .fill-B6{fill:#F7F8FE;}
.d2-1118191387 .fill-AA2{fill:#4A6FF3;}
.d2-1118191387 .fill-AA4{fill:#EDF0FD;}
.d2-1118191387 .fill-AA5{fill:#F7F8FE;}
.d2-1118191387 .fill-AB4{fill:#EDF0FD;}
.d2-1118191387 .fill-AB5{fill:#F7F8FE;}
.d2-1118191387 .stroke-N1{stroke:#0A0F25;}
.d2-1118191387 .stroke-N2{stroke:#676C7E;}
.d2-1118191387 .stroke-N3{stroke:#9499AB;}
.d2-1118191387 .stroke-N4{stroke:#CFD2DD;}
.d2-1118191387 .stroke-N5{stroke:#DEE1EB;}
.d2-1118191387 .stroke-N6{stroke:#EEF1F8;}
.d2-1118191387 .stroke-N7{stroke:#FFFFFF;}
.d2-1118191387 .stroke-B1{stroke:#0D32B2;}
.d2-1118191387 .stroke-B2{stroke:#0D32B2;}
.d2-1118191387 .stroke-B3{stroke:#E3E9FD;}
.d2-1118191387 .stroke-B4{stroke:#E3E9FD;}
.d2-1118191387 .stroke-B5{stroke:#EDF0FD;}
.d2-1118191387 .stroke-B6{stroke:#F7F8FE;}
.d2-1118191387 .stroke-AA2{stroke:#4A6FF3;}
.d2-1118191387 .stroke-AA4{stroke:#EDF0FD;}
.d2-1118191387 .stroke-AA5{stroke:#F7F8FE;}
.d2-1118191387 .stroke-AB4{stroke:#EDF0FD;}
.d2-1118191387 .stroke-AB5{stroke:#F7F8FE;}
.d2-1118191387 .background-color-N1{background-color:#0A0F25;}
.d2-1118191387 .background-color-N2{background-color:#676C7E;}
.d2-1118191387 .background-color-N3{background-color:#9499AB;}
.d2-1118191387 .background-color-N4{background-color:#CFD2DD;}
.d2-1118191387 .background-color-N5{background-color:#DEE1EB;}
.d2-1118191387 .background-color-N6{background-color:#EEF1F8;}
.d2-1118191387 .background-color-N7{background-color:#FFFFFF;}
.d2-1118191387 .background-color-B1{background-color:#0D32B2;}
.d2-1118191387 .background-color-B2{background-color:#0D32B2;}
.d2-1118191387 .background-color-B3{background-color:#E3E9FD;}
.d2-1118191387 .background-color-B4{background-color:#E3E9FD;}
.d2-1118191387 .background-color-B5{background-color:#EDF0FD;}
.d2-1118191387 .background-color-B6{background-color:#F7F8FE;}
.d2-1118191387 .background-color-AA2{background-color:#4A6FF3;}
.d2-1118191387 .background-color-AA4{background-color:#EDF0FD;}
.d2-1118191387 .background-color-AA5{background-color:#F7F8FE;}
.d2-1118191387 .background-color-AB4{background-color:#EDF0FD;}
.d2-1118191387 .background-color-AB5{background-color:#F7F8FE;}
.d2-1118191387 .color-N1{color:#0A0F25;}
.d2-1118191387 .color-N2{color:#676C7E;}
.d2-1118191387 .color-N3{color:#9499AB;}
.d2-1118191387 .color-N4{color:#CFD2DD;}
.d2-1118191387 .color-N5{color:#DEE1EB;}
.d2-1118191387 .color-N6{color:#EEF1F8;}
.d2-1118191387 .color-N7{color:#FFFFFF;}
.d2-1118191387 .color-B1{color:#0D32B2;}
.d2-1118191387 .color-B2{color:#0D32B2;}
.d2-1118191387 .color-B3{color:#E3E9FD;}
.d2-1118191387 .color-B4{color:#E3E9FD;}
.d2-1118191387 .color-B5{color:#EDF0FD;}
.d2-1118191387 .color-B6{color:#F7F8FE;}
.d2-1118191387 .color-AA2{color:#4A6FF3;}
.d2-1118191387 .color-AA4{color:#EDF0FD;}
.d2-1118191387 .color-AA5{color:#F7F8FE;}
.d2-1118191387 .color-AB4{color:#EDF0FD;}
.d2-1118191387 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><a href="root.layers.x" xlink:href="root.layers.x"><g id="x"><g class="shape" ><rect x="0.000000" y="0.000000" width="85.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="42.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text></g></a><g transform="translate(69 -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><mask id="d2-1118191387" maskUnits="userSpaceOnUse" x="-101" y="-118" width="304" height="285">
<rect x="-101" y="-118" width="304" height="285" fill="white"></rect>
<rect x="38.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
</mask><line x1="-41.000000" x2="143.000000" y1="117.000000" y2="117.000000" class=" stroke-B2" /><g class="appendix" x="-1" y="67" width="104" height="100%"><g transform="translate(0 167)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">1</text></g><text class="text" x="48" y="172" style="font-size: 16px;">root &gt; x</text></g>
</mask><line x1="-41.000000" x2="143.000000" y1="117.000000" y2="117.000000" class=" stroke-B2" /><g class="appendix" x="-1" y="67" width="104" height="100%"><g transform="translate(0 167)" class="appendix-icon"><circle cx="16" cy="0" r="16" fill="white" stroke="#DEE1EB" /><text class="text-bold" x="16" y="5" style="font-size: 16px;text-anchor:middle;">1</text></g><text class="text" x="48" y="172" style="font-size: 16px;">x</text></g>
<style type="text/css"><![CDATA[
.text {
font-family: "font-regular";

Before

Width:  |  Height:  |  Size: 657 KiB

After

Width:  |  Height:  |  Size: 657 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 662 KiB

After

Width:  |  Height:  |  Size: 662 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 662 KiB

After

Width:  |  Height:  |  Size: 662 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-3026443247" width="565" height="630" viewBox="-101 -118 565 630"><rect x="-101.000000" y="-118.000000" width="565" height="630" rx="0.000000" fill="PaleVioletRed" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-3026443247" width="565" height="630" viewBox="-101 -118 565 630"><rect x="-101.000000" y="-118.000000" width="565" height="630" rx="0.000000" fill="PaleVioletRed" stroke-width="0" /><style type="text/css"><![CDATA[
.appendix-icon {
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
}

Before

Width:  |  Height:  |  Size: 661 KiB

After

Width:  |  Height:  |  Size: 661 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-2257413360" width="565" height="630" viewBox="-101 -118 565 630"><rect x="-101.000000" y="-118.000000" width="565" height="630" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 565 630"><svg id="d2-svg" class="d2-2257413360" width="565" height="630" viewBox="-101 -118 565 630"><rect x="-101.000000" y="-118.000000" width="565" height="630" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.appendix-icon {
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
}

Before

Width:  |  Height:  |  Size: 661 KiB

After

Width:  |  Height:  |  Size: 661 KiB

View file

@ -2,6 +2,7 @@ package d2svg
import (
"fmt"
"html"
"io"
"oss.terrastruct.com/d2/d2target"
@ -141,4 +142,19 @@ func drawClass(writer io.Writer, diagramHash string, targetShape d2target.Shape)
)
rowBox.TopLeft.Y += rowHeight
}
if targetShape.Icon != nil && targetShape.Type != d2target.ShapeImage {
iconPosition := label.FromString(targetShape.IconPosition)
iconSize := d2target.GetIconSize(box, targetShape.IconPosition)
tl := iconPosition.GetPointOnBox(box, label.PADDING, float64(iconSize), float64(iconSize))
fmt.Fprintf(writer, `<image href="%s" x="%f" y="%f" width="%d" height="%d" />`,
html.EscapeString(targetShape.Icon.String()),
tl.X,
tl.Y,
iconSize,
iconSize,
)
}
}

View file

@ -74,6 +74,8 @@ type RenderOpts struct {
Center *bool
ThemeID *int64
DarkThemeID *int64
ThemeOverrides *d2target.ThemeOverrides
DarkThemeOverrides *d2target.ThemeOverrides
Font string
// the svg will be scaled by this factor, if unset the svg will fit to screen
Scale *float64
@ -932,6 +934,9 @@ func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape
shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[targetShape.Type]
s := shape.NewShape(shapeType, geo.NewBox(tl, width, height))
if shapeType == shape.CLOUD_TYPE && targetShape.ContentAspectRatio != nil {
s.SetInnerBoxAspectRatio(*targetShape.ContentAspectRatio)
}
var shadowAttr string
if targetShape.Shadow {
@ -1192,10 +1197,15 @@ func drawShape(writer, appendixWriter io.Writer, diagramHash string, targetShape
}
}
// to examine GetInsidePlacement
// padX, padY := s.GetDefaultPadding()
// innerTL := s.GetInsidePlacement(s.GetInnerBox().Width, s.GetInnerBox().Height, padX, padY)
// fmt.Fprint(writer, renderOval(&innerTL, 5, 5, "fill:red;"))
// // to examine shape's innerBox
// innerBox := s.GetInnerBox()
// el := d2themes.NewThemableElement("rect")
// el.X = float64(innerBox.TopLeft.X)
// el.Y = float64(innerBox.TopLeft.Y)
// el.Width = float64(innerBox.Width)
// el.Height = float64(innerBox.Height)
// el.Style = "fill:rgba(255,0,0,0.5);"
// fmt.Fprint(writer, el.Render())
// Closes the class=shape
fmt.Fprint(writer, `</g>`)
@ -1846,7 +1856,7 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
upperBuf := &bytes.Buffer{}
if opts.MasterID == "" {
EmbedFonts(upperBuf, diagramHash, buf.String(), diagram.FontFamily, diagram.GetCorpus()) // EmbedFonts *must* run before `d2sketch.DefineFillPatterns`, but after all elements are appended to `buf`
themeStylesheet, err := ThemeCSS(diagramHash, &themeID, darkThemeID)
themeStylesheet, err := ThemeCSS(diagramHash, &themeID, darkThemeID, opts.ThemeOverrides, opts.DarkThemeOverrides)
if err != nil {
return nil, err
}
@ -2008,17 +2018,17 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
}
// TODO include only colors that are being used to reduce size
func ThemeCSS(diagramHash string, themeID *int64, darkThemeID *int64) (stylesheet string, err error) {
func ThemeCSS(diagramHash string, themeID *int64, darkThemeID *int64, overrides, darkOverrides *d2target.ThemeOverrides) (stylesheet string, err error) {
if themeID == nil {
themeID = &d2themescatalog.NeutralDefault.ID
}
out, err := singleThemeRulesets(diagramHash, *themeID)
out, err := singleThemeRulesets(diagramHash, *themeID, overrides)
if err != nil {
return "", err
}
if darkThemeID != nil {
darkOut, err := singleThemeRulesets(diagramHash, *darkThemeID)
darkOut, err := singleThemeRulesets(diagramHash, *darkThemeID, darkOverrides)
if err != nil {
return "", err
}
@ -2028,9 +2038,10 @@ func ThemeCSS(diagramHash string, themeID *int64, darkThemeID *int64) (styleshee
return out, nil
}
func singleThemeRulesets(diagramHash string, themeID int64) (rulesets string, err error) {
func singleThemeRulesets(diagramHash string, themeID int64, overrides *d2target.ThemeOverrides) (rulesets string, err error) {
out := ""
theme := d2themescatalog.Find(themeID)
theme.ApplyOverrides(overrides)
// Global theme colors
for _, property := range []string{"fill", "stroke", "background-color", "color"} {

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 392 820"><svg id="d2-svg" class="d2-2916329547" width="392" height="820" viewBox="-91 -121 392 820"><rect x="-91.000000" y="-121.000000" width="392.000000" height="820.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 392 820"><svg id="d2-svg" class="d2-2916329547" width="392" height="820" viewBox="-91 -121 392 820"><rect x="-91.000000" y="-121.000000" width="392.000000" height="820.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2916329547 .text {
font-family: "d2-2916329547-font-regular";
}

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1245 615"><svg id="d2-svg" class="d2-3148583989" width="1245" height="615" viewBox="-91 -81 1245 615"><rect x="-91.000000" y="-81.000000" width="1245.000000" height="615.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-3148583989 .text-bold {
font-family: "d2-3148583989-font-bold";
}

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 434"><svg id="d2-svg" class="d2-327680947" width="257" height="434" viewBox="-101 -101 257 434"><rect x="-101.000000" y="-101.000000" width="257.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-327680947 .text-bold {
font-family: "d2-327680947-font-bold";
}

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 634"><svg id="d2-svg" class="d2-914436609" width="350" height="634" viewBox="-91 -121 350 634"><rect x="-91.000000" y="-121.000000" width="350.000000" height="634.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-914436609 .text {
font-family: "d2-914436609-font-regular";
}

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 624 570"><svg id="d2-svg" class="d2-2730605657" width="624" height="570" viewBox="-101 -101 624 570"><rect x="-101.000000" y="-101.000000" width="624.000000" height="570.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2730605657 .text-mono {
font-family: "d2-2730605657-font-mono";
}

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 985 417"><svg id="d2-svg" class="d2-1533752388" width="985" height="417" viewBox="-101 -101 985 417"><rect x="-101.000000" y="-101.000000" width="985.000000" height="417.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 985 417"><svg id="d2-svg" class="d2-1533752388" width="985" height="417" viewBox="-101 -101 985 417"><rect x="-101.000000" y="-101.000000" width="985.000000" height="417.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-1533752388 .text {
font-family: "d2-1533752388-font-regular";
}

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 257 455"><svg id="d2-svg" class="d2-2029734873" width="257" height="455" viewBox="-101 -101 257 455"><rect x="-101.000000" y="-101.000000" width="257.000000" height="455.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2029734873 .text-bold {
font-family: "d2-2029734873-font-bold";
}

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1178 477"><svg id="d2-svg" class="d2-1098532122" width="1178" height="477" viewBox="-100 -101 1178 477"><rect x="-100.000000" y="-101.000000" width="1178.000000" height="477.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-1098532122 .text {
font-family: "d2-1098532122-font-regular";
}

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 758 268"><svg id="d2-svg" class="d2-4290168978" width="758" height="268" viewBox="-101 -101 758 268"><rect x="-101.000000" y="-101.000000" width="758.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 758 268"><svg id="d2-svg" class="d2-4290168978" width="758" height="268" viewBox="-101 -101 758 268"><rect x="-101.000000" y="-101.000000" width="758.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-4290168978 .text-bold {
font-family: "d2-4290168978-font-bold";
}

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 1068 662"><svg id="d2-svg" class="d2-2504113906" width="1068" height="662" viewBox="-101 -101 1068 662"><rect x="-101.000000" y="-101.000000" width="1068.000000" height="662.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2504113906 .text {
font-family: "d2-2504113906-font-regular";
}

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-274840898" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 2801 2344"><svg id="d2-svg" class="d2-274840898" width="2801" height="2344" viewBox="-101 -101 2801 2344"><rect x="-101.000000" y="-101.000000" width="2801.000000" height="2344.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-274840898 .text {
font-family: "d2-274840898-font-regular";
}

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

View file

@ -2,6 +2,7 @@ package d2svg
import (
"fmt"
"html"
"io"
"oss.terrastruct.com/d2/d2target"
@ -163,4 +164,19 @@ func drawTable(writer io.Writer, diagramHash string, targetShape d2target.Shape)
lineEl.Style = "stroke-width:2"
fmt.Fprint(writer, lineEl.Render())
}
if targetShape.Icon != nil && targetShape.Type != d2target.ShapeImage {
iconPosition := label.FromString(targetShape.IconPosition)
iconSize := d2target.GetIconSize(box, targetShape.IconPosition)
tl := iconPosition.GetPointOnBox(box, label.PADDING, float64(iconSize), float64(iconSize))
fmt.Fprintf(writer, `<image href="%s" x="%f" y="%f" width="%d" height="%d" />`,
html.EscapeString(targetShape.Icon.String()),
tl.X,
tl.Y,
iconSize,
iconSize,
)
}
}

View file

@ -6,7 +6,6 @@ import (
"hash/fnv"
"math"
"net/url"
"os"
"strings"
"oss.terrastruct.com/util-go/go2"
@ -46,12 +45,29 @@ type Config struct {
Pad *int64 `json:"pad"`
Center *bool `json:"center"`
LayoutEngine *string `json:"layoutEngine"`
ThemeOverrides *ThemeOverrides `json:"themeOverrides"`
ThemeOverrides *ThemeOverrides `json:"themeOverrides,omitempty"`
DarkThemeOverrides *ThemeOverrides `json:"darkThemeOverrides,omitempty"`
}
type ThemeOverrides struct {
N1 *string `json:"n1"`
// TODO
N2 *string `json:"n2"`
N3 *string `json:"n3"`
N4 *string `json:"n4"`
N5 *string `json:"n5"`
N6 *string `json:"n6"`
N7 *string `json:"n7"`
B1 *string `json:"b1"`
B2 *string `json:"b2"`
B3 *string `json:"b3"`
B4 *string `json:"b4"`
B5 *string `json:"b5"`
B6 *string `json:"b6"`
AA2 *string `json:"aa2"`
AA4 *string `json:"aa4"`
AA5 *string `json:"aa5"`
AB4 *string `json:"ab4"`
AB5 *string `json:"ab5"`
}
type Diagram struct {
@ -73,26 +89,14 @@ type Diagram struct {
Steps []*Diagram `json:"steps,omitempty"`
}
// boardPath comes in the form of "x/layers/z/scenarios/a"
// or "layers/z/scenarios/a"
// or "x/z/a"
func (d *Diagram) GetBoard(boardPath string) *Diagram {
path := strings.Split(boardPath, string(os.PathSeparator))
if len(path) == 0 || len(boardPath) == 0 {
return d
}
return d.getBoard(path)
}
func (d *Diagram) getBoard(boardPath []string) *Diagram {
func (d *Diagram) GetBoard(boardPath []string) *Diagram {
if len(boardPath) == 0 {
return d
}
head := boardPath[0]
if head == "index" {
if len(boardPath) == 1 && d.Name == head {
return d
}
@ -103,7 +107,7 @@ func (d *Diagram) getBoard(boardPath []string) *Diagram {
}
for _, b := range d.Layers {
if b.Name == boardPath[1] {
return b.getBoard(boardPath[2:])
return b.GetBoard(boardPath[2:])
}
}
case "scenarios":
@ -112,7 +116,7 @@ func (d *Diagram) getBoard(boardPath []string) *Diagram {
}
for _, b := range d.Scenarios {
if b.Name == boardPath[1] {
return b.getBoard(boardPath[2:])
return b.GetBoard(boardPath[2:])
}
}
case "steps":
@ -121,24 +125,24 @@ func (d *Diagram) getBoard(boardPath []string) *Diagram {
}
for _, b := range d.Steps {
if b.Name == boardPath[1] {
return b.getBoard(boardPath[2:])
return b.GetBoard(boardPath[2:])
}
}
}
for _, b := range d.Layers {
if b.Name == head {
return b.getBoard(boardPath[1:])
return b.GetBoard(boardPath[1:])
}
}
for _, b := range d.Scenarios {
if b.Name == head {
return b.getBoard(boardPath[1:])
return b.GetBoard(boardPath[1:])
}
}
for _, b := range d.Steps {
if b.Name == head {
return b.getBoard(boardPath[1:])
return b.GetBoard(boardPath[1:])
}
}
return nil
@ -394,6 +398,7 @@ func (diagram Diagram) GetCorpus() string {
appendixCount++
corpus += fmt.Sprint(appendixCount)
}
corpus += s.PrettyLink
if s.Type == ShapeClass {
for _, cf := range s.Fields {
corpus += cf.Text(0).Text + cf.VisibilityToken()
@ -459,6 +464,7 @@ type Shape struct {
Tooltip string `json:"tooltip"`
Link string `json:"link"`
PrettyLink string `json:"prettyLink,omitempty"`
Icon *url.URL `json:"icon"`
IconPosition string `json:"iconPosition"`
@ -469,6 +475,8 @@ type Shape struct {
Class
SQLTable
ContentAspectRatio *float64 `json:"contentAspectRatio,omitempty"`
Text
LabelPosition string `json:"labelPosition,omitempty"`

View file

@ -2,7 +2,10 @@
// Color codes: darkest (N1) -> lightest (N7)
package d2themes
import "oss.terrastruct.com/d2/lib/color"
import (
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/lib/color"
)
type Theme struct {
ID int64 `json:"id"`
@ -26,6 +29,70 @@ func (t *Theme) IsDark() bool {
return t.ID >= 200 && t.ID < 300
}
func (t *Theme) ApplyOverrides(overrides *d2target.ThemeOverrides) {
if overrides == nil {
return
}
if overrides.B1 != nil {
t.Colors.B1 = *overrides.B1
}
if overrides.B2 != nil {
t.Colors.B2 = *overrides.B2
}
if overrides.B3 != nil {
t.Colors.B3 = *overrides.B3
}
if overrides.B4 != nil {
t.Colors.B4 = *overrides.B4
}
if overrides.B5 != nil {
t.Colors.B5 = *overrides.B5
}
if overrides.B5 != nil {
t.Colors.B5 = *overrides.B5
}
if overrides.B6 != nil {
t.Colors.B6 = *overrides.B6
}
if overrides.AA2 != nil {
t.Colors.AA2 = *overrides.AA2
}
if overrides.AA4 != nil {
t.Colors.AA4 = *overrides.AA4
}
if overrides.AA5 != nil {
t.Colors.AA5 = *overrides.AA5
}
if overrides.AB4 != nil {
t.Colors.AB4 = *overrides.AB4
}
if overrides.AB5 != nil {
t.Colors.AB5 = *overrides.AB5
}
if overrides.N1 != nil {
t.Colors.Neutrals.N1 = *overrides.N1
}
if overrides.N2 != nil {
t.Colors.Neutrals.N2 = *overrides.N2
}
if overrides.N3 != nil {
t.Colors.Neutrals.N3 = *overrides.N3
}
if overrides.N4 != nil {
t.Colors.Neutrals.N4 = *overrides.N4
}
if overrides.N5 != nil {
t.Colors.Neutrals.N5 = *overrides.N5
}
if overrides.N6 != nil {
t.Colors.Neutrals.N6 = *overrides.N6
}
if overrides.N7 != nil {
t.Colors.Neutrals.N7 = *overrides.N7
}
}
type Neutral struct {
N1 string `json:"n1"`
N2 string `json:"n2"`

View file

@ -0,0 +1,171 @@
classes: {
empty: {
label: ""
style: {
fill: transparent
stroke-width: 0
}
}
text: {
style: {
fill: transparent
stroke-width: 0
}
}
cluster: {
style: {
fill: transparent
stroke-dash: 4
stroke: "#C6D3DF"
}
}
grid: {
grid-columns: 1
label: ""
style: {
fill: white
stroke-width: 0
}
}
row: {
grid-rows: 1
label: ""
style: {
fill: transparent
stroke-width: 0
}
}
}
vars: {
left-cluster: {
label: "n-sized Vector"
class: cluster
0*.style.fill: "#DFEFFA"
0*.style.stroke: black
grid-rows: 1
grid-gap: 0
label.near: outside-top-left
"0.62"
"0.15"
empty1.class: empty
n.class: text
empty2.class: empty
"0.91"
"0.48"
"0.15" <- n -> "0.91"
}
right-cluster: {
label: "m-sized Vector"
class: cluster
0*.style.fill: "#72F5FF"
0*.style.stroke: black
grid-rows: 1
grid-gap: 0
label.near: outside-top-left
"0.62"
"0.15"
empyt1.class: empty
m.class: text
empty2.class: empty
"0.91"
"0.48"
"0.15" <- m -> "0.91"
}
}
grid-rows: 2
top-row: {
class: row
empty.class: empty
empty.width: 1100
Random Matrix Generator: {
width: 300
height: 170
style.font-size: 20
style.fill: "#A7BBCF"
style.stroke: black
style.border-radius: 10
}
}
bottom-row: {
class: row
left-grid: {
class: grid
1: ${left-cluster}
2: ${left-cluster}
3: ${left-cluster}
}
dot-container: {
class: empty
grid-columns: 1
empty1.class: empty
dot: Dot product {
class: text
circle: "" {
shape: circle
style.fill: black
style.stroke-width: 0
width: 20
height: 20
}
label.near: outside-bottom-center
}
}
matrix-container: {
class: empty
grid-columns: 1
matrix: Target dimension matrix {
label.near: outside-top-center
grid-rows: 4
grid-gap: 0
*.width: 100
*.height: 100
*.style.fill: "#F1F6F9"
*.style.stroke: black
"0.41"
"0.32"
"0.92"
"0.13"
"0.74"
"0.15"
"0.53"
"0.21"
"0.97"
"0.45"
"0.11"
"0.05"
"0.61"
"0.77"
"0.59"
"0.83"
}
}
empty.class: empty
right-grid: {
class: grid
1: ${right-cluster}
2: ${right-cluster}
3: ${right-cluster}
}
matrix-container -> right-grid
}
top-row.Random Matrix Generator -> bottom-row.matrix-container.matrix

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 192 KiB

View file

@ -30,6 +30,7 @@ func TestCLI_E2E(t *testing.T) {
tca := []struct {
name string
serial bool
skipCI bool
skip bool
run func(t *testing.T, ctx context.Context, dir string, env *xos.Env)
@ -239,6 +240,243 @@ You provided: .png`)
testdataIgnoreDiff(t, ".png", png)
},
},
{
name: "target-root",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "target-root.d2", `title: {
label: Main Plan
}
scenarios: {
b: {
title.label: Backup Plan
}
}`)
err := runTestMain(t, ctx, dir, env, "--target", "", "target-root.d2", "target-root.svg")
assert.Success(t, err)
svg := readFile(t, dir, "target-root.svg")
assert.Testdata(t, ".svg", svg)
},
},
{
name: "target-b",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "target-b.d2", `title: {
label: Main Plan
}
scenarios: {
b: {
title.label: Backup Plan
}
}`)
err := runTestMain(t, ctx, dir, env, "--target", "b", "target-b.d2", "target-b.svg")
assert.Success(t, err)
svg := readFile(t, dir, "target-b.svg")
assert.Testdata(t, ".svg", svg)
},
},
{
name: "target-nested-with-special-chars",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "target-nested-with-special-chars.d2", `layers: {
a: {
layers: {
"x / y . z": {
mad
}
}
}
}`)
err := runTestMain(t, ctx, dir, env, "--target", `layers.a.layers."x / y . z"`, "target-nested-with-special-chars.d2", "target-nested-with-special-chars.svg")
assert.Success(t, err)
svg := readFile(t, dir, "target-nested-with-special-chars.svg")
assert.Testdata(t, ".svg", svg)
},
},
{
name: "target-invalid",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "target-invalid.d2", `x -> y`)
err := runTestMain(t, ctx, dir, env, "--target", "b", "target-invalid.d2", "target-invalid.svg")
assert.ErrorString(t, err, `failed to wait xmain test: e2etests-cli/d2: failed to compile target-invalid.d2: render target "b" not found`)
},
},
{
name: "target-nested-index",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "target-nested-index.d2", `a
layers: {
l1: {
b
layers: {
index: {
c
layers: {
l3: {
d
}
}
}
}
}
}`)
err := runTestMain(t, ctx, dir, env, "--target", `l1.index.l3`, "target-nested-index.d2", "target-nested-index.svg")
assert.Success(t, err)
svg := readFile(t, dir, "target-nested-index.svg")
assert.Testdata(t, ".svg", svg)
},
},
{
name: "target-nested-index2",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "target-nested-index2.d2", `a
layers: {
index: {
b
layers: {
nest1: {
c
scenarios: {
nest2: {
d
}
}
}
}
}
}`)
err := runTestMain(t, ctx, dir, env, "--target", `index.nest1.nest2`, "target-nested-index2.d2", "target-nested-index2.svg")
assert.Success(t, err)
svg := readFile(t, dir, "target-nested-index2.svg")
assert.Testdata(t, ".svg", svg)
},
},
{
name: "theme-override",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "theme-override.d2", `
direction: right
vars: {
d2-config: {
theme-overrides: {
B1: "#2E7D32"
B2: "#66BB6A"
B3: "#A5D6A7"
B4: "#C5E1A5"
B5: "#E6EE9C"
B6: "#FFF59D"
AA2: "#0D47A1"
AA4: "#42A5F5"
AA5: "#90CAF9"
AB4: "#F44336"
AB5: "#FFCDD2"
N1: "#2E2E2E"
N2: "#2E2E2E"
N3: "#595959"
N4: "#858585"
N5: "#B1B1B1"
N6: "#DCDCDC"
N7: "#DCDCDC"
}
dark-theme-overrides: {
B1: "#2E7D32"
B2: "#66BB6A"
B3: "#A5D6A7"
B4: "#C5E1A5"
B5: "#E6EE9C"
B6: "#FFF59D"
AA2: "#0D47A1"
AA4: "#42A5F5"
AA5: "#90CAF9"
AB4: "#F44336"
AB5: "#FFCDD2"
N1: "#2E2E2E"
N2: "#2E2E2E"
N3: "#595959"
N4: "#858585"
N5: "#B1B1B1"
N6: "#DCDCDC"
N7: "#DCDCDC"
}
}
}
logs: {
shape: page
style.multiple: true
}
user: User {shape: person}
network: Network {
tower: Cell Tower {
satellites: {
shape: stored_data
style.multiple: true
}
satellites -> transmitter
satellites -> transmitter
satellites -> transmitter
transmitter
}
processor: Data Processor {
storage: Storage {
shape: cylinder
style.multiple: true
}
}
portal: Online Portal {
UI
}
tower.transmitter -> processor: phone logs
}
server: API Server
user -> network.tower: Make call
network.processor -> server
network.processor -> server
network.processor -> server
server -> logs
server -> logs
server -> logs: persist
server -> network.portal.UI: display
user -> network.portal.UI: access {
style.stroke-dash: 3
}
costumes: {
shape: sql_table
id: int {constraint: primary_key}
silliness: int
monster: int
last_updated: timestamp
}
monsters: {
shape: sql_table
id: int {constraint: primary_key}
movie: string
weight: int
last_updated: timestamp
}
costumes.monster -> monsters.id
`)
err := runTestMain(t, ctx, dir, env, "theme-override.d2", "theme-override.svg")
assert.Success(t, err)
svg := readFile(t, dir, "theme-override.svg")
assert.Testdata(t, ".svg", svg)
// theme color is used in SVG
assert.NotEqual(t, -1, strings.Index(string(svg), "#2E2E2E"))
},
},
{
name: "multiboard/life",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
@ -527,6 +765,86 @@ i used to read
assert.Testdata(t, ".svg", svg)
},
},
{
name: "renamed-board",
skipCI: true,
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "in.d2", `cat: how does the cat go? {
link: layers.cat
}
a.link: "https://www.google.com/maps/place/Smoked+Out+BBQ/@37.3848007,-121.9513887,17z/data=!3m1!4b1!4m6!3m5!1s0x808fc9182ad4d38d:0x8e2f39c3e927b296!8m2!3d37.3848007!4d-121.9492!16s%2Fg%2F11gjt85zvf"
label: blah
layers: {
cat: {
label: dog
home: {
link: _
}
the cat -> meow: goes
}
}
`)
err := runTestMain(t, ctx, dir, env, "in.d2", "out.pdf")
assert.Success(t, err)
pdf := readFile(t, dir, "out.pdf")
testdataIgnoreDiff(t, ".pdf", pdf)
},
},
{
name: "no-nav-pdf",
skipCI: true,
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "in.d2", `cat: how does the cat go? {
link: layers.cat
}
a.link: "https://www.google.com/maps/place/Smoked+Out+BBQ/@37.3848007,-121.9513887,17z/data=!3m1!4b1!4m6!3m5!1s0x808fc9182ad4d38d:0x8e2f39c3e927b296!8m2!3d37.3848007!4d-121.9492!16s%2Fg%2F11gjt85zvf"
label: ""
layers: {
cat: {
label: dog
home: {
link: _
}
the cat -> meow: goes
}
}
`)
err := runTestMain(t, ctx, dir, env, "in.d2", "out.pdf")
assert.Success(t, err)
pdf := readFile(t, dir, "out.pdf")
testdataIgnoreDiff(t, ".pdf", pdf)
},
},
{
name: "no-nav-pptx",
skipCI: true,
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "in.d2", `cat: how does the cat go? {
link: layers.cat
}
a.link: "https://www.google.com/maps/place/Smoked+Out+BBQ/@37.3848007,-121.9513887,17z/data=!3m1!4b1!4m6!3m5!1s0x808fc9182ad4d38d:0x8e2f39c3e927b296!8m2!3d37.3848007!4d-121.9492!16s%2Fg%2F11gjt85zvf"
label: ""
layers: {
cat: {
label: dog
home: {
link: _
}
the cat -> meow: goes
}
}
`)
err := runTestMain(t, ctx, dir, env, "in.d2", "out.pptx")
assert.Success(t, err)
file := readFile(t, dir, "out.pptx")
// err = pptx.Validate(file, 2)
assert.Success(t, err)
testdataIgnoreDiff(t, ".pptx", file)
},
},
{
name: "basic-fmt",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
@ -552,6 +870,7 @@ i used to read
},
{
name: "watch-regular",
serial: true,
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "index.d2", `
a -> b
@ -602,6 +921,7 @@ layers: {
},
{
name: "watch-ok-link",
serial: true,
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
// This link technically works because D2 interprets it as a URL,
// and on local filesystem, that is whe path where the compilation happens
@ -656,6 +976,7 @@ layers: {
},
{
name: "watch-bad-link",
serial: true,
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
// Just verify we don't crash even with a bad link (it's treated as a URL, which users might have locally)
writeFile(t, dir, "index.d2", `
@ -707,6 +1028,7 @@ layers: {
},
{
name: "watch-imported-file",
serial: true,
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "a.d2", `
...@b
@ -785,7 +1107,9 @@ c
for _, tc := range tca {
tc := tc
t.Run(tc.name, func(t *testing.T) {
if !tc.serial {
t.Parallel()
}
if tc.skipCI && os.Getenv("CI") != "" {
t.SkipNow()
@ -882,7 +1206,7 @@ func waitLogs(ctx context.Context, buf *bytes.Buffer, pattern *regexp.Regexp) (s
ticker := time.NewTicker(10 * time.Millisecond)
defer ticker.Stop()
var match string
for i := 0; i < 100 && match == ""; i++ {
for i := 0; i < 1000 && match == ""; i++ {
select {
case <-ticker.C:
out := buf.String()

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-1843626214" width="256" height="434" viewBox="-101 -101 256 434"><rect x="-101.000000" y="-101.000000" width="256.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-1843626214" width="256" height="434" viewBox="-101 -101 256 434"><rect x="-101.000000" y="-101.000000" width="256.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-1843626214 .text-bold {
font-family: "d2-1843626214-font-bold";
}

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

View file

@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 514 665"><svg id="d2-svg" width="514" height="665" viewBox="-206 -166 514 665"><style type="text/css"><![CDATA[
.d2-4132224283 .text {
font-family: "d2-4132224283-font-regular";
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 514 665"><svg id="d2-svg" width="514" height="665" viewBox="-206 -166 514 665"><style type="text/css"><![CDATA[
.d2-4130279961 .text {
font-family: "d2-4130279961-font-regular";
}
@font-face {
font-family: d2-4132224283-font-regular;
font-family: d2-4130279961-font-regular;
src: url("data:application/font-woff;base64,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");
}
.d2-4132224283 .text-bold {
font-family: "d2-4132224283-font-bold";
.d2-4130279961 .text-bold {
font-family: "d2-4130279961-font-bold";
}
@font-face {
font-family: d2-4132224283-font-bold;
font-family: d2-4130279961-font-bold;
src: url("data:application/font-woff;base64,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");
}]]></style><style type="text/css"><![CDATA[.shape {
shape-rendering: geometricPrecision;
@ -25,92 +25,92 @@
opacity: 0.5;
}
.d2-4132224283 .fill-N1{fill:#0A0F25;}
.d2-4132224283 .fill-N2{fill:#676C7E;}
.d2-4132224283 .fill-N3{fill:#9499AB;}
.d2-4132224283 .fill-N4{fill:#CFD2DD;}
.d2-4132224283 .fill-N5{fill:#DEE1EB;}
.d2-4132224283 .fill-N6{fill:#EEF1F8;}
.d2-4132224283 .fill-N7{fill:#FFFFFF;}
.d2-4132224283 .fill-B1{fill:#0D32B2;}
.d2-4132224283 .fill-B2{fill:#0D32B2;}
.d2-4132224283 .fill-B3{fill:#E3E9FD;}
.d2-4132224283 .fill-B4{fill:#E3E9FD;}
.d2-4132224283 .fill-B5{fill:#EDF0FD;}
.d2-4132224283 .fill-B6{fill:#F7F8FE;}
.d2-4132224283 .fill-AA2{fill:#4A6FF3;}
.d2-4132224283 .fill-AA4{fill:#EDF0FD;}
.d2-4132224283 .fill-AA5{fill:#F7F8FE;}
.d2-4132224283 .fill-AB4{fill:#EDF0FD;}
.d2-4132224283 .fill-AB5{fill:#F7F8FE;}
.d2-4132224283 .stroke-N1{stroke:#0A0F25;}
.d2-4132224283 .stroke-N2{stroke:#676C7E;}
.d2-4132224283 .stroke-N3{stroke:#9499AB;}
.d2-4132224283 .stroke-N4{stroke:#CFD2DD;}
.d2-4132224283 .stroke-N5{stroke:#DEE1EB;}
.d2-4132224283 .stroke-N6{stroke:#EEF1F8;}
.d2-4132224283 .stroke-N7{stroke:#FFFFFF;}
.d2-4132224283 .stroke-B1{stroke:#0D32B2;}
.d2-4132224283 .stroke-B2{stroke:#0D32B2;}
.d2-4132224283 .stroke-B3{stroke:#E3E9FD;}
.d2-4132224283 .stroke-B4{stroke:#E3E9FD;}
.d2-4132224283 .stroke-B5{stroke:#EDF0FD;}
.d2-4132224283 .stroke-B6{stroke:#F7F8FE;}
.d2-4132224283 .stroke-AA2{stroke:#4A6FF3;}
.d2-4132224283 .stroke-AA4{stroke:#EDF0FD;}
.d2-4132224283 .stroke-AA5{stroke:#F7F8FE;}
.d2-4132224283 .stroke-AB4{stroke:#EDF0FD;}
.d2-4132224283 .stroke-AB5{stroke:#F7F8FE;}
.d2-4132224283 .background-color-N1{background-color:#0A0F25;}
.d2-4132224283 .background-color-N2{background-color:#676C7E;}
.d2-4132224283 .background-color-N3{background-color:#9499AB;}
.d2-4132224283 .background-color-N4{background-color:#CFD2DD;}
.d2-4132224283 .background-color-N5{background-color:#DEE1EB;}
.d2-4132224283 .background-color-N6{background-color:#EEF1F8;}
.d2-4132224283 .background-color-N7{background-color:#FFFFFF;}
.d2-4132224283 .background-color-B1{background-color:#0D32B2;}
.d2-4132224283 .background-color-B2{background-color:#0D32B2;}
.d2-4132224283 .background-color-B3{background-color:#E3E9FD;}
.d2-4132224283 .background-color-B4{background-color:#E3E9FD;}
.d2-4132224283 .background-color-B5{background-color:#EDF0FD;}
.d2-4132224283 .background-color-B6{background-color:#F7F8FE;}
.d2-4132224283 .background-color-AA2{background-color:#4A6FF3;}
.d2-4132224283 .background-color-AA4{background-color:#EDF0FD;}
.d2-4132224283 .background-color-AA5{background-color:#F7F8FE;}
.d2-4132224283 .background-color-AB4{background-color:#EDF0FD;}
.d2-4132224283 .background-color-AB5{background-color:#F7F8FE;}
.d2-4132224283 .color-N1{color:#0A0F25;}
.d2-4132224283 .color-N2{color:#676C7E;}
.d2-4132224283 .color-N3{color:#9499AB;}
.d2-4132224283 .color-N4{color:#CFD2DD;}
.d2-4132224283 .color-N5{color:#DEE1EB;}
.d2-4132224283 .color-N6{color:#EEF1F8;}
.d2-4132224283 .color-N7{color:#FFFFFF;}
.d2-4132224283 .color-B1{color:#0D32B2;}
.d2-4132224283 .color-B2{color:#0D32B2;}
.d2-4132224283 .color-B3{color:#E3E9FD;}
.d2-4132224283 .color-B4{color:#E3E9FD;}
.d2-4132224283 .color-B5{color:#EDF0FD;}
.d2-4132224283 .color-B6{color:#F7F8FE;}
.d2-4132224283 .color-AA2{color:#4A6FF3;}
.d2-4132224283 .color-AA4{color:#EDF0FD;}
.d2-4132224283 .color-AA5{color:#F7F8FE;}
.d2-4132224283 .color-AB4{color:#EDF0FD;}
.d2-4132224283 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><style type="text/css">.md em,
.d2-4130279961 .fill-N1{fill:#0A0F25;}
.d2-4130279961 .fill-N2{fill:#676C7E;}
.d2-4130279961 .fill-N3{fill:#9499AB;}
.d2-4130279961 .fill-N4{fill:#CFD2DD;}
.d2-4130279961 .fill-N5{fill:#DEE1EB;}
.d2-4130279961 .fill-N6{fill:#EEF1F8;}
.d2-4130279961 .fill-N7{fill:#FFFFFF;}
.d2-4130279961 .fill-B1{fill:#0D32B2;}
.d2-4130279961 .fill-B2{fill:#0D32B2;}
.d2-4130279961 .fill-B3{fill:#E3E9FD;}
.d2-4130279961 .fill-B4{fill:#E3E9FD;}
.d2-4130279961 .fill-B5{fill:#EDF0FD;}
.d2-4130279961 .fill-B6{fill:#F7F8FE;}
.d2-4130279961 .fill-AA2{fill:#4A6FF3;}
.d2-4130279961 .fill-AA4{fill:#EDF0FD;}
.d2-4130279961 .fill-AA5{fill:#F7F8FE;}
.d2-4130279961 .fill-AB4{fill:#EDF0FD;}
.d2-4130279961 .fill-AB5{fill:#F7F8FE;}
.d2-4130279961 .stroke-N1{stroke:#0A0F25;}
.d2-4130279961 .stroke-N2{stroke:#676C7E;}
.d2-4130279961 .stroke-N3{stroke:#9499AB;}
.d2-4130279961 .stroke-N4{stroke:#CFD2DD;}
.d2-4130279961 .stroke-N5{stroke:#DEE1EB;}
.d2-4130279961 .stroke-N6{stroke:#EEF1F8;}
.d2-4130279961 .stroke-N7{stroke:#FFFFFF;}
.d2-4130279961 .stroke-B1{stroke:#0D32B2;}
.d2-4130279961 .stroke-B2{stroke:#0D32B2;}
.d2-4130279961 .stroke-B3{stroke:#E3E9FD;}
.d2-4130279961 .stroke-B4{stroke:#E3E9FD;}
.d2-4130279961 .stroke-B5{stroke:#EDF0FD;}
.d2-4130279961 .stroke-B6{stroke:#F7F8FE;}
.d2-4130279961 .stroke-AA2{stroke:#4A6FF3;}
.d2-4130279961 .stroke-AA4{stroke:#EDF0FD;}
.d2-4130279961 .stroke-AA5{stroke:#F7F8FE;}
.d2-4130279961 .stroke-AB4{stroke:#EDF0FD;}
.d2-4130279961 .stroke-AB5{stroke:#F7F8FE;}
.d2-4130279961 .background-color-N1{background-color:#0A0F25;}
.d2-4130279961 .background-color-N2{background-color:#676C7E;}
.d2-4130279961 .background-color-N3{background-color:#9499AB;}
.d2-4130279961 .background-color-N4{background-color:#CFD2DD;}
.d2-4130279961 .background-color-N5{background-color:#DEE1EB;}
.d2-4130279961 .background-color-N6{background-color:#EEF1F8;}
.d2-4130279961 .background-color-N7{background-color:#FFFFFF;}
.d2-4130279961 .background-color-B1{background-color:#0D32B2;}
.d2-4130279961 .background-color-B2{background-color:#0D32B2;}
.d2-4130279961 .background-color-B3{background-color:#E3E9FD;}
.d2-4130279961 .background-color-B4{background-color:#E3E9FD;}
.d2-4130279961 .background-color-B5{background-color:#EDF0FD;}
.d2-4130279961 .background-color-B6{background-color:#F7F8FE;}
.d2-4130279961 .background-color-AA2{background-color:#4A6FF3;}
.d2-4130279961 .background-color-AA4{background-color:#EDF0FD;}
.d2-4130279961 .background-color-AA5{background-color:#F7F8FE;}
.d2-4130279961 .background-color-AB4{background-color:#EDF0FD;}
.d2-4130279961 .background-color-AB5{background-color:#F7F8FE;}
.d2-4130279961 .color-N1{color:#0A0F25;}
.d2-4130279961 .color-N2{color:#676C7E;}
.d2-4130279961 .color-N3{color:#9499AB;}
.d2-4130279961 .color-N4{color:#CFD2DD;}
.d2-4130279961 .color-N5{color:#DEE1EB;}
.d2-4130279961 .color-N6{color:#EEF1F8;}
.d2-4130279961 .color-N7{color:#FFFFFF;}
.d2-4130279961 .color-B1{color:#0D32B2;}
.d2-4130279961 .color-B2{color:#0D32B2;}
.d2-4130279961 .color-B3{color:#E3E9FD;}
.d2-4130279961 .color-B4{color:#E3E9FD;}
.d2-4130279961 .color-B5{color:#EDF0FD;}
.d2-4130279961 .color-B6{color:#F7F8FE;}
.d2-4130279961 .color-AA2{color:#4A6FF3;}
.d2-4130279961 .color-AA4{color:#EDF0FD;}
.d2-4130279961 .color-AA5{color:#F7F8FE;}
.d2-4130279961 .color-AB4{color:#EDF0FD;}
.d2-4130279961 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><style type="text/css">.md em,
.md dfn {
font-family: "d2-4132224283-font-italic";
font-family: "d2-4130279961-font-italic";
}
.md b,
.md strong {
font-family: "d2-4132224283-font-bold";
font-family: "d2-4130279961-font-bold";
}
.md code,
.md kbd,
.md pre,
.md samp {
font-family: "d2-4132224283-font-mono";
font-family: "d2-4130279961-font-mono";
font-size: 1em;
}
@ -126,7 +126,7 @@
margin: 0;
color: var(--color-fg-default);
background-color: transparent; /* we don't want to define the background color */
font-family: "d2-4132224283-font-regular";
font-family: "d2-4130279961-font-regular";
font-size: 16px;
line-height: 1.5;
word-wrap: break-word;
@ -832,7 +832,7 @@
.md .contains-task-list:dir(rtl) .task-list-item-checkbox {
margin: 0 -1.6em 0.25em 0.2em;
}
</style><style type="text/css"><![CDATA[@keyframes d2Transition-d2-4132224283-0 {
</style><style type="text/css"><![CDATA[@keyframes d2Transition-d2-4130279961-0 {
0%, 0.000000% {
opacity: 0;
}
@ -842,7 +842,7 @@
25.000000%, 100% {
opacity: 0;
}
}@keyframes d2Transition-d2-4132224283-1 {
}@keyframes d2Transition-d2-4130279961-1 {
0%, 24.982143% {
opacity: 0;
}
@ -852,7 +852,7 @@
50.000000%, 100% {
opacity: 0;
}
}@keyframes d2Transition-d2-4132224283-2 {
}@keyframes d2Transition-d2-4130279961-2 {
0%, 49.982143% {
opacity: 0;
}
@ -862,26 +862,26 @@
75.000000%, 100% {
opacity: 0;
}
}@keyframes d2Transition-d2-4132224283-3 {
}@keyframes d2Transition-d2-4130279961-3 {
0%, 74.982143% {
opacity: 0;
}
75.000000%, 100.000000% {
opacity: 1;
}
}]]></style><g style="animation: d2Transition-d2-4132224283-0 5600ms infinite" class="d2-4132224283" width="412" height="247" viewBox="-206 -166 412 247"><rect x="-206.000000" y="-166.000000" width="412.000000" height="247.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="&#34;Chicken&#39;s plan&#34;"><g class="shape" ></g><text x="0.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken&#39;s plan</text></g><mask id="d2-4132224283" maskUnits="userSpaceOnUse" x="-206" y="-166" width="412" height="247">
}]]></style><g style="animation: d2Transition-d2-4130279961-0 5600ms infinite" class="d2-4130279961" width="412" height="247" viewBox="-206 -166 412 247"><rect x="-206.000000" y="-166.000000" width="412.000000" height="247.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="&#34;Chicken&#39;s plan&#34;"><g class="shape" ></g><text x="0.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken&#39;s plan</text></g><mask id="d2-4130279961" maskUnits="userSpaceOnUse" x="-206" y="-166" width="412" height="247">
<rect x="-206" y="-166" width="412" height="247" fill="white"></rect>
<rect x="-105.000000" y="-65.000000" width="210" height="45" fill="rgba(0,0,0,0.75)"></rect>
</mask></g><g style="animation: d2Transition-d2-4132224283-1 5600ms infinite" class="d2-4132224283" width="412" height="333" viewBox="-131 -166 412 333"><rect x="-131.000000" y="-166.000000" width="412.000000" height="333.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="&#34;Chicken&#39;s plan&#34;"><g class="shape" ></g><text x="75.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken&#39;s plan</text></g><g id="Approach road"><g class="shape" ><rect x="0.000000" y="0.000000" width="150.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="75.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Approach road</text></g><mask id="d2-3831827619" maskUnits="userSpaceOnUse" x="-131" y="-166" width="412" height="333">
</mask></g><g style="animation: d2Transition-d2-4130279961-1 5600ms infinite" class="d2-4130279961" width="412" height="333" viewBox="-131 -166 412 333"><rect x="-131.000000" y="-166.000000" width="412.000000" height="333.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="&#34;Chicken&#39;s plan&#34;"><g class="shape" ></g><text x="75.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken&#39;s plan</text></g><g id="Approach road"><g class="shape" ><rect x="0.000000" y="0.000000" width="150.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="75.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Approach road</text></g><mask id="d2-4293673862" maskUnits="userSpaceOnUse" x="-131" y="-166" width="412" height="333">
<rect x="-131" y="-166" width="412" height="333" fill="white"></rect>
<rect x="-30.000000" y="-65.000000" width="210" height="45" fill="rgba(0,0,0,0.75)"></rect>
<rect x="22.500000" y="22.500000" width="105" height="21" fill="rgba(0,0,0,0.75)"></rect>
</mask></g><g style="animation: d2Transition-d2-4132224283-2 5600ms infinite" class="d2-4132224283" width="412" height="499" viewBox="-131 -166 412 499"><rect x="-131.000000" y="-166.000000" width="412.000000" height="499.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="&#34;Chicken&#39;s plan&#34;"><g class="shape" ></g><text x="75.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken&#39;s plan</text></g><g id="Approach road"><g class="shape" ><rect x="0.000000" y="0.000000" width="150.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="75.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Approach road</text></g><g id="Cross road"><g class="shape" ><rect x="15.000000" y="166.000000" width="120.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="75.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Cross road</text></g><g id="(Approach road -&gt; Cross road)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 75.000000 68.000000 C 75.000000 106.000000 75.000000 126.000000 75.000000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-434121175)" /></g><mask id="d2-434121175" maskUnits="userSpaceOnUse" x="-131" y="-166" width="412" height="499">
</mask></g><g style="animation: d2Transition-d2-4130279961-2 5600ms infinite" class="d2-4130279961" width="412" height="499" viewBox="-131 -166 412 499"><rect x="-131.000000" y="-166.000000" width="412.000000" height="499.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="&#34;Chicken&#39;s plan&#34;"><g class="shape" ></g><text x="75.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken&#39;s plan</text></g><g id="Approach road"><g class="shape" ><rect x="0.000000" y="0.000000" width="150.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="75.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Approach road</text></g><g id="Cross road"><g class="shape" ><rect x="15.000000" y="166.000000" width="120.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="75.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Cross road</text></g><g id="(Approach road -&gt; Cross road)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 75.000000 68.000000 C 75.000000 106.000000 75.000000 126.000000 75.000000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-600153991)" /></g><mask id="d2-600153991" maskUnits="userSpaceOnUse" x="-131" y="-166" width="412" height="499">
<rect x="-131" y="-166" width="412" height="499" fill="white"></rect>
<rect x="-30.000000" y="-65.000000" width="210" height="45" fill="rgba(0,0,0,0.75)"></rect>
<rect x="22.500000" y="22.500000" width="105" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="37.500000" y="188.500000" width="75" height="21" fill="rgba(0,0,0,0.75)"></rect>
</mask></g><g style="animation: d2Transition-d2-4132224283-3 5600ms infinite" class="d2-4132224283" width="412" height="665" viewBox="-104 -166 412 665"><rect x="-104.000000" y="-166.000000" width="412.000000" height="665.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="&#34;Chicken&#39;s plan&#34;"><g class="shape" ></g><text x="102.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken&#39;s plan</text></g><g id="Approach road"><g class="shape" ><rect x="27.000000" y="0.000000" width="150.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="102.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Approach road</text></g><g id="Cross road"><g class="shape" ><rect x="42.000000" y="166.000000" width="120.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="102.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Cross road</text></g><g id="Make you wonder why"><g class="shape" ><rect x="0.000000" y="332.000000" width="203.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="101.500000" y="370.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Make you wonder why</text></g><g id="(Approach road -&gt; Cross road)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 101.500000 68.000000 C 101.500000 106.000000 101.500000 126.000000 101.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2249258493)" /></g><g id="(Cross road -&gt; Make you wonder why)[0]"><path d="M 101.500000 234.000000 C 101.500000 272.000000 101.500000 292.000000 101.500000 328.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2249258493)" /></g><mask id="d2-2249258493" maskUnits="userSpaceOnUse" x="-104" y="-166" width="412" height="665">
</mask></g><g style="animation: d2Transition-d2-4130279961-3 5600ms infinite" class="d2-4130279961" width="412" height="665" viewBox="-104 -166 412 665"><rect x="-104.000000" y="-166.000000" width="412.000000" height="665.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="&#34;Chicken&#39;s plan&#34;"><g class="shape" ></g><text x="102.000000" y="-30.000000" class="text fill-N1" style="text-anchor:middle;font-size:35px">Chicken&#39;s plan</text></g><g id="Approach road"><g class="shape" ><rect x="27.000000" y="0.000000" width="150.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="102.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Approach road</text></g><g id="Cross road"><g class="shape" ><rect x="42.000000" y="166.000000" width="120.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="102.000000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Cross road</text></g><g id="Make you wonder why"><g class="shape" ><rect x="0.000000" y="332.000000" width="203.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="101.500000" y="370.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Make you wonder why</text></g><g id="(Approach road -&gt; Cross road)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 101.500000 68.000000 C 101.500000 106.000000 101.500000 126.000000 101.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-191946974)" /></g><g id="(Cross road -&gt; Make you wonder why)[0]"><path d="M 101.500000 234.000000 C 101.500000 272.000000 101.500000 292.000000 101.500000 328.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-191946974)" /></g><mask id="d2-191946974" maskUnits="userSpaceOnUse" x="-104" y="-166" width="412" height="665">
<rect x="-104" y="-166" width="412" height="665" fill="white"></rect>
<rect x="-3.000000" y="-65.000000" width="210" height="45" fill="rgba(0,0,0,0.75)"></rect>
<rect x="49.500000" y="22.500000" width="105" height="21" fill="rgba(0,0,0,0.75)"></rect>

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 290 268"><svg id="d2-svg" class="d2-3054270525" width="290" height="268" viewBox="-101 -101 290 268"><rect x="-101.000000" y="-101.000000" width="290.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-3054270525 .text-bold {
font-family: "d2-3054270525-font-bold";
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 290 268"><svg id="d2-svg" class="d2-3109420268" width="290" height="268" viewBox="-101 -101 290 268"><rect x="-101.000000" y="-101.000000" width="290.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-3109420268 .text-bold {
font-family: "d2-3109420268-font-bold";
}
@font-face {
font-family: d2-3054270525-font-bold;
font-family: d2-3109420268-font-bold;
src: url("data:application/font-woff;base64,d09GRgABAAAAAAdAAAoAAAAADDAAAguFAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAAA9AAAAGAAAABgXxHXrmNtYXAAAAFUAAAARgAAAE4BEgEqZ2x5ZgAAAZwAAAG+AAAB7J/I7etoZWFkAAADXAAAADYAAAA2G38e1GhoZWEAAAOUAAAAJAAAACQKfwXEaG10eAAAA7gAAAAUAAAAFA1EAPFsb2NhAAADzAAAAAwAAAAMAR4BtG1heHAAAAPYAAAAIAAAACAAHQD3bmFtZQAAA/gAAAMoAAAIKgjwVkFwb3N0AAAHIAAAAB0AAAAg/9EAMgADAioCvAAFAAACigJYAAAASwKKAlgAAAFeADIBKQAAAgsHAwMEAwICBGAAAvcAAAADAAAAAAAAAABBREJPACAAIP//Au7/BgAAA9gBESAAAZ8AAAAAAfAClAAAACAAA3icRMu7DUBgAEbR8z8KEVPZRSlKU+jo7PpJJOJWtzkomoJJN2M0qKrFarMn/J87V84cr/gqqqbzAAAA//8BAAD//+jVDjMAAHicZI+xb9NAGEe/s907ObQKbhu7AhXXOexLoE7iXO1DRMExWGlVGimkE0JtpKytWglSFSEkVhYWyIAYmGBjQUz0D8jEzsySOQNiCgbZIITU5fduuu89mIMugDSQRiCDCnlYhAIA1yzN5oxRIrgQ1JAFQxrpSovJ+3esrJTLyrW11+aTfh919qXRz8MHncHgR7/RSN5+PkteoEdnABJc/fUdfUMzWAETYK7oOP5GEPC6rheWMbF0ndeFgbHMNxxaxMjcfHj7zmFjc6+qSMnXXNvzA8/Zf/OJrReD+VvD3r1hGB7ES7YacOv+pSvoZtmvAgAgiADkVTQDK/XmBs+OGNkWNKql35N/jB7nFLPt+dGSte11775aXbNr6VTRtGW610tF72Av+YKsoFRLPv7FnxaJoBnk4fK5FszqgZ9FFJZ1pIfHcXwchkdxfBS6lYpbcd355klvd9hsDnd7J83TTiva2YlandR9BUCaomnmLnND11N9If57yZQ5DqMYEzJ6+rKGc1ghC6p4dkPNE4WopPr89INLFohCLpB1NJ3YW46zTScZt+xJcnFM26VSm44BfgMAAP//AQAA//8hWGnzAAAAAQAAAAILhStB8elfDzz1AAED6AAAAADYXaCEAAAAAN1mLzb+N/7ECG0D8QABAAMAAgAAAAAAAAABAAAD2P7vAAAImP43/jcIbQABAAAAAAAAAAAAAAAAAAAABQKyAFACBgAkA1kAQQIrACQDCAAYAAAALABgAJIAvgD2AAEAAAAFAJAADABjAAcAAQAAAAAAAAAAAAAAAAAEAAN4nJyUz24bVRTGf05s0wrBAkVVuonugkWR6NhUSdU2K4fUikUUB48LQkJIE8/4jzKeGXkmDuEJWPMWvEVXPATPgVij+Xzs2AXRJoqSfHfu+fOdc75zgR3+ZptK9SHwRz0xXGGvfm54iwf1E8PbtOtbhqs8qf1puEZYmxuu83mtZ/gj3lZ/M/yA/epPhh+yW20b/phn1R3Dn2w7/jL8Kfu8XeAKvOBXwxV2yQxvscOPhrd5hMWsVHlE03CNz9gzXGcP6DOhIGZCwgjHkAkjrpgRkeMTMWPCkIgQR4cWMYW+JgRCjtF/fg3wKZgRKOKYAkeMT0xAztgi/iKvlHNlHOo0s7sWBWMCLuRxSUCCI2VESkLEpeIUFGS8okGDnIH4ZhTkeORMiPFImTGiQZc2p/QZMyHH0VakkplPypCCawLld2ZRdmZAREJurK5ICMXTiV8k7w6nOLpksl2PfLoR4Usc38m75JbK9is8/bo1Zpt5l2wC5upnrK7EurnWBMe6LfO2+Fa44BXuXv3ZZPL+HoX6XyjyBVeaf6hJJWKS4NwuLXwpyHePcRzp3MFXR76nQ58Turyhr3OLHj1anNGnw2v5dunh+JouZxzLoyO8uGtLMWf8gOMbOrIpY0fWn8XEIn4mM3Xn4jhTHVMy9bxk7qnWSBXefcLlDqUb6sjlM9AelZZO80u0ZwEjU0UmhlP1cqmN3PoXmiKmqqWc7e19uQ1z273lFt+QaodLtS44lZNbMHrfVL13NHOtH4+AkJQLWQxImdKg4Ea8zwm4IsZxrO6daEsKWiufMs+NVBIxFYMOieLMyPQ3MN34xn2woXtnb0ko/5Lp5aqq+2Rx6tXtjN6oe8s737ocrU2gYVNN19Q0ENfEtB9pp9b5+/LN9bqlPOWIlJjwXy/AMzya7HPAIWNlGOhmbq9DUy9Ek5ccqvpLIlkNpefIIhzg8ZwDDnjJ83f6uGTijItbcVnP3eKYI7ocflAVC/suR7xeffv/rL+LaVO1OJ6uTi/uPcUnd1DrF9qz2/eyp4mVk5hbtNutOCNgWnJxu+s1ucd4/wAAAP//AQAA///0t09ReJxiYGYAg//nGIwYsAAAAAAA//8BAAD//y8BAgMAAAA=");
}]]></style><style type="text/css"><![CDATA[.shape {
shape-rendering: geometricPrecision;
@ -18,78 +18,78 @@
opacity: 0.5;
}
.d2-3054270525 .fill-N1{fill:#0A0F25;}
.d2-3054270525 .fill-N2{fill:#676C7E;}
.d2-3054270525 .fill-N3{fill:#9499AB;}
.d2-3054270525 .fill-N4{fill:#CFD2DD;}
.d2-3054270525 .fill-N5{fill:#DEE1EB;}
.d2-3054270525 .fill-N6{fill:#EEF1F8;}
.d2-3054270525 .fill-N7{fill:#FFFFFF;}
.d2-3054270525 .fill-B1{fill:#0D32B2;}
.d2-3054270525 .fill-B2{fill:#0D32B2;}
.d2-3054270525 .fill-B3{fill:#E3E9FD;}
.d2-3054270525 .fill-B4{fill:#E3E9FD;}
.d2-3054270525 .fill-B5{fill:#EDF0FD;}
.d2-3054270525 .fill-B6{fill:#F7F8FE;}
.d2-3054270525 .fill-AA2{fill:#4A6FF3;}
.d2-3054270525 .fill-AA4{fill:#EDF0FD;}
.d2-3054270525 .fill-AA5{fill:#F7F8FE;}
.d2-3054270525 .fill-AB4{fill:#EDF0FD;}
.d2-3054270525 .fill-AB5{fill:#F7F8FE;}
.d2-3054270525 .stroke-N1{stroke:#0A0F25;}
.d2-3054270525 .stroke-N2{stroke:#676C7E;}
.d2-3054270525 .stroke-N3{stroke:#9499AB;}
.d2-3054270525 .stroke-N4{stroke:#CFD2DD;}
.d2-3054270525 .stroke-N5{stroke:#DEE1EB;}
.d2-3054270525 .stroke-N6{stroke:#EEF1F8;}
.d2-3054270525 .stroke-N7{stroke:#FFFFFF;}
.d2-3054270525 .stroke-B1{stroke:#0D32B2;}
.d2-3054270525 .stroke-B2{stroke:#0D32B2;}
.d2-3054270525 .stroke-B3{stroke:#E3E9FD;}
.d2-3054270525 .stroke-B4{stroke:#E3E9FD;}
.d2-3054270525 .stroke-B5{stroke:#EDF0FD;}
.d2-3054270525 .stroke-B6{stroke:#F7F8FE;}
.d2-3054270525 .stroke-AA2{stroke:#4A6FF3;}
.d2-3054270525 .stroke-AA4{stroke:#EDF0FD;}
.d2-3054270525 .stroke-AA5{stroke:#F7F8FE;}
.d2-3054270525 .stroke-AB4{stroke:#EDF0FD;}
.d2-3054270525 .stroke-AB5{stroke:#F7F8FE;}
.d2-3054270525 .background-color-N1{background-color:#0A0F25;}
.d2-3054270525 .background-color-N2{background-color:#676C7E;}
.d2-3054270525 .background-color-N3{background-color:#9499AB;}
.d2-3054270525 .background-color-N4{background-color:#CFD2DD;}
.d2-3054270525 .background-color-N5{background-color:#DEE1EB;}
.d2-3054270525 .background-color-N6{background-color:#EEF1F8;}
.d2-3054270525 .background-color-N7{background-color:#FFFFFF;}
.d2-3054270525 .background-color-B1{background-color:#0D32B2;}
.d2-3054270525 .background-color-B2{background-color:#0D32B2;}
.d2-3054270525 .background-color-B3{background-color:#E3E9FD;}
.d2-3054270525 .background-color-B4{background-color:#E3E9FD;}
.d2-3054270525 .background-color-B5{background-color:#EDF0FD;}
.d2-3054270525 .background-color-B6{background-color:#F7F8FE;}
.d2-3054270525 .background-color-AA2{background-color:#4A6FF3;}
.d2-3054270525 .background-color-AA4{background-color:#EDF0FD;}
.d2-3054270525 .background-color-AA5{background-color:#F7F8FE;}
.d2-3054270525 .background-color-AB4{background-color:#EDF0FD;}
.d2-3054270525 .background-color-AB5{background-color:#F7F8FE;}
.d2-3054270525 .color-N1{color:#0A0F25;}
.d2-3054270525 .color-N2{color:#676C7E;}
.d2-3054270525 .color-N3{color:#9499AB;}
.d2-3054270525 .color-N4{color:#CFD2DD;}
.d2-3054270525 .color-N5{color:#DEE1EB;}
.d2-3054270525 .color-N6{color:#EEF1F8;}
.d2-3054270525 .color-N7{color:#FFFFFF;}
.d2-3054270525 .color-B1{color:#0D32B2;}
.d2-3054270525 .color-B2{color:#0D32B2;}
.d2-3054270525 .color-B3{color:#E3E9FD;}
.d2-3054270525 .color-B4{color:#E3E9FD;}
.d2-3054270525 .color-B5{color:#EDF0FD;}
.d2-3054270525 .color-B6{color:#F7F8FE;}
.d2-3054270525 .color-AA2{color:#4A6FF3;}
.d2-3054270525 .color-AA4{color:#EDF0FD;}
.d2-3054270525 .color-AA5{color:#F7F8FE;}
.d2-3054270525 .color-AB4{color:#EDF0FD;}
.d2-3054270525 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="meow"><g class="shape" ><rect x="0.000000" y="0.000000" width="88.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="44.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">meow</text></g><mask id="d2-3054270525" maskUnits="userSpaceOnUse" x="-101" y="-101" width="290" height="268">
.d2-3109420268 .fill-N1{fill:#0A0F25;}
.d2-3109420268 .fill-N2{fill:#676C7E;}
.d2-3109420268 .fill-N3{fill:#9499AB;}
.d2-3109420268 .fill-N4{fill:#CFD2DD;}
.d2-3109420268 .fill-N5{fill:#DEE1EB;}
.d2-3109420268 .fill-N6{fill:#EEF1F8;}
.d2-3109420268 .fill-N7{fill:#FFFFFF;}
.d2-3109420268 .fill-B1{fill:#0D32B2;}
.d2-3109420268 .fill-B2{fill:#0D32B2;}
.d2-3109420268 .fill-B3{fill:#E3E9FD;}
.d2-3109420268 .fill-B4{fill:#E3E9FD;}
.d2-3109420268 .fill-B5{fill:#EDF0FD;}
.d2-3109420268 .fill-B6{fill:#F7F8FE;}
.d2-3109420268 .fill-AA2{fill:#4A6FF3;}
.d2-3109420268 .fill-AA4{fill:#EDF0FD;}
.d2-3109420268 .fill-AA5{fill:#F7F8FE;}
.d2-3109420268 .fill-AB4{fill:#EDF0FD;}
.d2-3109420268 .fill-AB5{fill:#F7F8FE;}
.d2-3109420268 .stroke-N1{stroke:#0A0F25;}
.d2-3109420268 .stroke-N2{stroke:#676C7E;}
.d2-3109420268 .stroke-N3{stroke:#9499AB;}
.d2-3109420268 .stroke-N4{stroke:#CFD2DD;}
.d2-3109420268 .stroke-N5{stroke:#DEE1EB;}
.d2-3109420268 .stroke-N6{stroke:#EEF1F8;}
.d2-3109420268 .stroke-N7{stroke:#FFFFFF;}
.d2-3109420268 .stroke-B1{stroke:#0D32B2;}
.d2-3109420268 .stroke-B2{stroke:#0D32B2;}
.d2-3109420268 .stroke-B3{stroke:#E3E9FD;}
.d2-3109420268 .stroke-B4{stroke:#E3E9FD;}
.d2-3109420268 .stroke-B5{stroke:#EDF0FD;}
.d2-3109420268 .stroke-B6{stroke:#F7F8FE;}
.d2-3109420268 .stroke-AA2{stroke:#4A6FF3;}
.d2-3109420268 .stroke-AA4{stroke:#EDF0FD;}
.d2-3109420268 .stroke-AA5{stroke:#F7F8FE;}
.d2-3109420268 .stroke-AB4{stroke:#EDF0FD;}
.d2-3109420268 .stroke-AB5{stroke:#F7F8FE;}
.d2-3109420268 .background-color-N1{background-color:#0A0F25;}
.d2-3109420268 .background-color-N2{background-color:#676C7E;}
.d2-3109420268 .background-color-N3{background-color:#9499AB;}
.d2-3109420268 .background-color-N4{background-color:#CFD2DD;}
.d2-3109420268 .background-color-N5{background-color:#DEE1EB;}
.d2-3109420268 .background-color-N6{background-color:#EEF1F8;}
.d2-3109420268 .background-color-N7{background-color:#FFFFFF;}
.d2-3109420268 .background-color-B1{background-color:#0D32B2;}
.d2-3109420268 .background-color-B2{background-color:#0D32B2;}
.d2-3109420268 .background-color-B3{background-color:#E3E9FD;}
.d2-3109420268 .background-color-B4{background-color:#E3E9FD;}
.d2-3109420268 .background-color-B5{background-color:#EDF0FD;}
.d2-3109420268 .background-color-B6{background-color:#F7F8FE;}
.d2-3109420268 .background-color-AA2{background-color:#4A6FF3;}
.d2-3109420268 .background-color-AA4{background-color:#EDF0FD;}
.d2-3109420268 .background-color-AA5{background-color:#F7F8FE;}
.d2-3109420268 .background-color-AB4{background-color:#EDF0FD;}
.d2-3109420268 .background-color-AB5{background-color:#F7F8FE;}
.d2-3109420268 .color-N1{color:#0A0F25;}
.d2-3109420268 .color-N2{color:#676C7E;}
.d2-3109420268 .color-N3{color:#9499AB;}
.d2-3109420268 .color-N4{color:#CFD2DD;}
.d2-3109420268 .color-N5{color:#DEE1EB;}
.d2-3109420268 .color-N6{color:#EEF1F8;}
.d2-3109420268 .color-N7{color:#FFFFFF;}
.d2-3109420268 .color-B1{color:#0D32B2;}
.d2-3109420268 .color-B2{color:#0D32B2;}
.d2-3109420268 .color-B3{color:#E3E9FD;}
.d2-3109420268 .color-B4{color:#E3E9FD;}
.d2-3109420268 .color-B5{color:#EDF0FD;}
.d2-3109420268 .color-B6{color:#F7F8FE;}
.d2-3109420268 .color-AA2{color:#4A6FF3;}
.d2-3109420268 .color-AA4{color:#EDF0FD;}
.d2-3109420268 .color-AA5{color:#F7F8FE;}
.d2-3109420268 .color-AB4{color:#EDF0FD;}
.d2-3109420268 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="meow"><g class="shape" ><rect x="0.000000" y="0.000000" width="88.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="44.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">meow</text></g><mask id="d2-3109420268" maskUnits="userSpaceOnUse" x="-101" y="-101" width="290" height="268">
<rect x="-101" y="-101" width="290" height="268" fill="white"></rect>
<rect x="22.500000" y="22.500000" width="43" height="21" fill="rgba(0,0,0,0.75)"></rect>
</mask></svg></svg>

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

View file

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 305 285"><svg id="d2-svg" class="d2-1655546234" width="305" height="285" viewBox="-101 -118 305 285"><rect x="-101.000000" y="-118.000000" width="305.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 305 285"><svg id="d2-svg" class="d2-4088621414" width="305" height="285" viewBox="-101 -118 305 285"><rect x="-101.000000" y="-118.000000" width="305.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.appendix-icon {
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
}
.d2-1655546234 .text-bold {
font-family: "d2-1655546234-font-bold";
.d2-4088621414 .text-bold {
font-family: "d2-4088621414-font-bold";
}
@font-face {
font-family: d2-1655546234-font-bold;
font-family: d2-4088621414-font-bold;
src: url("data:application/font-woff;base64,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");
}]]></style><style type="text/css"><![CDATA[.shape {
shape-rendering: geometricPrecision;
@ -21,78 +21,78 @@
opacity: 0.5;
}
.d2-1655546234 .fill-N1{fill:#0A0F25;}
.d2-1655546234 .fill-N2{fill:#676C7E;}
.d2-1655546234 .fill-N3{fill:#9499AB;}
.d2-1655546234 .fill-N4{fill:#CFD2DD;}
.d2-1655546234 .fill-N5{fill:#DEE1EB;}
.d2-1655546234 .fill-N6{fill:#EEF1F8;}
.d2-1655546234 .fill-N7{fill:#FFFFFF;}
.d2-1655546234 .fill-B1{fill:#0D32B2;}
.d2-1655546234 .fill-B2{fill:#0D32B2;}
.d2-1655546234 .fill-B3{fill:#E3E9FD;}
.d2-1655546234 .fill-B4{fill:#E3E9FD;}
.d2-1655546234 .fill-B5{fill:#EDF0FD;}
.d2-1655546234 .fill-B6{fill:#F7F8FE;}
.d2-1655546234 .fill-AA2{fill:#4A6FF3;}
.d2-1655546234 .fill-AA4{fill:#EDF0FD;}
.d2-1655546234 .fill-AA5{fill:#F7F8FE;}
.d2-1655546234 .fill-AB4{fill:#EDF0FD;}
.d2-1655546234 .fill-AB5{fill:#F7F8FE;}
.d2-1655546234 .stroke-N1{stroke:#0A0F25;}
.d2-1655546234 .stroke-N2{stroke:#676C7E;}
.d2-1655546234 .stroke-N3{stroke:#9499AB;}
.d2-1655546234 .stroke-N4{stroke:#CFD2DD;}
.d2-1655546234 .stroke-N5{stroke:#DEE1EB;}
.d2-1655546234 .stroke-N6{stroke:#EEF1F8;}
.d2-1655546234 .stroke-N7{stroke:#FFFFFF;}
.d2-1655546234 .stroke-B1{stroke:#0D32B2;}
.d2-1655546234 .stroke-B2{stroke:#0D32B2;}
.d2-1655546234 .stroke-B3{stroke:#E3E9FD;}
.d2-1655546234 .stroke-B4{stroke:#E3E9FD;}
.d2-1655546234 .stroke-B5{stroke:#EDF0FD;}
.d2-1655546234 .stroke-B6{stroke:#F7F8FE;}
.d2-1655546234 .stroke-AA2{stroke:#4A6FF3;}
.d2-1655546234 .stroke-AA4{stroke:#EDF0FD;}
.d2-1655546234 .stroke-AA5{stroke:#F7F8FE;}
.d2-1655546234 .stroke-AB4{stroke:#EDF0FD;}
.d2-1655546234 .stroke-AB5{stroke:#F7F8FE;}
.d2-1655546234 .background-color-N1{background-color:#0A0F25;}
.d2-1655546234 .background-color-N2{background-color:#676C7E;}
.d2-1655546234 .background-color-N3{background-color:#9499AB;}
.d2-1655546234 .background-color-N4{background-color:#CFD2DD;}
.d2-1655546234 .background-color-N5{background-color:#DEE1EB;}
.d2-1655546234 .background-color-N6{background-color:#EEF1F8;}
.d2-1655546234 .background-color-N7{background-color:#FFFFFF;}
.d2-1655546234 .background-color-B1{background-color:#0D32B2;}
.d2-1655546234 .background-color-B2{background-color:#0D32B2;}
.d2-1655546234 .background-color-B3{background-color:#E3E9FD;}
.d2-1655546234 .background-color-B4{background-color:#E3E9FD;}
.d2-1655546234 .background-color-B5{background-color:#EDF0FD;}
.d2-1655546234 .background-color-B6{background-color:#F7F8FE;}
.d2-1655546234 .background-color-AA2{background-color:#4A6FF3;}
.d2-1655546234 .background-color-AA4{background-color:#EDF0FD;}
.d2-1655546234 .background-color-AA5{background-color:#F7F8FE;}
.d2-1655546234 .background-color-AB4{background-color:#EDF0FD;}
.d2-1655546234 .background-color-AB5{background-color:#F7F8FE;}
.d2-1655546234 .color-N1{color:#0A0F25;}
.d2-1655546234 .color-N2{color:#676C7E;}
.d2-1655546234 .color-N3{color:#9499AB;}
.d2-1655546234 .color-N4{color:#CFD2DD;}
.d2-1655546234 .color-N5{color:#DEE1EB;}
.d2-1655546234 .color-N6{color:#EEF1F8;}
.d2-1655546234 .color-N7{color:#FFFFFF;}
.d2-1655546234 .color-B1{color:#0D32B2;}
.d2-1655546234 .color-B2{color:#0D32B2;}
.d2-1655546234 .color-B3{color:#E3E9FD;}
.d2-1655546234 .color-B4{color:#E3E9FD;}
.d2-1655546234 .color-B5{color:#EDF0FD;}
.d2-1655546234 .color-B6{color:#F7F8FE;}
.d2-1655546234 .color-AA2{color:#4A6FF3;}
.d2-1655546234 .color-AA4{color:#EDF0FD;}
.d2-1655546234 .color-AA5{color:#F7F8FE;}
.d2-1655546234 .color-AB4{color:#EDF0FD;}
.d2-1655546234 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><a href="y.svg" xlink:href="y.svg"><g id="y"><g class="shape" ><rect x="0.000000" y="0.000000" width="86.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="43.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text></g></a><g transform="translate(70 -16)" class="appendix-icon"><svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
.d2-4088621414 .fill-N1{fill:#0A0F25;}
.d2-4088621414 .fill-N2{fill:#676C7E;}
.d2-4088621414 .fill-N3{fill:#9499AB;}
.d2-4088621414 .fill-N4{fill:#CFD2DD;}
.d2-4088621414 .fill-N5{fill:#DEE1EB;}
.d2-4088621414 .fill-N6{fill:#EEF1F8;}
.d2-4088621414 .fill-N7{fill:#FFFFFF;}
.d2-4088621414 .fill-B1{fill:#0D32B2;}
.d2-4088621414 .fill-B2{fill:#0D32B2;}
.d2-4088621414 .fill-B3{fill:#E3E9FD;}
.d2-4088621414 .fill-B4{fill:#E3E9FD;}
.d2-4088621414 .fill-B5{fill:#EDF0FD;}
.d2-4088621414 .fill-B6{fill:#F7F8FE;}
.d2-4088621414 .fill-AA2{fill:#4A6FF3;}
.d2-4088621414 .fill-AA4{fill:#EDF0FD;}
.d2-4088621414 .fill-AA5{fill:#F7F8FE;}
.d2-4088621414 .fill-AB4{fill:#EDF0FD;}
.d2-4088621414 .fill-AB5{fill:#F7F8FE;}
.d2-4088621414 .stroke-N1{stroke:#0A0F25;}
.d2-4088621414 .stroke-N2{stroke:#676C7E;}
.d2-4088621414 .stroke-N3{stroke:#9499AB;}
.d2-4088621414 .stroke-N4{stroke:#CFD2DD;}
.d2-4088621414 .stroke-N5{stroke:#DEE1EB;}
.d2-4088621414 .stroke-N6{stroke:#EEF1F8;}
.d2-4088621414 .stroke-N7{stroke:#FFFFFF;}
.d2-4088621414 .stroke-B1{stroke:#0D32B2;}
.d2-4088621414 .stroke-B2{stroke:#0D32B2;}
.d2-4088621414 .stroke-B3{stroke:#E3E9FD;}
.d2-4088621414 .stroke-B4{stroke:#E3E9FD;}
.d2-4088621414 .stroke-B5{stroke:#EDF0FD;}
.d2-4088621414 .stroke-B6{stroke:#F7F8FE;}
.d2-4088621414 .stroke-AA2{stroke:#4A6FF3;}
.d2-4088621414 .stroke-AA4{stroke:#EDF0FD;}
.d2-4088621414 .stroke-AA5{stroke:#F7F8FE;}
.d2-4088621414 .stroke-AB4{stroke:#EDF0FD;}
.d2-4088621414 .stroke-AB5{stroke:#F7F8FE;}
.d2-4088621414 .background-color-N1{background-color:#0A0F25;}
.d2-4088621414 .background-color-N2{background-color:#676C7E;}
.d2-4088621414 .background-color-N3{background-color:#9499AB;}
.d2-4088621414 .background-color-N4{background-color:#CFD2DD;}
.d2-4088621414 .background-color-N5{background-color:#DEE1EB;}
.d2-4088621414 .background-color-N6{background-color:#EEF1F8;}
.d2-4088621414 .background-color-N7{background-color:#FFFFFF;}
.d2-4088621414 .background-color-B1{background-color:#0D32B2;}
.d2-4088621414 .background-color-B2{background-color:#0D32B2;}
.d2-4088621414 .background-color-B3{background-color:#E3E9FD;}
.d2-4088621414 .background-color-B4{background-color:#E3E9FD;}
.d2-4088621414 .background-color-B5{background-color:#EDF0FD;}
.d2-4088621414 .background-color-B6{background-color:#F7F8FE;}
.d2-4088621414 .background-color-AA2{background-color:#4A6FF3;}
.d2-4088621414 .background-color-AA4{background-color:#EDF0FD;}
.d2-4088621414 .background-color-AA5{background-color:#F7F8FE;}
.d2-4088621414 .background-color-AB4{background-color:#EDF0FD;}
.d2-4088621414 .background-color-AB5{background-color:#F7F8FE;}
.d2-4088621414 .color-N1{color:#0A0F25;}
.d2-4088621414 .color-N2{color:#676C7E;}
.d2-4088621414 .color-N3{color:#9499AB;}
.d2-4088621414 .color-N4{color:#CFD2DD;}
.d2-4088621414 .color-N5{color:#DEE1EB;}
.d2-4088621414 .color-N6{color:#EEF1F8;}
.d2-4088621414 .color-N7{color:#FFFFFF;}
.d2-4088621414 .color-B1{color:#0D32B2;}
.d2-4088621414 .color-B2{color:#0D32B2;}
.d2-4088621414 .color-B3{color:#E3E9FD;}
.d2-4088621414 .color-B4{color:#E3E9FD;}
.d2-4088621414 .color-B5{color:#EDF0FD;}
.d2-4088621414 .color-B6{color:#F7F8FE;}
.d2-4088621414 .color-AA2{color:#4A6FF3;}
.d2-4088621414 .color-AA4{color:#EDF0FD;}
.d2-4088621414 .color-AA5{color:#F7F8FE;}
.d2-4088621414 .color-AB4{color:#EDF0FD;}
.d2-4088621414 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><a href="y.svg" xlink:href="y.svg"><g id="y"><g class="shape" ><rect x="0.000000" y="0.000000" width="86.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="43.000000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text></g></a><g transform="translate(70 -16)" class="appendix-icon"><svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_3440_35088111)">
<path d="M16 31.1109C24.3456 31.1109 31.1111 24.3454 31.1111 15.9998C31.1111 7.65415 24.3456 0.888672 16 0.888672C7.65436 0.888672 0.888885 7.65415 0.888885 15.9998C0.888885 24.3454 7.65436 31.1109 16 31.1109Z" fill="white" stroke="#DEE1EB"/>
<path d="M14.3909 16.7965C14.7364 17.2584 15.1772 17.6406 15.6834 17.9171C16.1896 18.1938 16.7494 18.3582 17.3248 18.3993C17.9001 18.4405 18.4777 18.3575 19.0181 18.1559C19.5586 17.9543 20.0492 17.6389 20.4571 17.2309L22.8708 14.8173C23.6036 14.0586 24.0089 13.0425 23.9998 11.9877C23.9906 10.933 23.5676 9.92404 22.8217 9.17821C22.0759 8.43237 21.067 8.00931 20.0123 8.00015C18.9575 7.99098 17.9413 8.39644 17.1827 9.1292L15.7988 10.505" stroke="#2E3346" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
@ -104,7 +104,7 @@
</clipPath>
</defs>
</svg>
</g><mask id="d2-1655546234" maskUnits="userSpaceOnUse" x="-101" y="-118" width="305" height="285">
</g><mask id="d2-4088621414" maskUnits="userSpaceOnUse" x="-101" y="-118" width="305" height="285">
<rect x="-101" y="-118" width="305" height="285" fill="white"></rect>
<rect x="38.500000" y="22.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
</mask></svg></svg>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 304 285"><svg id="d2-svg" class="d2-3111330921" width="304" height="285" viewBox="-101 -118 304 285"><rect x="-101.000000" y="-118.000000" width="304.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 304 285"><svg id="d2-svg" class="d2-1416247347" width="304" height="285" viewBox="-101 -118 304 285"><rect x="-101.000000" y="-118.000000" width="304.000000" height="285.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.appendix-icon {
filter: drop-shadow(0px 0px 32px rgba(31, 36, 58, 0.1));
}
.d2-3111330921 .text-bold {
font-family: "d2-3111330921-font-bold";
.d2-1416247347 .text-bold {
font-family: "d2-1416247347-font-bold";
}
@font-face {
font-family: d2-3111330921-font-bold;
font-family: d2-1416247347-font-bold;
src: url("data:application/font-woff;base64,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");
}]]></style><style type="text/css"><![CDATA[.shape {
shape-rendering: geometricPrecision;
@ -21,78 +21,78 @@
opacity: 0.5;
}
.d2-3111330921 .fill-N1{fill:#0A0F25;}
.d2-3111330921 .fill-N2{fill:#676C7E;}
.d2-3111330921 .fill-N3{fill:#9499AB;}
.d2-3111330921 .fill-N4{fill:#CFD2DD;}
.d2-3111330921 .fill-N5{fill:#DEE1EB;}
.d2-3111330921 .fill-N6{fill:#EEF1F8;}
.d2-3111330921 .fill-N7{fill:#FFFFFF;}
.d2-3111330921 .fill-B1{fill:#0D32B2;}
.d2-3111330921 .fill-B2{fill:#0D32B2;}
.d2-3111330921 .fill-B3{fill:#E3E9FD;}
.d2-3111330921 .fill-B4{fill:#E3E9FD;}
.d2-3111330921 .fill-B5{fill:#EDF0FD;}
.d2-3111330921 .fill-B6{fill:#F7F8FE;}
.d2-3111330921 .fill-AA2{fill:#4A6FF3;}
.d2-3111330921 .fill-AA4{fill:#EDF0FD;}
.d2-3111330921 .fill-AA5{fill:#F7F8FE;}
.d2-3111330921 .fill-AB4{fill:#EDF0FD;}
.d2-3111330921 .fill-AB5{fill:#F7F8FE;}
.d2-3111330921 .stroke-N1{stroke:#0A0F25;}
.d2-3111330921 .stroke-N2{stroke:#676C7E;}
.d2-3111330921 .stroke-N3{stroke:#9499AB;}
.d2-3111330921 .stroke-N4{stroke:#CFD2DD;}
.d2-3111330921 .stroke-N5{stroke:#DEE1EB;}
.d2-3111330921 .stroke-N6{stroke:#EEF1F8;}
.d2-3111330921 .stroke-N7{stroke:#FFFFFF;}
.d2-3111330921 .stroke-B1{stroke:#0D32B2;}
.d2-3111330921 .stroke-B2{stroke:#0D32B2;}
.d2-3111330921 .stroke-B3{stroke:#E3E9FD;}
.d2-3111330921 .stroke-B4{stroke:#E3E9FD;}
.d2-3111330921 .stroke-B5{stroke:#EDF0FD;}
.d2-3111330921 .stroke-B6{stroke:#F7F8FE;}
.d2-3111330921 .stroke-AA2{stroke:#4A6FF3;}
.d2-3111330921 .stroke-AA4{stroke:#EDF0FD;}
.d2-3111330921 .stroke-AA5{stroke:#F7F8FE;}
.d2-3111330921 .stroke-AB4{stroke:#EDF0FD;}
.d2-3111330921 .stroke-AB5{stroke:#F7F8FE;}
.d2-3111330921 .background-color-N1{background-color:#0A0F25;}
.d2-3111330921 .background-color-N2{background-color:#676C7E;}
.d2-3111330921 .background-color-N3{background-color:#9499AB;}
.d2-3111330921 .background-color-N4{background-color:#CFD2DD;}
.d2-3111330921 .background-color-N5{background-color:#DEE1EB;}
.d2-3111330921 .background-color-N6{background-color:#EEF1F8;}
.d2-3111330921 .background-color-N7{background-color:#FFFFFF;}
.d2-3111330921 .background-color-B1{background-color:#0D32B2;}
.d2-3111330921 .background-color-B2{background-color:#0D32B2;}
.d2-3111330921 .background-color-B3{background-color:#E3E9FD;}
.d2-3111330921 .background-color-B4{background-color:#E3E9FD;}
.d2-3111330921 .background-color-B5{background-color:#EDF0FD;}
.d2-3111330921 .background-color-B6{background-color:#F7F8FE;}
.d2-3111330921 .background-color-AA2{background-color:#4A6FF3;}
.d2-3111330921 .background-color-AA4{background-color:#EDF0FD;}
.d2-3111330921 .background-color-AA5{background-color:#F7F8FE;}
.d2-3111330921 .background-color-AB4{background-color:#EDF0FD;}
.d2-3111330921 .background-color-AB5{background-color:#F7F8FE;}
.d2-3111330921 .color-N1{color:#0A0F25;}
.d2-3111330921 .color-N2{color:#676C7E;}
.d2-3111330921 .color-N3{color:#9499AB;}
.d2-3111330921 .color-N4{color:#CFD2DD;}
.d2-3111330921 .color-N5{color:#DEE1EB;}
.d2-3111330921 .color-N6{color:#EEF1F8;}
.d2-3111330921 .color-N7{color:#FFFFFF;}
.d2-3111330921 .color-B1{color:#0D32B2;}
.d2-3111330921 .color-B2{color:#0D32B2;}
.d2-3111330921 .color-B3{color:#E3E9FD;}
.d2-3111330921 .color-B4{color:#E3E9FD;}
.d2-3111330921 .color-B5{color:#EDF0FD;}
.d2-3111330921 .color-B6{color:#F7F8FE;}
.d2-3111330921 .color-AA2{color:#4A6FF3;}
.d2-3111330921 .color-AA4{color:#EDF0FD;}
.d2-3111330921 .color-AA5{color:#F7F8FE;}
.d2-3111330921 .color-AB4{color:#EDF0FD;}
.d2-3111330921 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><a href="x/index.svg" xlink:href="x/index.svg"><g id="x"><g class="shape" ><rect x="0.000000" y="0.000000" width="85.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="42.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text></g></a><g transform="translate(69 -16)" class="appendix-icon"><svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
.d2-1416247347 .fill-N1{fill:#0A0F25;}
.d2-1416247347 .fill-N2{fill:#676C7E;}
.d2-1416247347 .fill-N3{fill:#9499AB;}
.d2-1416247347 .fill-N4{fill:#CFD2DD;}
.d2-1416247347 .fill-N5{fill:#DEE1EB;}
.d2-1416247347 .fill-N6{fill:#EEF1F8;}
.d2-1416247347 .fill-N7{fill:#FFFFFF;}
.d2-1416247347 .fill-B1{fill:#0D32B2;}
.d2-1416247347 .fill-B2{fill:#0D32B2;}
.d2-1416247347 .fill-B3{fill:#E3E9FD;}
.d2-1416247347 .fill-B4{fill:#E3E9FD;}
.d2-1416247347 .fill-B5{fill:#EDF0FD;}
.d2-1416247347 .fill-B6{fill:#F7F8FE;}
.d2-1416247347 .fill-AA2{fill:#4A6FF3;}
.d2-1416247347 .fill-AA4{fill:#EDF0FD;}
.d2-1416247347 .fill-AA5{fill:#F7F8FE;}
.d2-1416247347 .fill-AB4{fill:#EDF0FD;}
.d2-1416247347 .fill-AB5{fill:#F7F8FE;}
.d2-1416247347 .stroke-N1{stroke:#0A0F25;}
.d2-1416247347 .stroke-N2{stroke:#676C7E;}
.d2-1416247347 .stroke-N3{stroke:#9499AB;}
.d2-1416247347 .stroke-N4{stroke:#CFD2DD;}
.d2-1416247347 .stroke-N5{stroke:#DEE1EB;}
.d2-1416247347 .stroke-N6{stroke:#EEF1F8;}
.d2-1416247347 .stroke-N7{stroke:#FFFFFF;}
.d2-1416247347 .stroke-B1{stroke:#0D32B2;}
.d2-1416247347 .stroke-B2{stroke:#0D32B2;}
.d2-1416247347 .stroke-B3{stroke:#E3E9FD;}
.d2-1416247347 .stroke-B4{stroke:#E3E9FD;}
.d2-1416247347 .stroke-B5{stroke:#EDF0FD;}
.d2-1416247347 .stroke-B6{stroke:#F7F8FE;}
.d2-1416247347 .stroke-AA2{stroke:#4A6FF3;}
.d2-1416247347 .stroke-AA4{stroke:#EDF0FD;}
.d2-1416247347 .stroke-AA5{stroke:#F7F8FE;}
.d2-1416247347 .stroke-AB4{stroke:#EDF0FD;}
.d2-1416247347 .stroke-AB5{stroke:#F7F8FE;}
.d2-1416247347 .background-color-N1{background-color:#0A0F25;}
.d2-1416247347 .background-color-N2{background-color:#676C7E;}
.d2-1416247347 .background-color-N3{background-color:#9499AB;}
.d2-1416247347 .background-color-N4{background-color:#CFD2DD;}
.d2-1416247347 .background-color-N5{background-color:#DEE1EB;}
.d2-1416247347 .background-color-N6{background-color:#EEF1F8;}
.d2-1416247347 .background-color-N7{background-color:#FFFFFF;}
.d2-1416247347 .background-color-B1{background-color:#0D32B2;}
.d2-1416247347 .background-color-B2{background-color:#0D32B2;}
.d2-1416247347 .background-color-B3{background-color:#E3E9FD;}
.d2-1416247347 .background-color-B4{background-color:#E3E9FD;}
.d2-1416247347 .background-color-B5{background-color:#EDF0FD;}
.d2-1416247347 .background-color-B6{background-color:#F7F8FE;}
.d2-1416247347 .background-color-AA2{background-color:#4A6FF3;}
.d2-1416247347 .background-color-AA4{background-color:#EDF0FD;}
.d2-1416247347 .background-color-AA5{background-color:#F7F8FE;}
.d2-1416247347 .background-color-AB4{background-color:#EDF0FD;}
.d2-1416247347 .background-color-AB5{background-color:#F7F8FE;}
.d2-1416247347 .color-N1{color:#0A0F25;}
.d2-1416247347 .color-N2{color:#676C7E;}
.d2-1416247347 .color-N3{color:#9499AB;}
.d2-1416247347 .color-N4{color:#CFD2DD;}
.d2-1416247347 .color-N5{color:#DEE1EB;}
.d2-1416247347 .color-N6{color:#EEF1F8;}
.d2-1416247347 .color-N7{color:#FFFFFF;}
.d2-1416247347 .color-B1{color:#0D32B2;}
.d2-1416247347 .color-B2{color:#0D32B2;}
.d2-1416247347 .color-B3{color:#E3E9FD;}
.d2-1416247347 .color-B4{color:#E3E9FD;}
.d2-1416247347 .color-B5{color:#EDF0FD;}
.d2-1416247347 .color-B6{color:#F7F8FE;}
.d2-1416247347 .color-AA2{color:#4A6FF3;}
.d2-1416247347 .color-AA4{color:#EDF0FD;}
.d2-1416247347 .color-AA5{color:#F7F8FE;}
.d2-1416247347 .color-AB4{color:#EDF0FD;}
.d2-1416247347 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><a href="x/index.svg" xlink:href="x/index.svg"><g id="x"><g class="shape" ><rect x="0.000000" y="0.000000" width="85.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="42.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text></g></a><g transform="translate(69 -16)" class="appendix-icon"><svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_3440_35088111)">
<path d="M16 31.1109C24.3456 31.1109 31.1111 24.3454 31.1111 15.9998C31.1111 7.65415 24.3456 0.888672 16 0.888672C7.65436 0.888672 0.888885 7.65415 0.888885 15.9998C0.888885 24.3454 7.65436 31.1109 16 31.1109Z" fill="white" stroke="#DEE1EB"/>
<path d="M14.3909 16.7965C14.7364 17.2584 15.1772 17.6406 15.6834 17.9171C16.1896 18.1938 16.7494 18.3582 17.3248 18.3993C17.9001 18.4405 18.4777 18.3575 19.0181 18.1559C19.5586 17.9543 20.0492 17.6389 20.4571 17.2309L22.8708 14.8173C23.6036 14.0586 24.0089 13.0425 23.9998 11.9877C23.9906 10.933 23.5676 9.92404 22.8217 9.17821C22.0759 8.43237 21.067 8.00931 20.0123 8.00015C18.9575 7.99098 17.9413 8.39644 17.1827 9.1292L15.7988 10.505" stroke="#2E3346" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
@ -104,7 +104,7 @@
</clipPath>
</defs>
</svg>
</g><mask id="d2-3111330921" maskUnits="userSpaceOnUse" x="-101" y="-118" width="304" height="285">
</g><mask id="d2-1416247347" maskUnits="userSpaceOnUse" x="-101" y="-118" width="304" height="285">
<rect x="-101" y="-118" width="304" height="285" fill="white"></rect>
<rect x="38.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
</mask></svg></svg>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-1843626214" width="256" height="434" viewBox="-101 -101 256 434"><rect x="-101.000000" y="-101.000000" width="256.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 434"><svg id="d2-svg" class="d2-1843626214" width="256" height="434" viewBox="-101 -101 256 434"><rect x="-101.000000" y="-101.000000" width="256.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-1843626214 .text-bold {
font-family: "d2-1843626214-font-bold";
}

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 290 268"><svg id="d2-svg" class="d2-3054270525" width="290" height="268" viewBox="-101 -101 290 268"><rect x="-101.000000" y="-101.000000" width="290.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 290 268"><svg id="d2-svg" class="d2-3054270525" width="290" height="268" viewBox="-101 -101 290 268"><rect x="-101.000000" y="-101.000000" width="290.000000" height="268.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-3054270525 .text-bold {
font-family: "d2-3054270525-font-bold";
}

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 368 766"><svg id="d2-svg" width="368" height="766" viewBox="-101 -101 368 766"><style type="text/css"><![CDATA[
.d2-2543050356 .text-bold {
font-family: "d2-2543050356-font-bold";
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 368 766"><svg id="d2-svg" width="368" height="766" viewBox="-101 -101 368 766"><style type="text/css"><![CDATA[
.d2-1574744994 .text-bold {
font-family: "d2-1574744994-font-bold";
}
@font-face {
font-family: d2-2543050356-font-bold;
font-family: d2-1574744994-font-bold;
src: url("data:application/font-woff;base64,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");
}]]></style><style type="text/css"><![CDATA[.shape {
shape-rendering: geometricPrecision;
@ -18,78 +18,78 @@
opacity: 0.5;
}
.d2-2543050356 .fill-N1{fill:#0A0F25;}
.d2-2543050356 .fill-N2{fill:#676C7E;}
.d2-2543050356 .fill-N3{fill:#9499AB;}
.d2-2543050356 .fill-N4{fill:#CFD2DD;}
.d2-2543050356 .fill-N5{fill:#DEE1EB;}
.d2-2543050356 .fill-N6{fill:#EEF1F8;}
.d2-2543050356 .fill-N7{fill:#FFFFFF;}
.d2-2543050356 .fill-B1{fill:#0D32B2;}
.d2-2543050356 .fill-B2{fill:#0D32B2;}
.d2-2543050356 .fill-B3{fill:#E3E9FD;}
.d2-2543050356 .fill-B4{fill:#E3E9FD;}
.d2-2543050356 .fill-B5{fill:#EDF0FD;}
.d2-2543050356 .fill-B6{fill:#F7F8FE;}
.d2-2543050356 .fill-AA2{fill:#4A6FF3;}
.d2-2543050356 .fill-AA4{fill:#EDF0FD;}
.d2-2543050356 .fill-AA5{fill:#F7F8FE;}
.d2-2543050356 .fill-AB4{fill:#EDF0FD;}
.d2-2543050356 .fill-AB5{fill:#F7F8FE;}
.d2-2543050356 .stroke-N1{stroke:#0A0F25;}
.d2-2543050356 .stroke-N2{stroke:#676C7E;}
.d2-2543050356 .stroke-N3{stroke:#9499AB;}
.d2-2543050356 .stroke-N4{stroke:#CFD2DD;}
.d2-2543050356 .stroke-N5{stroke:#DEE1EB;}
.d2-2543050356 .stroke-N6{stroke:#EEF1F8;}
.d2-2543050356 .stroke-N7{stroke:#FFFFFF;}
.d2-2543050356 .stroke-B1{stroke:#0D32B2;}
.d2-2543050356 .stroke-B2{stroke:#0D32B2;}
.d2-2543050356 .stroke-B3{stroke:#E3E9FD;}
.d2-2543050356 .stroke-B4{stroke:#E3E9FD;}
.d2-2543050356 .stroke-B5{stroke:#EDF0FD;}
.d2-2543050356 .stroke-B6{stroke:#F7F8FE;}
.d2-2543050356 .stroke-AA2{stroke:#4A6FF3;}
.d2-2543050356 .stroke-AA4{stroke:#EDF0FD;}
.d2-2543050356 .stroke-AA5{stroke:#F7F8FE;}
.d2-2543050356 .stroke-AB4{stroke:#EDF0FD;}
.d2-2543050356 .stroke-AB5{stroke:#F7F8FE;}
.d2-2543050356 .background-color-N1{background-color:#0A0F25;}
.d2-2543050356 .background-color-N2{background-color:#676C7E;}
.d2-2543050356 .background-color-N3{background-color:#9499AB;}
.d2-2543050356 .background-color-N4{background-color:#CFD2DD;}
.d2-2543050356 .background-color-N5{background-color:#DEE1EB;}
.d2-2543050356 .background-color-N6{background-color:#EEF1F8;}
.d2-2543050356 .background-color-N7{background-color:#FFFFFF;}
.d2-2543050356 .background-color-B1{background-color:#0D32B2;}
.d2-2543050356 .background-color-B2{background-color:#0D32B2;}
.d2-2543050356 .background-color-B3{background-color:#E3E9FD;}
.d2-2543050356 .background-color-B4{background-color:#E3E9FD;}
.d2-2543050356 .background-color-B5{background-color:#EDF0FD;}
.d2-2543050356 .background-color-B6{background-color:#F7F8FE;}
.d2-2543050356 .background-color-AA2{background-color:#4A6FF3;}
.d2-2543050356 .background-color-AA4{background-color:#EDF0FD;}
.d2-2543050356 .background-color-AA5{background-color:#F7F8FE;}
.d2-2543050356 .background-color-AB4{background-color:#EDF0FD;}
.d2-2543050356 .background-color-AB5{background-color:#F7F8FE;}
.d2-2543050356 .color-N1{color:#0A0F25;}
.d2-2543050356 .color-N2{color:#676C7E;}
.d2-2543050356 .color-N3{color:#9499AB;}
.d2-2543050356 .color-N4{color:#CFD2DD;}
.d2-2543050356 .color-N5{color:#DEE1EB;}
.d2-2543050356 .color-N6{color:#EEF1F8;}
.d2-2543050356 .color-N7{color:#FFFFFF;}
.d2-2543050356 .color-B1{color:#0D32B2;}
.d2-2543050356 .color-B2{color:#0D32B2;}
.d2-2543050356 .color-B3{color:#E3E9FD;}
.d2-2543050356 .color-B4{color:#E3E9FD;}
.d2-2543050356 .color-B5{color:#EDF0FD;}
.d2-2543050356 .color-B6{color:#F7F8FE;}
.d2-2543050356 .color-AA2{color:#4A6FF3;}
.d2-2543050356 .color-AA4{color:#EDF0FD;}
.d2-2543050356 .color-AA5{color:#F7F8FE;}
.d2-2543050356 .color-AB4{color:#EDF0FD;}
.d2-2543050356 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><style type="text/css"><![CDATA[@keyframes d2Transition-d2-2543050356-0 {
.d2-1574744994 .fill-N1{fill:#0A0F25;}
.d2-1574744994 .fill-N2{fill:#676C7E;}
.d2-1574744994 .fill-N3{fill:#9499AB;}
.d2-1574744994 .fill-N4{fill:#CFD2DD;}
.d2-1574744994 .fill-N5{fill:#DEE1EB;}
.d2-1574744994 .fill-N6{fill:#EEF1F8;}
.d2-1574744994 .fill-N7{fill:#FFFFFF;}
.d2-1574744994 .fill-B1{fill:#0D32B2;}
.d2-1574744994 .fill-B2{fill:#0D32B2;}
.d2-1574744994 .fill-B3{fill:#E3E9FD;}
.d2-1574744994 .fill-B4{fill:#E3E9FD;}
.d2-1574744994 .fill-B5{fill:#EDF0FD;}
.d2-1574744994 .fill-B6{fill:#F7F8FE;}
.d2-1574744994 .fill-AA2{fill:#4A6FF3;}
.d2-1574744994 .fill-AA4{fill:#EDF0FD;}
.d2-1574744994 .fill-AA5{fill:#F7F8FE;}
.d2-1574744994 .fill-AB4{fill:#EDF0FD;}
.d2-1574744994 .fill-AB5{fill:#F7F8FE;}
.d2-1574744994 .stroke-N1{stroke:#0A0F25;}
.d2-1574744994 .stroke-N2{stroke:#676C7E;}
.d2-1574744994 .stroke-N3{stroke:#9499AB;}
.d2-1574744994 .stroke-N4{stroke:#CFD2DD;}
.d2-1574744994 .stroke-N5{stroke:#DEE1EB;}
.d2-1574744994 .stroke-N6{stroke:#EEF1F8;}
.d2-1574744994 .stroke-N7{stroke:#FFFFFF;}
.d2-1574744994 .stroke-B1{stroke:#0D32B2;}
.d2-1574744994 .stroke-B2{stroke:#0D32B2;}
.d2-1574744994 .stroke-B3{stroke:#E3E9FD;}
.d2-1574744994 .stroke-B4{stroke:#E3E9FD;}
.d2-1574744994 .stroke-B5{stroke:#EDF0FD;}
.d2-1574744994 .stroke-B6{stroke:#F7F8FE;}
.d2-1574744994 .stroke-AA2{stroke:#4A6FF3;}
.d2-1574744994 .stroke-AA4{stroke:#EDF0FD;}
.d2-1574744994 .stroke-AA5{stroke:#F7F8FE;}
.d2-1574744994 .stroke-AB4{stroke:#EDF0FD;}
.d2-1574744994 .stroke-AB5{stroke:#F7F8FE;}
.d2-1574744994 .background-color-N1{background-color:#0A0F25;}
.d2-1574744994 .background-color-N2{background-color:#676C7E;}
.d2-1574744994 .background-color-N3{background-color:#9499AB;}
.d2-1574744994 .background-color-N4{background-color:#CFD2DD;}
.d2-1574744994 .background-color-N5{background-color:#DEE1EB;}
.d2-1574744994 .background-color-N6{background-color:#EEF1F8;}
.d2-1574744994 .background-color-N7{background-color:#FFFFFF;}
.d2-1574744994 .background-color-B1{background-color:#0D32B2;}
.d2-1574744994 .background-color-B2{background-color:#0D32B2;}
.d2-1574744994 .background-color-B3{background-color:#E3E9FD;}
.d2-1574744994 .background-color-B4{background-color:#E3E9FD;}
.d2-1574744994 .background-color-B5{background-color:#EDF0FD;}
.d2-1574744994 .background-color-B6{background-color:#F7F8FE;}
.d2-1574744994 .background-color-AA2{background-color:#4A6FF3;}
.d2-1574744994 .background-color-AA4{background-color:#EDF0FD;}
.d2-1574744994 .background-color-AA5{background-color:#F7F8FE;}
.d2-1574744994 .background-color-AB4{background-color:#EDF0FD;}
.d2-1574744994 .background-color-AB5{background-color:#F7F8FE;}
.d2-1574744994 .color-N1{color:#0A0F25;}
.d2-1574744994 .color-N2{color:#676C7E;}
.d2-1574744994 .color-N3{color:#9499AB;}
.d2-1574744994 .color-N4{color:#CFD2DD;}
.d2-1574744994 .color-N5{color:#DEE1EB;}
.d2-1574744994 .color-N6{color:#EEF1F8;}
.d2-1574744994 .color-N7{color:#FFFFFF;}
.d2-1574744994 .color-B1{color:#0D32B2;}
.d2-1574744994 .color-B2{color:#0D32B2;}
.d2-1574744994 .color-B3{color:#E3E9FD;}
.d2-1574744994 .color-B4{color:#E3E9FD;}
.d2-1574744994 .color-B5{color:#EDF0FD;}
.d2-1574744994 .color-B6{color:#F7F8FE;}
.d2-1574744994 .color-AA2{color:#4A6FF3;}
.d2-1574744994 .color-AA4{color:#EDF0FD;}
.d2-1574744994 .color-AA5{color:#F7F8FE;}
.d2-1574744994 .color-AB4{color:#EDF0FD;}
.d2-1574744994 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><style type="text/css"><![CDATA[@keyframes d2Transition-d2-1574744994-0 {
0%, 0.000000% {
opacity: 0;
}
@ -99,7 +99,7 @@
33.333333%, 100% {
opacity: 0;
}
}@keyframes d2Transition-d2-2543050356-1 {
}@keyframes d2Transition-d2-1574744994-1 {
0%, 33.309524% {
opacity: 0;
}
@ -109,24 +109,24 @@
66.666667%, 100% {
opacity: 0;
}
}@keyframes d2Transition-d2-2543050356-2 {
}@keyframes d2Transition-d2-1574744994-2 {
0%, 66.642857% {
opacity: 0;
}
66.666667%, 100.000000% {
opacity: 1;
}
}]]></style><g style="animation: d2Transition-d2-2543050356-0 4200ms infinite" class="d2-2543050356" width="255" height="434" viewBox="-101 -101 255 434"><rect x="-101.000000" y="-101.000000" width="255.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">a</text></g><g id="b"><g class="shape" ><rect x="0.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">b</text></g><g id="(a -&gt; b)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 26.500000 68.000000 C 26.500000 106.000000 26.500000 126.000000 26.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-3922440645)" /></g><mask id="d2-3922440645" maskUnits="userSpaceOnUse" x="-101" y="-101" width="255" height="434">
}]]></style><g style="animation: d2Transition-d2-1574744994-0 4200ms infinite" class="d2-1574744994" width="255" height="434" viewBox="-101 -101 255 434"><rect x="-101.000000" y="-101.000000" width="255.000000" height="434.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">a</text></g><g id="b"><g class="shape" ><rect x="0.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">b</text></g><g id="(a -&gt; b)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 26.500000 68.000000 C 26.500000 106.000000 26.500000 126.000000 26.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-1919875308)" /></g><mask id="d2-1919875308" maskUnits="userSpaceOnUse" x="-101" y="-101" width="255" height="434">
<rect x="-101" y="-101" width="255" height="434" fill="white"></rect>
<rect x="22.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="22.500000" y="188.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
</mask></g><g style="animation: d2Transition-d2-2543050356-1 4200ms infinite" class="d2-2543050356" width="368" height="600" viewBox="-101 -101 368 600"><rect x="-101.000000" y="-101.000000" width="368.000000" height="600.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">a</text></g><g id="b"><g class="shape" ><rect x="0.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">b</text></g><g id="d"><g class="shape" ><rect x="56.000000" y="332.000000" width="54.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="83.000000" y="370.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">d</text></g><g id="c"><g class="shape" ><rect x="113.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="139.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">c</text></g><g id="(a -&gt; b)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 26.500000 68.000000 C 26.500000 106.000000 26.500000 126.000000 26.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2589177380)" /></g><g id="(b -&gt; d)[0]"><path d="M 26.500000 234.000000 C 26.500000 272.000000 33.299999 292.000000 58.250760 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2589177380)" /></g><g id="(c -&gt; d)[0]"><path d="M 139.500000 234.000000 C 139.500000 272.000000 132.699997 292.000000 107.749240 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2589177380)" /></g><mask id="d2-2589177380" maskUnits="userSpaceOnUse" x="-101" y="-101" width="368" height="600">
</mask></g><g style="animation: d2Transition-d2-1574744994-1 4200ms infinite" class="d2-1574744994" width="368" height="600" viewBox="-101 -101 368 600"><rect x="-101.000000" y="-101.000000" width="368.000000" height="600.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">a</text></g><g id="b"><g class="shape" ><rect x="0.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">b</text></g><g id="d"><g class="shape" ><rect x="56.000000" y="332.000000" width="54.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="83.000000" y="370.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">d</text></g><g id="c"><g class="shape" ><rect x="113.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="139.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">c</text></g><g id="(a -&gt; b)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 26.500000 68.000000 C 26.500000 106.000000 26.500000 126.000000 26.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-483309782)" /></g><g id="(b -&gt; d)[0]"><path d="M 26.500000 234.000000 C 26.500000 272.000000 33.299999 292.000000 58.250760 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-483309782)" /></g><g id="(c -&gt; d)[0]"><path d="M 139.500000 234.000000 C 139.500000 272.000000 132.699997 292.000000 107.749240 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-483309782)" /></g><mask id="d2-483309782" maskUnits="userSpaceOnUse" x="-101" y="-101" width="368" height="600">
<rect x="-101" y="-101" width="368" height="600" fill="white"></rect>
<rect x="22.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="22.500000" y="188.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="78.500000" y="354.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="135.500000" y="188.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
</mask></g><g style="animation: d2Transition-d2-2543050356-2 4200ms infinite" class="d2-2543050356" width="368" height="766" viewBox="-101 -101 368 766"><rect x="-101.000000" y="-101.000000" width="368.000000" height="766.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">a</text></g><g id="b"><g class="shape" ><rect x="0.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">b</text></g><g id="d"><g class="shape" ><rect x="56.000000" y="332.000000" width="54.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="83.000000" y="370.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">d</text></g><g id="c"><g class="shape" ><rect x="113.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="139.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">c</text></g><g id="e"><g class="shape" ><rect x="57.000000" y="498.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="83.500000" y="536.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">e</text></g><g id="(a -&gt; b)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 26.500000 68.000000 C 26.500000 106.000000 26.500000 126.000000 26.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-3700658505)" /></g><g id="(b -&gt; d)[0]"><path d="M 26.500000 234.000000 C 26.500000 272.000000 33.299999 292.000000 58.250760 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-3700658505)" /></g><g id="(c -&gt; d)[0]"><path d="M 139.500000 234.000000 C 139.500000 272.000000 132.699997 292.000000 107.749240 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-3700658505)" /></g><g id="(d -&gt; e)[0]"><path d="M 83.000000 400.000000 C 83.000000 438.000000 83.000000 458.000000 83.000000 494.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-3700658505)" /></g><mask id="d2-3700658505" maskUnits="userSpaceOnUse" x="-101" y="-101" width="368" height="766">
</mask></g><g style="animation: d2Transition-d2-1574744994-2 4200ms infinite" class="d2-1574744994" width="368" height="766" viewBox="-101 -101 368 766"><rect x="-101.000000" y="-101.000000" width="368.000000" height="766.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="38.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">a</text></g><g id="b"><g class="shape" ><rect x="0.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="26.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">b</text></g><g id="d"><g class="shape" ><rect x="56.000000" y="332.000000" width="54.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="83.000000" y="370.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">d</text></g><g id="c"><g class="shape" ><rect x="113.000000" y="166.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="139.500000" y="204.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">c</text></g><g id="e"><g class="shape" ><rect x="57.000000" y="498.000000" width="53.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="83.500000" y="536.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">e</text></g><g id="(a -&gt; b)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 26.500000 68.000000 C 26.500000 106.000000 26.500000 126.000000 26.500000 162.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2079318802)" /></g><g id="(b -&gt; d)[0]"><path d="M 26.500000 234.000000 C 26.500000 272.000000 33.299999 292.000000 58.250760 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2079318802)" /></g><g id="(c -&gt; d)[0]"><path d="M 139.500000 234.000000 C 139.500000 272.000000 132.699997 292.000000 107.749240 328.692294" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2079318802)" /></g><g id="(d -&gt; e)[0]"><path d="M 83.000000 400.000000 C 83.000000 438.000000 83.000000 458.000000 83.000000 494.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2079318802)" /></g><mask id="d2-2079318802" maskUnits="userSpaceOnUse" x="-101" y="-101" width="368" height="766">
<rect x="-101" y="-101" width="368" height="766" fill="white"></rect>
<rect x="22.500000" y="22.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="22.500000" y="188.500000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.1-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 271 437"><svg id="d2-svg" class="d2-2922829426" width="271" height="437" viewBox="-101 -101 271 437"><rect x="-101.000000" y="-101.000000" width="271.000000" height="437.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-2922829426 .text-bold {
font-family: "d2-2922829426-font-bold";
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" d2Version="v0.6.3-HEAD" preserveAspectRatio="xMinYMin meet" viewBox="0 0 279 445"><svg id="d2-svg" class="d2-3562348775" width="279" height="445" viewBox="-101 -101 279 445"><rect x="-101.000000" y="-101.000000" width="279.000000" height="445.000000" rx="0.000000" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-3562348775 .text-bold {
font-family: "d2-3562348775-font-bold";
}
@font-face {
font-family: d2-2922829426-font-bold;
font-family: d2-3562348775-font-bold;
src: url("data:application/font-woff;base64,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");
}]]></style><style type="text/css"><![CDATA[.shape {
shape-rendering: geometricPrecision;
@ -18,79 +18,79 @@
opacity: 0.5;
}
.d2-2922829426 .fill-N1{fill:#0A0F25;}
.d2-2922829426 .fill-N2{fill:#676C7E;}
.d2-2922829426 .fill-N3{fill:#9499AB;}
.d2-2922829426 .fill-N4{fill:#CFD2DD;}
.d2-2922829426 .fill-N5{fill:#DEE1EB;}
.d2-2922829426 .fill-N6{fill:#EEF1F8;}
.d2-2922829426 .fill-N7{fill:#FFFFFF;}
.d2-2922829426 .fill-B1{fill:#0D32B2;}
.d2-2922829426 .fill-B2{fill:#0D32B2;}
.d2-2922829426 .fill-B3{fill:#E3E9FD;}
.d2-2922829426 .fill-B4{fill:#E3E9FD;}
.d2-2922829426 .fill-B5{fill:#EDF0FD;}
.d2-2922829426 .fill-B6{fill:#F7F8FE;}
.d2-2922829426 .fill-AA2{fill:#4A6FF3;}
.d2-2922829426 .fill-AA4{fill:#EDF0FD;}
.d2-2922829426 .fill-AA5{fill:#F7F8FE;}
.d2-2922829426 .fill-AB4{fill:#EDF0FD;}
.d2-2922829426 .fill-AB5{fill:#F7F8FE;}
.d2-2922829426 .stroke-N1{stroke:#0A0F25;}
.d2-2922829426 .stroke-N2{stroke:#676C7E;}
.d2-2922829426 .stroke-N3{stroke:#9499AB;}
.d2-2922829426 .stroke-N4{stroke:#CFD2DD;}
.d2-2922829426 .stroke-N5{stroke:#DEE1EB;}
.d2-2922829426 .stroke-N6{stroke:#EEF1F8;}
.d2-2922829426 .stroke-N7{stroke:#FFFFFF;}
.d2-2922829426 .stroke-B1{stroke:#0D32B2;}
.d2-2922829426 .stroke-B2{stroke:#0D32B2;}
.d2-2922829426 .stroke-B3{stroke:#E3E9FD;}
.d2-2922829426 .stroke-B4{stroke:#E3E9FD;}
.d2-2922829426 .stroke-B5{stroke:#EDF0FD;}
.d2-2922829426 .stroke-B6{stroke:#F7F8FE;}
.d2-2922829426 .stroke-AA2{stroke:#4A6FF3;}
.d2-2922829426 .stroke-AA4{stroke:#EDF0FD;}
.d2-2922829426 .stroke-AA5{stroke:#F7F8FE;}
.d2-2922829426 .stroke-AB4{stroke:#EDF0FD;}
.d2-2922829426 .stroke-AB5{stroke:#F7F8FE;}
.d2-2922829426 .background-color-N1{background-color:#0A0F25;}
.d2-2922829426 .background-color-N2{background-color:#676C7E;}
.d2-2922829426 .background-color-N3{background-color:#9499AB;}
.d2-2922829426 .background-color-N4{background-color:#CFD2DD;}
.d2-2922829426 .background-color-N5{background-color:#DEE1EB;}
.d2-2922829426 .background-color-N6{background-color:#EEF1F8;}
.d2-2922829426 .background-color-N7{background-color:#FFFFFF;}
.d2-2922829426 .background-color-B1{background-color:#0D32B2;}
.d2-2922829426 .background-color-B2{background-color:#0D32B2;}
.d2-2922829426 .background-color-B3{background-color:#E3E9FD;}
.d2-2922829426 .background-color-B4{background-color:#E3E9FD;}
.d2-2922829426 .background-color-B5{background-color:#EDF0FD;}
.d2-2922829426 .background-color-B6{background-color:#F7F8FE;}
.d2-2922829426 .background-color-AA2{background-color:#4A6FF3;}
.d2-2922829426 .background-color-AA4{background-color:#EDF0FD;}
.d2-2922829426 .background-color-AA5{background-color:#F7F8FE;}
.d2-2922829426 .background-color-AB4{background-color:#EDF0FD;}
.d2-2922829426 .background-color-AB5{background-color:#F7F8FE;}
.d2-2922829426 .color-N1{color:#0A0F25;}
.d2-2922829426 .color-N2{color:#676C7E;}
.d2-2922829426 .color-N3{color:#9499AB;}
.d2-2922829426 .color-N4{color:#CFD2DD;}
.d2-2922829426 .color-N5{color:#DEE1EB;}
.d2-2922829426 .color-N6{color:#EEF1F8;}
.d2-2922829426 .color-N7{color:#FFFFFF;}
.d2-2922829426 .color-B1{color:#0D32B2;}
.d2-2922829426 .color-B2{color:#0D32B2;}
.d2-2922829426 .color-B3{color:#E3E9FD;}
.d2-2922829426 .color-B4{color:#E3E9FD;}
.d2-2922829426 .color-B5{color:#EDF0FD;}
.d2-2922829426 .color-B6{color:#F7F8FE;}
.d2-2922829426 .color-AA2{color:#4A6FF3;}
.d2-2922829426 .color-AA4{color:#EDF0FD;}
.d2-2922829426 .color-AA5{color:#F7F8FE;}
.d2-2922829426 .color-AB4{color:#EDF0FD;}
.d2-2922829426 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="x"><g class="shape" ><ellipse rx="34.500000" ry="34.500000" cx="34.500000" cy="34.500000" class="shape stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="34.500000" y="40.000000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text></g><g id="y"><g class="shape" ><rect x="2.000000" y="169.000000" width="66.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="35.000000" y="207.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text></g><g id="(x -&gt; y)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 34.980001 70.999900 C 34.599998 109.000000 34.500000 129.000000 34.500000 165.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-2922829426)" /></g><mask id="d2-2922829426" maskUnits="userSpaceOnUse" x="-101" y="-101" width="271" height="437">
<rect x="-101" y="-101" width="271" height="437" fill="white"></rect>
<rect x="30.500000" y="24.000000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="30.500000" y="191.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
.d2-3562348775 .fill-N1{fill:#0A0F25;}
.d2-3562348775 .fill-N2{fill:#676C7E;}
.d2-3562348775 .fill-N3{fill:#9499AB;}
.d2-3562348775 .fill-N4{fill:#CFD2DD;}
.d2-3562348775 .fill-N5{fill:#DEE1EB;}
.d2-3562348775 .fill-N6{fill:#EEF1F8;}
.d2-3562348775 .fill-N7{fill:#FFFFFF;}
.d2-3562348775 .fill-B1{fill:#0D32B2;}
.d2-3562348775 .fill-B2{fill:#0D32B2;}
.d2-3562348775 .fill-B3{fill:#E3E9FD;}
.d2-3562348775 .fill-B4{fill:#E3E9FD;}
.d2-3562348775 .fill-B5{fill:#EDF0FD;}
.d2-3562348775 .fill-B6{fill:#F7F8FE;}
.d2-3562348775 .fill-AA2{fill:#4A6FF3;}
.d2-3562348775 .fill-AA4{fill:#EDF0FD;}
.d2-3562348775 .fill-AA5{fill:#F7F8FE;}
.d2-3562348775 .fill-AB4{fill:#EDF0FD;}
.d2-3562348775 .fill-AB5{fill:#F7F8FE;}
.d2-3562348775 .stroke-N1{stroke:#0A0F25;}
.d2-3562348775 .stroke-N2{stroke:#676C7E;}
.d2-3562348775 .stroke-N3{stroke:#9499AB;}
.d2-3562348775 .stroke-N4{stroke:#CFD2DD;}
.d2-3562348775 .stroke-N5{stroke:#DEE1EB;}
.d2-3562348775 .stroke-N6{stroke:#EEF1F8;}
.d2-3562348775 .stroke-N7{stroke:#FFFFFF;}
.d2-3562348775 .stroke-B1{stroke:#0D32B2;}
.d2-3562348775 .stroke-B2{stroke:#0D32B2;}
.d2-3562348775 .stroke-B3{stroke:#E3E9FD;}
.d2-3562348775 .stroke-B4{stroke:#E3E9FD;}
.d2-3562348775 .stroke-B5{stroke:#EDF0FD;}
.d2-3562348775 .stroke-B6{stroke:#F7F8FE;}
.d2-3562348775 .stroke-AA2{stroke:#4A6FF3;}
.d2-3562348775 .stroke-AA4{stroke:#EDF0FD;}
.d2-3562348775 .stroke-AA5{stroke:#F7F8FE;}
.d2-3562348775 .stroke-AB4{stroke:#EDF0FD;}
.d2-3562348775 .stroke-AB5{stroke:#F7F8FE;}
.d2-3562348775 .background-color-N1{background-color:#0A0F25;}
.d2-3562348775 .background-color-N2{background-color:#676C7E;}
.d2-3562348775 .background-color-N3{background-color:#9499AB;}
.d2-3562348775 .background-color-N4{background-color:#CFD2DD;}
.d2-3562348775 .background-color-N5{background-color:#DEE1EB;}
.d2-3562348775 .background-color-N6{background-color:#EEF1F8;}
.d2-3562348775 .background-color-N7{background-color:#FFFFFF;}
.d2-3562348775 .background-color-B1{background-color:#0D32B2;}
.d2-3562348775 .background-color-B2{background-color:#0D32B2;}
.d2-3562348775 .background-color-B3{background-color:#E3E9FD;}
.d2-3562348775 .background-color-B4{background-color:#E3E9FD;}
.d2-3562348775 .background-color-B5{background-color:#EDF0FD;}
.d2-3562348775 .background-color-B6{background-color:#F7F8FE;}
.d2-3562348775 .background-color-AA2{background-color:#4A6FF3;}
.d2-3562348775 .background-color-AA4{background-color:#EDF0FD;}
.d2-3562348775 .background-color-AA5{background-color:#F7F8FE;}
.d2-3562348775 .background-color-AB4{background-color:#EDF0FD;}
.d2-3562348775 .background-color-AB5{background-color:#F7F8FE;}
.d2-3562348775 .color-N1{color:#0A0F25;}
.d2-3562348775 .color-N2{color:#676C7E;}
.d2-3562348775 .color-N3{color:#9499AB;}
.d2-3562348775 .color-N4{color:#CFD2DD;}
.d2-3562348775 .color-N5{color:#DEE1EB;}
.d2-3562348775 .color-N6{color:#EEF1F8;}
.d2-3562348775 .color-N7{color:#FFFFFF;}
.d2-3562348775 .color-B1{color:#0D32B2;}
.d2-3562348775 .color-B2{color:#0D32B2;}
.d2-3562348775 .color-B3{color:#E3E9FD;}
.d2-3562348775 .color-B4{color:#E3E9FD;}
.d2-3562348775 .color-B5{color:#EDF0FD;}
.d2-3562348775 .color-B6{color:#F7F8FE;}
.d2-3562348775 .color-AA2{color:#4A6FF3;}
.d2-3562348775 .color-AA4{color:#EDF0FD;}
.d2-3562348775 .color-AA5{color:#F7F8FE;}
.d2-3562348775 .color-AB4{color:#EDF0FD;}
.d2-3562348775 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g id="x"><g class="shape" ><ellipse rx="38.500000" ry="38.500000" cx="38.500000" cy="38.500000" class="shape stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="38.500000" y="44.000000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">x</text></g><g id="y"><g class="shape" ><rect x="6.000000" y="177.000000" width="66.000000" height="66.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g><text x="39.000000" y="215.500000" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">y</text></g><g id="(x -&gt; y)[0]"><marker id="mk-3488378134" 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 points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 38.980001 78.999900 C 38.599998 117.000000 38.500000 137.000000 38.500000 173.000000" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-3488378134)" mask="url(#d2-3562348775)" /></g><mask id="d2-3562348775" maskUnits="userSpaceOnUse" x="-101" y="-101" width="279" height="445">
<rect x="-101" y="-101" width="279" height="445" fill="white"></rect>
<rect x="34.500000" y="28.000000" width="8" height="21" fill="rgba(0,0,0,0.75)"></rect>
<rect x="34.500000" y="199.500000" width="9" height="21" fill="rgba(0,0,0,0.75)"></rect>
</mask></svg></svg>

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

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