grooph 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -31
- package/THIRD-PARTY-NOTICES.md +5 -1
- package/dist/app/assets/App-CT9KxzfQ.css +1 -0
- package/dist/app/assets/App-D1pDFbEY.js +5 -0
- package/dist/app/assets/EmbedApp-CTausQWY.js +1 -0
- package/dist/app/assets/ExportPanel-CbRH4C69.js +8 -0
- package/dist/app/assets/Import-DF0XLxRI.js +1 -0
- package/dist/app/assets/SketchView-BjeUHG4X.js +143 -0
- package/dist/app/assets/{brakes-BJPDrrJT.js → brakes-B9b3hDX8.js} +1 -1
- package/dist/app/assets/{builtins-D_22fKRF.js → builtins-DzyPaYdd.js} +1 -1
- package/dist/app/assets/{compile-BAvi-rd0.js → compile-DL2budwP.js} +8 -8
- package/dist/app/assets/{front-BRl7rl-u.js → front-OxfL-OaD.js} +1 -1
- package/dist/app/assets/full-C0asYORc.js +1 -0
- package/dist/app/assets/graph-more-Dn_hNa20.js +2 -0
- package/dist/app/assets/graph-stage-CwNePnN4.js +4 -0
- package/dist/app/assets/graph-views-CmkQ41zC.js +2 -0
- package/dist/app/assets/{index-CeaKwKuU.js → index-B5ZkSF4L.js} +2 -2
- package/dist/app/assets/mermaid-read-cyqJ32v-.js +17 -0
- package/dist/app/assets/{plan-templates-BQu8G2sX.js → plan-templates-u2fF3GnS.js} +1 -1
- package/dist/app/assets/runs-BA5HKtsx.js +1 -0
- package/dist/app/assets/screens-CMMuexid.js +16 -0
- package/dist/app/assets/share-DV3wsAsJ.js +8 -0
- package/dist/app/assets/site-looks.v1.css +223 -0
- package/dist/app/assets/space-Cuy4YqyZ.js +1 -0
- package/dist/app/assets/styles-Dlp-yYlE.css +1 -0
- package/dist/app/assets/templates-DbAhWvP6.js +2 -0
- package/dist/app/assets/{themes-DtOBrLk0.js → themes-C34TrvOJ.js} +1 -1
- package/dist/app/assets/{units-DOIUgOIU.js → units-DlniUjfH.js} +1 -1
- package/dist/app/assets/{views-CLwg5VNv.js → views-CFqRShXD.js} +2 -1
- package/dist/app/grooph-app.json +1 -1
- package/dist/app/index.html +14 -11
- package/dist/app/llms.txt +6 -7
- package/dist/app/manifest.webmanifest +1 -1
- package/dist/app/og.png +0 -0
- package/dist/app/routes.json +42 -33
- package/dist/app/sw.js +7 -2
- package/dist/browser/grooph.d.ts +44 -0
- package/dist/browser/grooph.global.js +7 -0
- package/dist/browser/grooph.js +7 -0
- package/dist/bundle/grooph.js +6734 -2536
- package/hooks/grooph-event.mjs +163 -14
- package/package.json +14 -6
- package/dist/app/assets/App-48y1Ec5B.js +0 -5
- package/dist/app/assets/App-Cv1auMeh.css +0 -1
- package/dist/app/assets/EmbedApp-390Z2d4x.js +0 -1
- package/dist/app/assets/ExportPanel-Ca3wBB38.js +0 -8
- package/dist/app/assets/Import-ByMI7Uz9.js +0 -1
- package/dist/app/assets/graph-more-393HTgQE.js +0 -2
- package/dist/app/assets/graph-stage-BkrQGQ-z.js +0 -4
- package/dist/app/assets/graph-views-COQF_QTQ.js +0 -2
- package/dist/app/assets/runs-DcjRi7S6.js +0 -1
- package/dist/app/assets/screens-aIjMSzZg.js +0 -16
- package/dist/app/assets/share-BzIzB4EY.js +0 -8
- package/dist/app/assets/space-DWgrlnfB.js +0 -1
- package/dist/app/assets/styles-BA1aVO9R.css +0 -1
- package/dist/app/assets/templates-CoNTzuuz.js +0 -2
- package/dist/app/demo/run.txt +0 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import{a as e,c as t,t as n}from"./index-B5ZkSF4L.js";import{Gt as r,Ht as i,Wt as a,b as o,en as s,nn as c,pn as l}from"./share-DV3wsAsJ.js";import{v as u}from"./App-D1pDFbEY.js";import{n as d}from"./mermaid-read-cyqJ32v-.js";import{a as f,i as p,n as m,o as h,r as g}from"./screens-CMMuexid.js";var _=t(e(),1),v=`:root{--draw-ink:var(--ink);--draw-green:#1f7a5a;--draw-blue:#2563eb;--draw-red:#c0392b;--draw-amber:#b26b00}@media (prefers-color-scheme:dark){:root{--draw-green:#5dbb94;--draw-blue:#7aa2ff;--draw-red:#ff8f80;--draw-amber:#f0b35a}}.graph-sketch{z-index:1;overscroll-behavior:contain;background:var(--bg);pointer-events:auto;position:absolute;inset:52px 0 0;overflow-y:auto;container:sk/size}.sk{--sk-radius-lg:10px;--sk-gutter:12px;min-height:100%;padding:6px var(--sk-gutter) 32px;box-sizing:border-box;gap:20px;display:grid}.sk-draw{align-content:start;gap:10px;min-width:0;display:grid}@container sk (width>=1024px){.sk{grid-template-columns:minmax(0,1.7fr) minmax(340px,1fr);align-items:start;padding-inline:20px}.sk-draw{position:sticky;top:12px}}.sk-bar{flex-wrap:wrap;align-items:center;gap:4px 14px;display:flex;position:relative}.sk-tools-row{align-items:center;gap:2px;min-width:0;display:flex}.sk-tools-row:last-child{flex:auto}.sk-spacer{flex:1 1 0}.sk-rule{background:var(--line-strong);flex:none;width:1px;height:20px;margin-inline:7px}.sk-bar svg{fill:none;stroke:currentColor;stroke-width:1.6px;stroke-linecap:round;stroke-linejoin:round}.sk-bar svg circle{fill:currentColor;stroke:none}.sk-seg{flex:none;gap:2px;display:inline-flex}.sk-seg button,.sk-icon{border-radius:var(--radius);min-width:40px;height:40px;min-height:40px;color:var(--ink-2);font:600 .9rem/1 var(--font);cursor:pointer;touch-action:manipulation;background:0 0;border:0;justify-content:center;align-items:center;gap:7px;padding:0 11px 0 10px;display:inline-flex}.sk-icon{width:40px;padding:0}.sk-seg button svg,.sk-icon svg{flex:none;width:20px;height:20px}.sk-seg button[aria-checked=true]{background:var(--ink);color:var(--bg)}.sk-seg button[data-options]{position:relative}.sk-seg button[data-options]:after{content:"";opacity:.55;border:3px solid;border-color:#0000 currentColor currentColor #0000;position:absolute;bottom:4px;right:4px}@media (hover:hover){.sk-seg button[aria-checked=false]:hover,.sk-icon:not(:disabled):hover{background:var(--surface-2);color:var(--ink)}}.sk-icon[aria-expanded=true]{background:var(--surface-2);color:var(--ink)}.sk-icon:disabled{opacity:.35;cursor:default}@media (prefers-reduced-motion:no-preference){.sk-seg button{transition:background-color .12s ease-out,color .12s ease-out}}.sk-seg button{padding:0}.sk-seg button span{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.sk-inks{border:0;flex:none;gap:0;margin:0;padding:0;display:inline-flex}.sk-inks input{opacity:0;width:1px;height:1px;position:absolute}.sk-inks label{border-radius:var(--radius);cursor:pointer;place-items:center;width:31px;height:40px;display:grid}.sk-swatch{border-radius:50%;width:18px;height:18px;box-shadow:inset 0 0 0 1px #0000002e;box-shadow:inset 0 0 0 1px lab(0% 0 0/.18)}.sk-inks input:checked+label .sk-swatch{box-shadow:inset 0 0 0 1px #0000002e, 0 0 0 2.5px var(--bg), 0 0 0 4px var(--ink)}@supports (color:lab(0% 0 0)){.sk-inks input:checked+label .sk-swatch{box-shadow:inset 0 0 0 1px lab(0% 0 0/.18), 0 0 0 2.5px var(--bg), 0 0 0 4px var(--ink)}}@media (hover:hover){.sk-inks input:not(:checked)+label:hover{background:var(--surface-2)}}.sk-inks input:focus-visible+label{outline:2px solid var(--focus);outline-offset:-2px}@media (forced-colors:active){.sk-seg button[aria-checked=true],.sk-inks input:checked+label{outline-offset:-2px;outline:2px solid canvastext}}.sk-go{border:1px solid var(--accent);border-radius:var(--radius);background:var(--accent);height:40px;min-height:40px;color:var(--accent-ink);font:650 .95rem/1 var(--font);white-space:nowrap;cursor:pointer;touch-action:manipulation;justify-content:center;align-items:center;gap:7px;padding:0 15px 0 13px;display:inline-flex;position:relative}.sk-go svg{stroke-width:1.8px;flex:none;width:18px;height:18px}@media (hover:hover){.sk-go:hover{filter:brightness(1.08)}}.sk-go:active{transform:translateY(1px)}.sk-go[data-stale=true]:after{content:"";background:var(--accent-ink);opacity:.7;border-radius:50%;width:6px;height:6px;position:absolute;top:5px;right:5px}@container sk (width<=719px){.sk-tools-row{flex:100%}.sk-bar .sk-more,.sk-bar .sk-tools{position:static}.sk-bar .sk-menu,.sk-bar .sk-add .sk-menu{width:auto;min-width:0;left:0;right:0}}@container sk (width<=419px){.sk-rule{margin-inline:4px}.sk-go{padding-inline:11px 12px}}@container sk (width<=399px){.sk-inks label{width:30px}.sk-icon,.sk-seg button{width:36px;min-width:36px}.sk-rule{margin-inline:4px}.sk-go svg{display:none}.sk-go{padding-inline:12px}}@container sk (width<=349px){.sk-inks label{width:27px}.sk-icon,.sk-seg button{width:30px;min-width:30px}.sk-tools-row:last-child .sk-rule{display:none}.sk-go{padding-inline:10px;font-size:.9rem}}.sk-more,.sk-tools{position:relative}.sk-menu{z-index:20;border:1px solid var(--line-strong);border-radius:var(--sk-radius-lg);background:var(--surface);min-width:260px;box-shadow:var(--shadow-card);gap:2px;margin:0;padding:6px;list-style:none;display:grid;position:absolute;top:calc(100% + 6px);left:0}.sk-menu[hidden]{display:none}.sk-menu button{width:100%;min-height:44px;color:var(--ink);font:450 .95rem/1.2 var(--font);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:6px;padding:0 12px}.sk-menu [role=menuitemcheckbox]{padding-left:40px;position:relative}.sk-menu [role=menuitemcheckbox]:before{content:"";border:1.5px solid var(--line-strong);border-radius:4px;width:16px;height:16px;margin-top:-8px;position:absolute;top:50%;left:12px}.sk-menu [role=menuitemcheckbox][aria-checked=true]:before{border-color:var(--accent);background:var(--accent)}.sk-menu [role=menuitemcheckbox][aria-checked=true]:after{content:"";border:solid var(--accent-ink);border-width:0 2px 2px 0;width:5px;height:9px;margin-top:-6.5px;position:absolute;top:50%;left:17.5px;transform:rotate(45deg)}.sk-menu [role=menuitemradio]{padding-left:40px;position:relative}.sk-menu [role=menuitemradio][aria-checked=true]:before{content:"";background:var(--accent);border-radius:50%;width:8px;height:8px;margin-top:-4px;position:absolute;top:50%;left:16px}.sk-menu button small{color:var(--ink-3);margin-top:2px;font-size:.8rem;display:block}.sk-tool-menu{width:290px}.sk-tool-menu button{padding-block:8px}.sk-menu [role=separator]{background:var(--line);height:1px;margin:4px 6px}@media (hover:hover){.sk-menu button:hover{background:var(--surface-2)}}.sk-menu button:focus-visible{outline-offset:-2px}.sk-add .sk-menu{overscroll-behavior:contain;width:340px;max-height:min(60cqh,560px);overflow-y:auto}.sk-menu-head{color:var(--ink-3);font:600 .8rem/1.2 var(--font);margin:8px 12px 4px}.sk-menu-head:first-child{margin-top:4px}.sk-add-shapes{grid-template-columns:repeat(2,minmax(0,1fr));gap:2px;display:grid}.sk-add-shapes button{align-items:center;gap:10px;min-height:42px;padding:0 8px;font-size:.9rem;display:flex}.sk-add-shapes svg{stroke-width:1.4px;flex:none;width:28px;height:20px}.sk-add-shapes svg circle{fill:none;stroke:currentColor}.sk-add-shapes svg .sk-fill{fill:currentColor;stroke:none}.sk-add-arrows{grid-template-columns:minmax(0,1fr)}.sk-add-templates{gap:2px;display:grid}.sk-add-templates button{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.sk-pad{border:1px solid var(--line);border-radius:var(--sk-radius-lg);background:var(--surface);position:relative;overflow:hidden}@container sk (width<=719px){.sk-pad{margin-inline:calc(-1 * var(--sk-gutter));border-inline:0;border-radius:0}}.sk-pad canvas{width:100%;height:clamp(260px, calc(100cqh - 6px - var(--sk-toolbar,92px) - 70px), 1100px);touch-action:none;cursor:crosshair;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;display:block}.sk-pad canvas[data-tool=erase],.sk-pad canvas[data-tool=cut]{cursor:cell}.sk-pad canvas[data-tool=select]{cursor:default}.sk-pad canvas[data-tool=select][data-over]{cursor:move}.sk-pad canvas[data-tool=hand],.sk-pad canvas[data-space]{cursor:grab}.sk-pad canvas[data-panning]{cursor:grabbing}@container sk (height<=540px){.sk-pad canvas{height:max(150px, calc(100cqh - var(--sk-toolbar,52px) - 54px))}.sk-read-row{flex-wrap:nowrap;align-items:center}.sk-read{align-items:center;gap:10px;min-width:0;font-size:.86rem;line-height:1.35;display:flex}.sk-read>span:first-child{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;min-width:0;display:-webkit-box;overflow:hidden}.sk-read .sk-ms{display:none}.sk-read .sk-to-result,.sk-read-row .sk-check{flex:none}}@container sk (height<=540px) and (width<=699px){.sk-read-row .sk-check{display:none}}.sk-hint{color:var(--ink-2);text-align:center;pointer-events:none;place-content:center;justify-items:center;gap:14px;padding:24px;display:grid;position:absolute;inset:0}.sk-hint[hidden]{display:none}.sk-hint p{max-width:30ch;margin:0;font-size:1rem;line-height:1.5}.sk-hint strong{color:var(--ink);margin-bottom:4px;font-size:1.06rem;font-weight:600;display:block}.sk-hint .btn{pointer-events:auto}.sk-chip{border:1px solid var(--line);background:color-mix(in oklch, var(--surface) 90%, transparent);max-width:calc(100% - 16px);color:var(--ink-2);border-radius:8px;flex-wrap:wrap;align-items:center;gap:4px 10px;margin:0;padding:3px 3px 3px 10px;font-size:.82rem;line-height:1.3;display:flex;position:absolute;bottom:8px;left:8px}.sk-chip[hidden]{display:none}.sk-chip button,.sk-zoom{border:1px solid var(--line);background:var(--surface);min-height:30px;color:var(--ink);font:600 .8rem/1 var(--font);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:0 9px;display:inline-flex}.sk-corner{gap:6px;display:flex;position:absolute;top:8px;right:8px}.sk-full{border:1px solid var(--line);background:color-mix(in oklch, var(--surface) 90%, transparent);width:32px;height:32px;color:var(--ink-2);cursor:pointer;border-radius:6px;place-items:center;padding:0;display:grid}.sk-full svg{fill:none;stroke:currentColor;stroke-width:1.6px;stroke-linecap:round;stroke-linejoin:round;width:18px;height:18px}.sk-zoom{background:color-mix(in oklch, var(--surface) 90%, transparent);min-height:32px;color:var(--ink-2);font-family:var(--mono);font-variant-numeric:tabular-nums;font-weight:500}.sk-zoom:after{content:"Fit";color:var(--ink);font-family:var(--font);font-weight:600}.sk-zoom[hidden]{display:none}.sk-sel-bar{z-index:6;border:1px solid var(--line-strong);background:var(--surface);border-radius:9px;flex-wrap:wrap;gap:1px;max-width:calc(100% - 8px);padding:3px;display:flex;position:absolute;box-shadow:0 1px 2px #0000001f,0 8px 20px -6px #00000052;box-shadow:0 1px 2px lab(0% 0 0/.12),0 8px 20px -6px lab(0% 0 0/.32)}.sk-sel-bar[hidden],.sk-sel-bar button[hidden]{display:none}.sk-sel-bar button{height:32px;color:var(--ink);font:600 .82rem/1 var(--font);white-space:nowrap;cursor:pointer;touch-action:manipulation;background:0 0;border:0;border-radius:6px;padding:0 9px}.sk-sel-bar button[data-sel=delete]{color:var(--error)}@container sk (width<=399px){.sk-sel-bar button{padding:0 7px}}.sk-full[aria-pressed=false] .sk-leave,.sk-full[aria-pressed=true] .sk-enter{display:none}@media (hover:hover){.sk-full:hover{background:var(--surface-2);color:var(--ink)}.sk-sel-bar button:hover,.sk-zoom:hover,.sk-chip button:hover{background:var(--surface-2)}}.sk-name-edit{z-index:5;margin:0;position:absolute}.sk-name-edit[hidden]{display:none}.sk-name-edit input{box-sizing:border-box;border:2px solid var(--accent);border-radius:var(--radius);background:var(--surface);width:100%;min-height:44px;color:var(--ink);font:600 1rem/1.2 var(--font);text-align:center;box-shadow:var(--shadow-card);padding:0 12px}.sk-read-row{flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:6px 16px;display:flex}.sk-read{min-width:0;color:var(--ink-2);margin:0;font-size:.94rem;line-height:1.5}.sk-read strong{color:var(--ink)}.sk-read .sk-ms{color:var(--ink-3);font:.8rem var(--mono);font-variant-numeric:tabular-nums;white-space:nowrap}.sk-read .sk-to-result{color:var(--accent);white-space:nowrap;margin-left:4px;font-weight:560}@container sk (width>=1024px){.sk-read .sk-to-result{display:none}}.sk-check{min-height:36px;color:var(--ink-2);cursor:pointer;align-items:center;gap:8px;font-size:.94rem;display:inline-flex}.sk-check input{width:18px;height:18px;accent-color:var(--accent);margin:0}.sk-result{align-content:start;gap:14px;min-width:0;scroll-margin-top:8px;display:grid}.sk-back{color:var(--accent);justify-self:start;font-size:.92rem;font-weight:560}@container sk (width>=1024px){.sk-back{display:none}}.sk-panel{border:1px solid var(--line);border-radius:var(--sk-radius-lg);background:var(--surface);gap:12px;min-width:0;padding:16px;display:grid}.sk-panel-head{flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:4px 12px;display:flex}.sk-panel h2{margin:0;font-size:1rem;font-weight:650}.sk-panel h2 label{cursor:inherit}.sk-panel-head span{color:var(--ink-3);font-size:.86rem}.sk-diagram{border-radius:var(--radius);place-items:center;min-height:220px;display:grid;overflow-x:auto}.sk-diagram svg{max-width:100%;height:auto}.sk-diagram [data-node]{cursor:pointer}.sk-empty{max-width:32ch;color:var(--ink-3);text-align:center;margin:0;font-size:.94rem}.sk-guesses{border-radius:var(--radius);background:var(--surface-2);color:var(--ink-2);gap:4px;margin:0;padding:10px 12px 10px 28px;font-size:.88rem;line-height:1.45;display:grid}.sk-guesses[hidden]{display:none}.sk-row{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.sk-row .btn[hidden]{display:none}.sk-status{color:var(--ink-3);margin:0;font-size:.88rem}.sk-note{color:var(--ink-3);margin:0;font-size:.86rem;line-height:1.45}.sk-note strong{color:var(--ink-2);font-weight:600}.sk-names{grid-template-columns:repeat(auto-fill,minmax(min(100%,270px),1fr));gap:8px 14px;display:grid}.sk-names>.sk-status{grid-column:1/-1}.sk-name-row{align-items:center;gap:6px;min-width:0;display:flex}.sk-names label{flex:auto;align-items:center;gap:8px;min-width:0;display:flex}.sk-names select,.sk-shape-note{flex:none;width:11em}.sk-names select{border:1px solid var(--line);background:linear-gradient(45deg, transparent 50%, var(--ink-2) 50%) right 14px center / 5px 5px no-repeat, linear-gradient(135deg, var(--ink-2) 50%, transparent 50%) right 9px center / 5px 5px no-repeat, var(--surface-2);min-height:40px;color:var(--ink);font:400 .9rem/1.2 var(--font);appearance:none;cursor:pointer;border-radius:6px;padding:0 26px 0 9px}.sk-shape-note{color:var(--ink-3);padding-left:10px;font-size:.86rem}.sk-names input{border:1px solid var(--line);background:var(--surface-2);min-width:0;min-height:40px;color:var(--ink);font:400 .95rem/1.3 var(--font);border-radius:6px;flex:auto;padding:0 10px}.sk-names input::placeholder{color:var(--ink-3)}.sk-tag{background:var(--accent);min-width:28px;color:var(--accent-ink);font:600 .78rem/1 var(--mono);text-align:center;border-radius:4px;flex:none;padding:5px 6px}.sk-line-tag{border:1px solid var(--accent);background:var(--accent-soft);color:var(--ink);padding:4px 5px}.sk-code{box-sizing:border-box;resize:vertical;border:1px solid var(--line);border-radius:var(--radius);background:var(--surface-2);width:100%;min-height:240px;color:var(--ink);font:.86rem/1.55 var(--mono);tab-size:2;white-space:pre;padding:12px;overflow:auto}.sk-full-page,.sk-full-page body{overflow:hidden}.sk-full-page .stage,.sk-full-page .graph-views{z-index:100}.sk-full-page .graph-switch,.sk-full-page .graph-views-note{display:none}.sk.is-full .sk-draw{z-index:100;padding:max(6px, env(safe-area-inset-top)) max(8px, env(safe-area-inset-right)) max(4px, env(safe-area-inset-bottom)) max(8px, env(safe-area-inset-left));background:var(--bg);grid-template-rows:auto minmax(0,1fr) auto;gap:6px;position:fixed;inset:0}.sk.is-full .sk-pad{border:1px solid var(--line);border-radius:var(--radius);min-height:0;margin-inline:0;display:grid}.sk.is-full .sk-pad canvas{height:100%;min-height:0}.sk.is-full .sk-read-row{flex-wrap:nowrap;align-items:center;min-height:30px;padding-inline:4px}.sk.is-full .sk-read{align-items:center;gap:2px 10px;font-size:.86rem;line-height:1.35;display:flex}.sk.is-full .sk-read>span:first-child{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;min-width:0;display:-webkit-box;overflow:hidden}.sk.is-full .sk-read .sk-ms{display:none}.sk.is-full .sk-read .sk-to-result{flex:none;margin-left:0;display:inline}.sk.is-full .sk-read-row .sk-check{flex:none;min-height:30px;font-size:.86rem}@media (max-width:559px){.sk.is-full .sk-read-row .sk-check{display:none}}@media (max-width:719px){.sk.is-full .sk-tools-row{flex:100%}}.graph-views.is-sketch{background:var(--bg);pointer-events:auto}.graph-views.is-sketch .graph-switch{top:8px}:is(.stage:has(>.graph-views.is-sketch)>.toolbar,.stage:has(>.graph-views.is-sketch)>.loop-legend,.stage:has(>.graph-views.is-sketch)>.empty-canvas,.stage:has(>.graph-views.is-sketch)>.look-dot){display:none}`,y=(e,t)=>Math.hypot(e[0]-t[0],e[1]-t[1]);function b(e){let t=0;for(let n=1;n<e.length;n++)t+=y(e[n-1],e[n]);return t}function x(e){let t=1/0,n=1/0,r=-1/0,i=-1/0;for(let[a,o]of e)a<t&&(t=a),o<n&&(n=o),a>r&&(r=a),o>i&&(i=o);return{x0:t,y0:n,x1:r,y1:i,w:r-t,h:i-n,cx:(t+r)/2,cy:(n+i)/2}}function S(e,t){let n=e.map(e=>[e[0],e[1]]),r=b(n)/(t-1);if(!(r>0))return Array.from({length:t},()=>[n[0][0],n[0][1]]);let i=[[n[0][0],n[0][1]]],a=0;for(let e=1;e<n.length;e++){let t=y(n[e-1],n[e]);if(a+t>=r&&t>0){let o=(r-a)/t,s=[n[e-1][0]+o*(n[e][0]-n[e-1][0]),n[e-1][1]+o*(n[e][1]-n[e-1][1])];i.push(s),n.splice(e,0,s),a=0}else a+=t}let o=n[n.length-1];for(;i.length<t;)i.push([o[0],o[1]]);return i.slice(0,t)}function ee(e){let t=b(e)/2;for(let n=1;n<e.length;n++){let r=y(e[n-1],e[n]);if(r>=t&&r>0)return[e[n-1][0]+(e[n][0]-e[n-1][0])*t/r,e[n-1][1]+(e[n][1]-e[n-1][1])*t/r];t-=r}return[e[e.length-1][0],e[e.length-1][1]]}function C(e,t,n){let r=n[0]-t[0],i=n[1]-t[1],a=r*r+i*i,o=a?Math.max(0,Math.min(1,((e[0]-t[0])*r+(e[1]-t[1])*i)/a)):0;return Math.hypot(e[0]-t[0]-o*r,e[1]-t[1]-o*i)}function w(e,t){let n=1/0;for(let r=0;r<t.length;r++)n=Math.min(n,C(e,t[r],t[(r+1)%t.length]));return n}function te(e,t){let n=t.length?y(e,t[0]):1/0;for(let r=1;r<t.length;r++)n=Math.min(n,C(e,t[r-1],t[r]));return n}function ne(e,t){let n=!1;for(let r=0,i=t.length-1;r<t.length;i=r++){let[a,o]=t[r],[s,c]=t[i];o>e[1]!=c>e[1]&&e[0]<(s-a)*(e[1]-o)/(c-o)+a&&(n=!n)}return n}function T(e,t){let n=[];for(let r=0;r<e.length-1;r++){let i=e[r],a=e[r+1],o=Math.max(1,Math.ceil(y(i,a)/t));for(let e=0;e<o;e++)n.push([i[0]+(a[0]-i[0])*e/o,i[1]+(a[1]-i[1])*e/o])}let r=e[e.length-1];return n.push([r[0],r[1]]),n}function E(e,t,n,r){let i=0,a=t;for(;a+r>=0&&a+r<e.length&&i<n;)i+=y(e[a],e[a+r]),a+=r;return e[a]}function re(e){let t=0;for(let n=0,r=e.length-1;n<e.length;r=n++)t+=(e[r][0]+e[n][0])*(e[r][1]-e[n][1]);return Math.abs(t)/2}function ie(e){let t=e.slice().sort((e,t)=>e[0]-t[0]||e[1]-t[1]),n=(e,t,n)=>(t[0]-e[0])*(n[1]-e[1])-(t[1]-e[1])*(n[0]-e[0]),r=e=>{let t=[];for(let r of e){for(;t.length>=2&&n(t[t.length-2],t[t.length-1],r)<=0;)t.pop();t.push(r)}return t.pop(),t};return[...r(t),...r(t.slice().reverse())]}var ae=64,oe={rect:[[0,0],[1,0],[1,1],[0,1]],diamond:[[.5,0],[1,.5],[.5,1],[0,.5]],hexagon:[[.22,0],[.78,0],[1,.5],[.78,1],[.22,1],[0,.5]],trapezoid:[[.22,0],[.78,0],[1,1],[0,1]],"inv-trapezoid":[[0,0],[1,0],[.78,1],[.22,1]],"lean-right":[[.22,0],[1,0],[.78,1],[0,1]],"lean-left":[[0,0],[.78,0],[1,1],[.22,1]],triangle:[[.5,0],[1,1],[0,1]],"flip-triangle":[[0,0],[1,0],[.5,1]],ellipse:Array.from({length:48},(e,t)=>[.5+.5*Math.cos(t*Math.PI/24),.5+.5*Math.sin(t*Math.PI/24)])},se=Object.fromEntries(Object.entries(oe).map(([e,t])=>[e,S([...t,t[0]],ae)])),D=new Set([`triangle`,`flip-triangle`,`lean-right`,`lean-left`,`inv-trapezoid`]),O=60,k={rect:`rect`,subroutine:`rect`,diamond:`diamond`,hexagon:`hexagon`,trapezoid:`trapezoid`,"inv-trapezoid":`inv-trapezoid`,"lean-right":`lean-right`,"lean-left":`lean-left`,triangle:`triangle`,"flip-triangle":`flip-triangle`,circle:`ellipse`,stadium:`ellipse`,double:`ellipse`,dot:`ellipse`,bullseye:`ellipse`},A=new Set([`circle`,`stadium`,`double`]);function j(e){let t=e.length,n=[];for(let r=0;r<t;r++){let i=e[(r-2+t)%t],a=e[r],o=e[(r+2)%t],s=Math.abs(Math.atan2(o[1]-a[1],o[0]-a[0])-Math.atan2(a[1]-i[1],a[0]-i[0]));s>Math.PI&&(s=2*Math.PI-s),n.push(s)}let r=n.slice().sort((e,t)=>e-t),i=Math.max(.6,2.2*r[t>>1]),a=n.map((e,t)=>[e,t]).filter(([e])=>e>i).sort((e,t)=>t[0]-e[0]),o=[];for(let[,e]of a)o.every(n=>Math.min(Math.abs(e-n),t-Math.abs(e-n))>3)&&o.push(e);return o.length}function M(e){let t=t=>{let n=t*Math.PI/180,r=Math.cos(n),i=Math.sin(n),a=1/0,o=1/0,s=-1/0,c=-1/0;for(let[t,n]of e){let e=t*r+n*i,l=n*r-t*i;a=Math.min(a,e),s=Math.max(s,e),o=Math.min(o,l),c=Math.max(c,l)}return(s-a)*(c-o)},n=0,r=t(0);for(let e=-25;e<=25;e++){let i=t(e);i<r&&([n,r]=[e,i])}return Math.abs(n)<3||Math.abs(n)>=25?0:n*Math.PI/180}function ce(e){let t=x(e);if(t.w<12||t.h<12)return null;let n=S(e,ae),r=j(S(e,40)),i=Math.max(t.w,t.h)<O,a=N(n,t,r,i),o=M(n);if(!o)return{...a,bb:t,poly:n};let s=Math.cos(o),c=Math.sin(o),l=n.map(([e,t])=>[e*s+t*c,t*s-e*c]),u=x(l),d=N(l,u,r,i);return d.kind===`rect`&&d.score<a.score?{...d,bb:t,poly:n,upright:{w:u.w,h:u.h}}:{...a,bb:t,poly:n}}function N(e,t,n,r){let i=e.map(([e,n])=>[(e-t.x0)/t.w,(n-t.y0)/t.h]),a=Object.keys(oe).filter(e=>r===!1||!D.has(e)).map(e=>{let t=0;for(let n of i)t+=w(n,oe[e]);return{kind:e,a:t}}).sort((e,t)=>e.a-t.a).filter((e,t)=>t<4||e.kind===`ellipse`).map(({kind:e,a:t})=>{let n=0;for(let t of se[e])n+=w(t,i);return{kind:e,score:(t+n)/128}}).sort((e,t)=>e.score-t.score),o=a[0],s=a[1];if(o.kind===`ellipse`&&n>=4&&s.score<o.score+.03)o=s;else if(o.kind!==`ellipse`&&n<=2){let e=a.find(e=>e.kind===`ellipse`);e.score<o.score+.03&&(o=e)}let c=t.w/t.h;return{kind:o.kind===`ellipse`?c>.77&&c<1.3?`circle`:`stadium`:o.kind,score:o.score,unsure:o.score>.1}}function P(e){let t=e.length,n=b(e),r=(r,i)=>{let a=[];for(let o=r,s=0;o>=0&&o<t&&s<=.2*n;s+=o+i>=0&&o+i<t?y(e[o],e[o+i]):0,o+=i)a.push(o);let o=Math.ceil(a.length/80);return a.filter((e,t)=>t%o===0)},i=r(0,1),a=r(t-1,-1),o=0,s=t-1,c=y(e[0],e[t-1]);for(let t of i)for(let n of a){if(n<=t+2)continue;let r=y(e[t],e[n]);r<c-1e-9&&([c,o,s]=[r,t,n])}return e.slice(o,s+1)}function le(e,t){let n=e.length,r=e[0],i=e[n-1],a=y(r,i),o=0;for(let r=1;r<n&&o<.2*t;r++)o+=y(e[r-1],e[r]),a=Math.min(a,y(e[r],i));o=0;for(let i=n-2;i>=0&&o<.2*t;i--)o+=y(e[i+1],e[i]),a=Math.min(a,y(e[i],r));return a}var F=6,I=.12,L=.82;function R(e,t){let n=t.w,r=t.h;(e===`circle`||(e===`rect`||e===`diamond`)&&n/r>.88&&n/r<1.14)&&(n=r=(n+r)/2);let i=t.cx-n/2,a=t.cy-r/2,o=k[e];if(o===`ellipse`){let e=4*Math.max(8,Math.min(24,Math.round(Math.PI*(n+r)/8/F))),i=Array.from({length:e},(i,a)=>{let o=-Math.PI/2+a*2*Math.PI/e;return[t.cx+n/2*Math.cos(o),t.cy+r/2*Math.sin(o)]});return[...i,[i[0][0],i[0][1]]]}let s=oe[o].map(([e,t])=>[i+e*n,a+t*r]),c=T([...s,s[0]],F),l=[];for(let e of c)l.push(e),s.some(t=>y(t,e)<1e-6)&&l.push([e[0],e[1]]);return l}function ue(e,t=0,n=1){let r=e.length;if(r<3)return null;let i=n>=.01&&n<=100?n:1,a=(e,t)=>e.map(([e,n])=>[e*t,n*t]),o=de(a(e,i))??pe(a(e,i),Math.max(0,Math.min(t,r-2)));return o&&i!==1?{...o,pts:a(o.pts,1/i),box:x(a(o.pts,1/i))}:o}function de(e){let t=e.length,n=e[t-1],r=new Float64Array(t),i=Array(t),a=1/0,o=1/0,s=-1/0,c=-1/0;for(let n=t-1;n>=0;n--){n<t-1&&(r[n]=r[n+1]+y(e[n],e[n+1]));let[l,u]=e[n];a=Math.min(a,l),o=Math.min(o,u),s=Math.max(s,l),c=Math.max(c,u),i[n]={x0:a,y0:o,x1:s,y1:c,w:s-a,h:c-o,cx:(a+s)/2,cy:(o+c)/2}}let l=t=>{let a=i[t];return Math.max(a.w,a.h)>=28&&Math.min(a.w,a.h)>=18&&r[t]>1.3*(a.w+a.h)&&y(e[t],n)<Math.max(14,.18*Math.hypot(a.w,a.h))},u=0;for(;u<t&&!l(u);)u++;if(u>=t)return null;let d=u;for(let r=u+1;r<t&&l(r);r++)y(e[r],n)<y(e[d],n)&&(d=r);let f=ce(e.slice(d));if(!f||f.score>I||re(f.poly)<L*re(ie(f.poly)))return null;let p=f.upright?{...f.bb,x0:f.bb.cx-f.upright.w/2,x1:f.bb.cx+f.upright.w/2,y0:f.bb.cy-f.upright.h/2,y1:f.bb.cy+f.upright.h/2,w:f.upright.w,h:f.upright.h}:f.bb,m=fe(R(f.kind,p),e[d]);return{kind:f.kind,pts:m,from:d,box:x(m)}}function fe(e,t){let n=e.slice(0,-1),r=0;for(let e=1;e<n.length;e++)y(n[e],t)<y(n[r],t)&&(r=e);let i=[...n.slice(r),...n.slice(0,r)];return[...i,[i[0][0],i[0][1]]]}function pe(e,t){let n=e[t],r=e[e.length-1],i=y(n,r);if(i<24)return null;let a=e.slice(t);if(b(a)>1.12*i)return null;for(let e of a)if(C(e,n,r)>.07*i+3)return null;let o=[[n[0],n[1]],[r[0],r[1]]];return{kind:`line`,pts:o,from:t,box:x(o)}}function z(e,t,n,r=!1){let i=y(e,t),a=Math.atan2(t[1]-e[1],t[0]-e[0]),o=Math.min(14/n,i/(r?4:3)),s=3/n,c=[],l=(e,t)=>{let n=Math.max(1,Math.ceil(y(e,t)/s));for(let r=1;r<=n;r++)c.push([e[0]+(t[0]-e[0])*r/n,e[1]+(t[1]-e[1])*r/n])},u=(e,t,n)=>[e[0]-t*o*Math.cos(a+n),e[1]-t*o*Math.sin(a+n)];if(r){let t=u(e,-1,-.5),n=u(e,-1,.5);c.push(t),l(t,e),l(e,n),l(n,e)}else c.push([e[0],e[1]]);return l(e,t),l(t,u(t,1,.5)),l(u(t,1,.5),t),l(t,u(t,1,-.5)),c}var me=(e,t,n,r)=>({x0:e-n/2,y0:t-r/2,x1:e+n/2,y1:t+r/2,w:n,h:r,cx:e,cy:t});function he(e,t,n){let r=[];for(let i=0;i<=32;i++)r.push([e+n*Math.cos(-Math.PI/2+i/32*2*Math.PI),t+n*Math.sin(-Math.PI/2+i/32*2*Math.PI)]);let i=Math.max(2,Math.round(n/2.5));for(let a=0;a<=i*24;a++){let o=a/(i*24),s=n*(1-o),c=-Math.PI/2+o*i*2*Math.PI;r.push([e+s*Math.cos(c),t+s*Math.sin(c)])}return T([...r,[e,t-n]],2)}function B(e,t,n,r,i,a){return e===`dot`?[{pts:he(t,n,r/2)}]:e===`bullseye`?[{pts:R(`circle`,me(t,n,r,i))},{pts:he(t,n,r*.22)}]:[{pts:R(e,me(t,n,r,i)),name:a}]}function V(e,t){let n=T(e,3),r=n[n.length-1],i=e[e.length-2],a=Math.atan2(r[1]-i[1],r[0]-i[0]),o=e=>[r[0]-14*Math.cos(a+e),r[1]-14*Math.sin(a+e)];return{pts:[...n,...T([r,o(.5),r,o(-.5)],2).slice(1)],name:t,line:!0}}function ge(e,t,n=7){let r=t[0]-e.cx,i=t[1]-e.cy,a=Math.min(r?e.w/2/Math.abs(r):1/0,i?e.h/2/Math.abs(i):1/0),o=Math.hypot(r,i)||1;return[e.cx+r*a+r/o*n,e.cy+i*a+i/o*n]}function H(e,t,n,r=0){let i=x(e.flatMap(e=>e.pts)),a=x(t.flatMap(e=>e.pts)),o=a.cx-i.cx,s=a.cy-i.cy,c=Math.hypot(o,s),l=-s/c*r,u=o/c*r,d={...i,cx:i.cx+l,cy:i.cy+u},f={...a,cx:a.cx+l,cy:a.cy+u};return V([ge(d,[f.cx,f.cy]),ge(f,[d.cx,d.cy])],n)}function _e(e,t,n,r){return[...B(`circle`,e,t,n,n,r),...B(`circle`,e,t,n*.72,n*.72)]}var U=[{id:`steps`,label:`Steps in order`,group:`Flowcharts`,diagram:`flowchart`,parts(){let e=B(`stadium`,0,0,140,56,`Start`),t=B(`rect`,0,120,150,64,`First step`),n=B(`rect`,0,240,150,64,`Second step`),r=B(`stadium`,0,360,140,56,`Done`);return[...e,...t,...n,...r,H(e,t),H(t,n),H(n,r)]}},{id:`decision`,label:`A yes-or-no choice`,group:`Flowcharts`,diagram:`flowchart`,parts(){let e=B(`stadium`,0,0,140,56,`Start`),t=B(`diamond`,0,140,140,104,`Ready?`),n=B(`rect`,-120,300,140,64,`Go ahead`),r=B(`rect`,120,300,140,64,`Wait`);return[...e,...t,...n,...r,H(e,t),V([[-70,140],[-120,140],[-120,261]],`Yes`),V([[70,140],[120,140],[120,261]],`No`)]}},{id:`loop`,label:`Try until done`,group:`Flowcharts`,diagram:`flowchart`,parts(){let e=B(`stadium`,0,0,140,56,`Start`),t=B(`rect`,0,120,150,64,`Try`),n=B(`diamond`,0,260,140,104,`Done?`),r=B(`stadium`,0,400,140,56,`Finish`);return[...e,...t,...n,...r,H(e,t),H(t,n),H(n,r,`Yes`),V([[70,260],[150,260],[150,120],[82,120]],`No`)]}},{id:`sign-in`,label:`Sign in, with retries`,group:`Flowcharts`,diagram:`flowchart`,parts(){let e=B(`stadium`,0,0,140,56,`Start`),t=B(`lean-right`,0,120,170,64,`Enter password`),n=B(`diamond`,0,260,140,104,`Correct?`),r=B(`diamond`,210,260,140,104,`Tries left?`),i=B(`stadium`,0,400,140,56,`Signed in`),a=B(`stadium`,210,400,140,56,`Locked out`);return[...e,...t,...n,...r,...i,...a,H(e,t),H(t,n),H(n,i,`Yes`),H(n,r,`No`),V([[210,208],[210,120],[74,120]],`Yes`),H(r,a,`No`)]}},{id:`retry`,label:`A request, retried`,group:`Flowcharts`,diagram:`flowchart`,parts(){let e=B(`stadium`,0,0,140,56,`Start`),t=B(`rect`,0,120,150,64,`Send request`),n=B(`diamond`,0,260,140,104,`Worked?`),r=B(`rect`,210,260,120,64,`Wait`),i=B(`stadium`,0,400,140,56,`Done`);return[...e,...t,...n,...r,...i,H(e,t),H(t,n),H(n,i,`Yes`),H(n,r,`No`),V([[210,224],[210,120],[82,120]])]}},{id:`door`,label:`A door: closed, open, locked`,group:`State diagrams`,diagram:`state`,parts(){let e=B(`dot`,-150,0,30,30),t=B(`rect`,0,0,130,60,`Closed`),n=B(`rect`,230,0,130,60,`Open`),r=B(`rect`,0,160,130,60,`Locked`);return[...e,...t,...n,...r,H(e,t),H(t,n,`open`,-14),H(n,t,`close`,-14),H(t,r,`lock`,24),H(r,t,`unlock`,24)]}},{id:`light`,label:`A traffic light`,group:`State diagrams`,diagram:`state`,parts(){let e=B(`dot`,-170,0,30,30),t=B(`rect`,0,0,120,60,`Red`),n=B(`rect`,210,150,120,60,`Green`),r=B(`rect`,-90,150,120,60,`Yellow`);return[...e,...t,...n,...r,H(e,t),H(t,n,`go`),H(n,r,`slow`),H(r,t,`stop`)]}},{id:`order`,label:`An order, start to end`,group:`State diagrams`,diagram:`state`,parts(){let e=B(`dot`,0,0,30,30),t=B(`rect`,0,110,140,60,`Placed`),n=B(`rect`,0,230,140,60,`Paid`),r=B(`rect`,0,350,140,60,`Shipped`),i=B(`rect`,220,230,140,60,`Canceled`),a=B(`bullseye`,0,460,42,42);return[...e,...t,...n,...r,...i,...a,H(e,t),H(t,n,`pay`),H(n,r,`ship`),H(r,a),H(t,i,`cancel`),V([[220,264],[220,460],[29,460]])]}},{id:`player`,label:`A media player`,group:`State diagrams`,diagram:`state`,parts(){let e=B(`dot`,0,-110,30,30),t=B(`rect`,0,0,130,60,`Stopped`),n=B(`rect`,230,0,130,60,`Playing`),r=B(`rect`,230,160,130,60,`Paused`),i=B(`bullseye`,0,160,42,42);return[...e,...t,...n,...r,...i,H(e,t),H(t,n,`play`,-14),H(n,t,`stop`,-14),H(n,r,`pause`,30),H(r,n,`play`,30),H(r,t,`stop`),H(t,i,`close`)]}},{id:`vending`,label:`A vending machine`,group:`State diagrams`,diagram:`state`,parts(){let e=B(`dot`,-160,0,30,30),t=B(`rect`,0,0,130,60,`Idle`),n=B(`rect`,0,160,130,60,`Paid`),r=B(`rect`,230,160,130,60,`Vending`);return[...e,...t,...n,...r,H(e,t),H(t,n,`coin`,30),H(n,t,`refund`,30),H(n,r,`choose`),V([[230,126],[230,0],[72,0]],`done`)]}},{id:`grind-loop`,label:`Grind loop`,group:`Agent workflows`,diagram:`flowchart`,parts(){let e=B(`rect`,0,0,150,64,`Builder`),t=B(`hexagon`,0,130,150,64,`Tests`),n=_e(0,260,84,`Done`);return[...e,...t,...n,H(e,t),H(t,n,`pass`),V([[75,130],[150,130],[150,0],[82,0]],`fail`)]}},{id:`ralph-loop`,label:`Ralph loop`,group:`Agent workflows`,diagram:`flowchart`,parts(){let e=B(`rect`,0,0,150,64,`Builder`),t=B(`hexagon`,0,130,150,64,`Tests`),n=B(`hexagon`,0,260,150,64,`Plan empty?`),r=_e(0,410,84,`Done`);return[...e,...t,...n,...r,H(e,t),V([[75,130],[150,130],[150,0],[82,0]],`fail`),H(t,n,`pass`),V([[-75,260],[-150,260],[-150,0],[-82,0]],`fail`),H(n,r,`pass`)]}},{id:`red-team-loop`,label:`Red-team loop`,group:`Agent workflows`,diagram:`flowchart`,parts(){let e=B(`rect`,0,0,150,64,`Builder`),t=B(`diamond`,0,140,140,104,`Red team`),n=_e(0,290,84,`Done`);return[...e,...t,...n,H(e,t),H(t,n,`pass`),V([[70,140],[150,140],[150,0],[82,0]],`fail`)]}},{id:`review-gate`,label:`Review gate`,group:`Agent workflows`,diagram:`flowchart`,parts(){let e=B(`rect`,0,0,150,64,`Builder`),t=B(`diamond`,0,140,140,104,`Critic`),n=B(`trapezoid`,0,290,170,64,`Merge approval`),r=_e(0,450,84,`Done`);return[...e,...t,...n,...r,H(e,t),V([[70,140],[150,140],[150,0],[82,0]],`fail`),H(t,n,`pass`),H(n,r,`pass`),V([[-70,290],[-150,290],[-150,0],[-82,0]],`fail`)]}},{id:`spec-then-loop`,label:`Spec then loop`,group:`Agent workflows`,diagram:`flowchart`,parts(){let e=B(`rect`,0,0,150,64,`Planner`),t=B(`trapezoid`,0,130,170,64,`Spec approval`),n=B(`rect`,0,260,150,64,`Builder`),r=B(`diamond`,0,400,140,104,`Critic`),i=_e(0,550,84,`Done`);return[...e,...t,...n,...r,...i,H(e,t),H(t,n,`pass`),H(n,r),V([[70,400],[150,400],[150,260],[82,260]],`fail`),H(r,i,`pass`)]}},{id:`human-gated-irreversible`,label:`Human gate, then act`,group:`Agent workflows`,diagram:`flowchart`,parts(){let e=B(`trapezoid`,0,0,160,64,`Step approval`),t=B(`rect`,0,120,180,64,`Irreversible step`),n=_e(0,240,84,`Done`);return[...e,...t,...n,H(e,t,`pass`),H(t,n)]}},{id:`debate-then-build`,label:`Debate then build`,group:`Agent workflows`,diagram:`flowchart`,parts(){let e=B(`rect`,-110,0,150,64,`Planner A`),t=B(`rect`,110,0,150,64,`Planner B`),n=B(`diamond`,110,140,140,104,`Judge`),r=B(`trapezoid`,110,290,170,64,`Plan approval`),i=B(`rect`,-110,290,150,64,`Builder`),a=B(`hexagon`,-110,420,150,64,`Tests`),o=_e(-110,550,84,`Done`);return[...e,...t,...n,...r,...i,...a,...o,H(e,t),H(t,n),V([[40,140],[-110,140],[-110,39]],`verdict: rebut`),H(n,r,`pass`),V([[40,290],[-28,290]],`pass`),H(i,a),V([[-185,420],[-240,420],[-240,290],[-192,290]],`fail`),H(a,o,`pass`)]}},{id:`tournament-then-judge`,label:`Tournament then judge`,group:`Agent workflows`,diagram:`flowchart`,parts(){let e=B(`rect`,-150,0,124,64,`Candidate A`),t=B(`rect`,0,0,124,64,`Candidate B`),n=B(`rect`,150,0,124,64,`Candidate C`),r=B(`hexagon`,0,150,170,64,`Finalist filter`),i=B(`diamond`,0,290,140,104,`Judge`),a=B(`rect`,0,430,150,64,`Finisher`),o=_e(0,560,84,`Done`);return[...e,...t,...n,...r,...i,...a,...o,H(e,r),H(t,r),H(n,r),H(r,i,`pass`),H(i,a,`pass`),H(a,o)]}}],W={rect:[`[`,`]`],subroutine:[`[[`,`]]`],stadium:[`([`,`])`],circle:[`((`,`))`],double:[`(((`,`)))`],diamond:[`{`,`}`],hexagon:[`{{`,`}}`],trapezoid:[`[/`,`\\]`],"inv-trapezoid":[`[\\`,`/]`],"lean-right":[`[/`,`/]`],"lean-left":[`[\\`,`\\]`],triangle:`tri`,"flip-triangle":`flip-tri`,dot:`sm-circ`,bullseye:`fr-circ`};function G(e,t,n){let r=W[t];return typeof r==`string`?`${e}@{ shape: ${r}, label: "${n.replace(/\\/g,`#92;`)}" }`:`${e}${r[0]}"${n}"${r[1]}`}var K=e=>String(e).replace(/[\x00-\x1f\x7f]+/g,` `).replace(/[#&<>"]/g,e=>`#`+e.charCodeAt(0)+`;`);function q(e){switch(e.kind){case`agent`:return s(e)?`diamond`:c(e)?`rect`:`stadium`;case`check`:return`hexagon`;case`human-gate`:return`trapezoid`;case`merge`:return`circle`;case`stop`:return`double`}}var ve={rect:`agent`,subroutine:`agent`,"lean-right":`agent`,"lean-left":`agent`,"inv-trapezoid":`agent`,triangle:`agent`,"flip-triangle":`agent`,stadium:`other agent`,diamond:`critic`,hexagon:`check`,trapezoid:`human-gate`,circle:`merge`,double:`stop`,bullseye:`stop`,dot:`start`},J=e=>ve[q(e)];function ye(e){let t=e.when??`always`;return[t===`always`?``:typeof t==`string`?t:`verdict: ${t.verdict}`,e.approval?`approval`:``].filter(e=>e!==``).join(`, `)||e.label||``}var be={rect:[150,64],stadium:[150,60],diamond:[140,104],hexagon:[150,64],trapezoid:[170,64],circle:[84,84],double:[84,84]},xe=[.85,.9],Se=[1,1.2];function Y(e,t){let n=T(e,3),r=n[n.length-1],i=e[e.length-2],a=Math.atan2(r[1]-i[1],r[0]-i[0]),o=e=>[r[0]-14*Math.cos(a+e),r[1]-14*Math.sin(a+e)];return{pts:[...n,...T([r,o(.5),r,o(-.5)],2).slice(1)],...t?{name:t}:{},line:!0}}function Ce(e,t,n=7){let r=t[0]-e.cx,i=t[1]-e.cy,a=Math.min(r?e.w/2/Math.abs(r):1/0,i?e.h/2/Math.abs(i):1/0),o=Math.hypot(r,i)||1;return[e.cx+r*a+r/o*n,e.cy+i*a+i/o*n]}function we(e,t,n,r=8){let i=n.x0-r,a=n.x1+r,o=n.y0-r,s=n.y1+r,c=0,l=1,u=t[0]-e[0],d=t[1]-e[1];for(let[t,n]of[[-u,e[0]-i],[u,a-e[0]],[-d,e[1]-o],[d,s-e[1]]])if(t===0){if(n<0)return!1}else{let e=n/t;if(t<0?c=Math.max(c,e):l=Math.min(l,e),c>l)return!1}return!0}function Te(e,t){let n=[],r=new Map;for(let i of e.nodes){let a=t[i.id]??{x:0,y:0},o=q(i),[s,c]=be[o],l=e.groups?.length?Se:xe,u=(a.x+100)*l[0],d=(a.y+42)*l[1],f=i.name||i.id,p=o===`double`?[...B(`circle`,u,d,s,c,f),...B(`circle`,u,d,s*.72,c*.72)]:B(o,u,d,s,c,f);for(let e of p)n.push({...e,mark:{node:i.id}});r.set(i.id,x(p.flatMap(e=>e.pts)))}let i=e.groups??[],a=new Map,o=(t,n)=>{if(a.has(t.id))return a.get(t.id);if(n.has(t.id))return;n.add(t.id);let s=t.members.flatMap(e=>{let t=r.get(e)??(i.find(t=>t.id===e)?o(i.find(t=>t.id===e),n):void 0);return t?[t]:[]});if(s.length===0)return;let c=s.length===1&&t.members.length===1?e.nodes.find(e=>e.id===t.members[0]):void 0,l=c&&[`stadium`,`circle`,`double`].includes(q(c))?s[0].w*.55:30,u=Math.min(...s.map(e=>e.x0))-l,d=Math.max(...s.map(e=>e.x1))+l,f=Math.min(...s.map(e=>e.y0))-30-22,p=Math.max(...s.map(e=>e.y1))+30,m={x0:u,x1:d,y0:f,y1:p,w:d-u,h:p-f,cx:(u+d)/2,cy:(f+p)/2};return a.set(t.id,m),m},s=new Map(i.map(e=>[e.id,e])),c=(e,t=new Set)=>(t.add(e.id),new Set(e.members.flatMap(e=>s.has(e)?t.has(e)?[]:[...c(s.get(e),t)]:[e]))),l=(e,t)=>e.x0<t.x1&&t.x0<e.x1&&e.y0<t.y1&&t.y0<e.y1,u=new Map,d=new Map,f=(e,t=new Set)=>{if(d.has(e.id))return d.get(e.id);if(t.has(e.id))return!1;t.add(e.id);let n=e.members.filter(e=>s.has(e)),i=n.map(e=>f(s.get(e),t)).every(Boolean),a=o(e,new Set),m=i&&a!==void 0;if(m){let t={...a,x0:a.x0-8,x1:a.x1+8,y0:a.y0-8,y1:a.y1+8},i=c(e),o=new Set(n.flatMap(e=>[e,...p(e)]));m=[...r].every(([e,n])=>i.has(e)||!l(n,t))&&[...u].every(([e,n])=>o.has(e)||!l(n,t))}return d.set(e.id,m),m&&u.set(e.id,a),m};function p(e,t=new Set){let n=s.get(e);if(!n||t.has(e))return t;t.add(e);for(let e of n.members)s.has(e)&&p(e,t);return t}let m=[];for(let e of i)f(e)||m.push(e.id);for(let e of i){let t=u.get(e.id);if(t)for(let r of B(`rect`,t.cx,t.cy,t.w,t.h,e.name||e.id))n.push({...r,mark:{group:e.id}})}let h=[...r.values()],g=new Map;for(let t of e.edges){if(!r.has(t.from)||!r.has(t.to))continue;let e=[t.from,t.to].sort().join(`\0`);(g.get(e)??g.set(e,[]).get(e)).push(t)}let _={right:0,left:0},v=(e,t)=>h.some(n=>n!==e&&n.y1>e.y0&&n.y0<e.y1&&(t===`right`?n.x0>=e.x1-1:n.x1<=e.x0+1));for(let t of e.edges){let e=r.get(t.from),n=r.get(t.to);if(!e||!n)continue;let i=ye(t);if(t.from===t.to){let n=e.x1+7,r=e.x1+44;y(t,Y([[n,e.cy-16],[r,e.cy-16],[r,e.cy+16],[n,e.cy+16]],i));continue}let a=g.get([t.from,t.to].sort().join(`\0`)),o=a.length>1?(a.indexOf(t)-(a.length-1)/2)*30*(t.from<t.to?1:-1):0,s=n.cx-e.cx,c=n.cy-e.cy,l=Math.hypot(s,c)||1,u=-c/l*o,d=s/l*o,f={...e,cx:e.cx+u,cy:e.cy+d},p={...n,cx:n.cx+u,cy:n.cy+d},m=Ce(f,[p.cx,p.cy]),b=Ce(p,[f.cx,f.cy]);if(!h.some(t=>t!==e&&t!==n&&we(m,b,t))){y(t,Y([m,b],i));continue}let x=n.cy<=e.cy,S=t=>!v(e,t)&&!v(n,t),ee=S(x?`right`:`left`)?x?`right`:`left`:S(x?`left`:`right`)?x?`left`:`right`:void 0;if(!ee){y(t,Y([m,b],i));continue}let C=Math.min(e.y0,n.y0),w=Math.max(e.y1,n.y1),te=h.filter(e=>e.y1>C&&e.y0<w),ne=_[ee]++,T=ee===`right`?Math.max(...te.map(e=>e.x1))+34+24*ne:Math.min(...te.map(e=>e.x0))-34-24*ne,E=ee===`right`?e.x1+7:e.x0-7,re=ee===`right`?n.x1+7:n.x0-7;y(t,Y([[E,e.cy],[T,e.cy],[T,n.cy],[re,n.cy]],i))}return{parts:n,unboxed:m};function y(e,t){n.push({...t,mark:{edge:e.id}})}}function Ee(e,t,n){let r=new Set(e),i=new Map;for(let e of t)(i.get(e.from)??i.set(e.from,[]).get(e.from)).push(e);let a=n.find(e=>!r.has(e.from)&&r.has(e.to))?.to??e[0],o=new Map,s=[],c=e=>{o.set(e,`on`);for(let t of i.get(e)??[]){let e=o.get(t.to);e===`on`?s.push(t.id):e||c(t.to)}o.set(e,`done`)};for(let t of[a,...e])o.has(t)||c(t);return s}function De(e,t){let n=e=>Array.isArray(e)?e.map(n):e&&typeof e==`object`?Object.fromEntries(Object.keys(e).sort().map(t=>[t,n(e[t])])):e;return JSON.stringify(n(e))===JSON.stringify(n(t))}function Oe(e,t,n,o,s=[]){let c=new Set(e.nodes.filter(e=>e.kind===`dot`).map(e=>e.id)),u=e.nodes.filter(e=>!c.has(e.id)).map(e=>e.kind===`bullseye`?{...e,kind:`double`}:e);if(u.length===0)return{error:c.size?`Only a start dot was read. Draw the steps, like a box or a diamond, and the arrows between them.`:`No shapes were read. Draw a closed shape, like a box or a circle.`};let f=new Map(e.groups.map(e=>[e.id,e])),p=new Map([...u,...e.groups].map(e=>[e.id,e.poly])),m=(e,t)=>{for(let n=t.parent;n!==null;n=f.get(n)?.parent??null)if(n===e)return!0;return!1},h=(e,t,n)=>{let r=[e.pts[0],e.pts[e.pts.length-1]];if(t===n)return t===e.from?r[0]:r[1];let i=e=>w(e,p.get(t)??[])-w(e,p.get(n)??[]);return i(r[0])<=i(r[1])?r[0]:r[1]},g=(e,t,n)=>u.filter(t=>m(e,t)&&t.id!==n).sort((e,n)=>w(t,e.poly)-w(t,n.poly))[0]?.id,_=0,v=e.edges.filter(e=>!c.has(e.from)&&!c.has(e.to)).flatMap(e=>{let t=f.has(e.from)?g(e.from,h(e,e.from,e.to),e.to):e.from,n=f.has(e.to)?g(e.to,h(e,e.to,e.from),e.from):e.to;return t&&n?[{...e,from:t,to:n}]:(_++,[])}),y=e=>t[e]?.replace(/\s+/g,` `).trim()??``,b=new Map(o.nodes.map(e=>[e.id,e])),x=new Map,S=new Set;for(let e of u){let t=n.nodes[e.id],r=t===void 0?void 0:b.get(t);r&&!S.has(r.id)&&(x.set(e.id,r),S.add(r.id))}for(let e of u){if(x.has(e.id)||!y(e.id))continue;let t=o.nodes.filter(t=>!S.has(t.id)&&(t.name||t.id)===y(e.id));t.length===1&&(x.set(e.id,t[0]),S.add(t[0].id))}let ee=e=>y(e.id)||(x.get(e.id)?.name??``)||e.label,C=new Map((o.groups??[]).map(e=>[e.id,e])),te=e=>y(e.id)||C.get(n.groups[e.id]??``)?.name||e.label,ne=[`flowchart TD`,...u.map(e=>` ${G(e.id,e.kind,K(ee(e)))}`)],T=[];for(let e of v)for(let[t,n]of e.both?[[e.from,e.to],[e.to,e.from]]:[[e.from,e.to]]){let r=y(e.id);ne.push(` ${t} -->${r?`|"${K(r)}"|`:``} ${n}`),T.push({line:e,from:t.toLowerCase(),to:n.toLowerCase()})}let E=ne.join(`
|
|
2
|
+
`),re=d(E,{name:`sketch read`});if(!re.ok)return{error:`grooph could not read the drawing: ${re.error}`};let ie=re.doc,ae=i(o),oe=e=>{let t=r(e,ae);return ae.add(t),t},se={nodes:{},edges:{},groups:{}},D=new Map,O=[],k=new Set,A=0;for(let e of u){let t=ie.nodes.find(t=>t.id===e.id.toLowerCase());if(!t)continue;let n=x.get(e.id),r=ee(e),i;n&&J(n)===ve[e.kind]?(i={...n,name:r},k.add(r)):n&&n.kind===`agent`&&t.kind===`agent`?i={...n,name:r,role:t.role}:n?i={...t,id:n.id,name:r}:(i={...t,id:oe(a(r,`step`)),name:r},A++),D.set(t.id,i.id),se.nodes[e.id]=i.id,O.push(i)}let j=(e,t)=>{let n=new Map(t.map((e,t)=>[e.id,t]));return e.map((e,r)=>[e,n.get(e.id)??t.length+r]).sort((e,t)=>e[1]-t[1]).map(([e])=>e)},M=o.edges.filter(e=>S.has(e.from)&&S.has(e.to)),ce=new Set,N=new Set,P=new Map,le=[];for(let e of ie.edges){let t=D.get(e.from),r=D.get(e.to);if(!t||!r)continue;let i=T.findIndex((t,n)=>!N.has(n)&&t.from===e.from&&t.to===e.to);i>=0&&N.add(i);let a=i>=0?T[i].line:void 0,o=e.label!==void 0&&a&&y(a.id)?{...e,label:y(a.id)}:e,s=a?n.edges[a.id]:void 0,c=M.filter(e=>!ce.has(e.id)&&e.from===t&&e.to===r),l=c.find(e=>e.id===s)??c[0],u;if(l){if(ce.add(l.id),a===void 0||s!==l.id&&y(a.id)===``||y(a.id)===ye(l))u=l;else{let{when:e,approval:t,label:n,...r}=l;u={...r,...o.when===void 0?{}:{when:o.when},...o.approval?{approval:!0}:{},...o.label===void 0?{}:{label:o.label}}}}else u={...o,id:oe(`${t}-to-${r}`),from:t,to:r};P.set(e.id,u.id),a&&se.edges[a.id]===void 0&&(se.edges[a.id]=u.id),le.push(u)}let F=new Set(le.map(e=>e.id)),I=new Set(O.map(e=>e.id)),L=o.loops.filter(e=>e.back.every(e=>F.has(e))&&e.members.every(e=>I.has(e))),R=o.loops.filter(e=>!L.includes(e));for(let e of L)k.add(e.name);for(let e of ie.loops){let t=e.members.map(e=>D.get(e)).filter(e=>e!==void 0),n=e.back.map(e=>P.get(e)).filter(e=>e!==void 0);if(t.length===0||n.length===0)continue;let r=new Set(L.filter(e=>e.members.some(e=>t.includes(e))).flatMap(e=>e.members));if(t.every(e=>r.has(e))){k.add(e.name);continue}let i=new Set(t),a=new Set(L.flatMap(e=>e.back)),o=Ee(t,le.filter(e=>i.has(e.from)&&i.has(e.to)&&!a.has(e.id)),le);if(o.length===0){let n=e=>le.some(t=>t.id===e&&i.has(t.from)&&i.has(t.to)),r=L.filter(e=>e.back.some(n)).sort((e,t)=>t.members.length-e.members.length)[0];r&&(L[L.indexOf(r)]={...r,members:[...r.members,...t.filter(e=>!r.members.includes(e))]}),k.add(e.name);continue}let s=e=>e.members.filter(e=>t.includes(e)).length/new Set([...e.members,...t]).size,c=R.filter(e=>s(e)>=.5).sort((e,t)=>s(t)-s(e))[0];c?(R.splice(R.indexOf(c),1),k.add(e.name),L.push({...c,members:t,back:o})):L.push({...e,id:oe(`${t[0]}-loop`),members:t,back:o})}let ue=new Set,de=[],fe=new Map;for(let t of e.groups){let e=n.groups[t.id],r=e!==void 0&&!ue.has(e)?C.get(e):void 0;r&&ue.add(r.id),fe.set(t.id,r?r.id:oe(a(te(t),`box`)))}let pe=new Map(u.map(e=>[e.id,se.nodes[e.id]])),z=e.groups.flatMap(t=>{let n=fe.get(t.id),r=[...u.filter(e=>e.parent===t.id).map(e=>pe.get(e.id)),...e.groups.filter(e=>e.parent===t.id).map(e=>fe.get(e.id))],i=C.get(n),a=new Map((i?.members??[]).map((e,t)=>[e,t])),o=r.filter(e=>e!==void 0).map((e,t)=>[e,a.get(e)??1e6+t]).sort((e,t)=>e[1]-t[1]).map(([e])=>e);if(o.length===0)return[];se.groups[t.id]=n;let s=te(t);return i||de.push(`${s}: a box drawn round steps, so a group`),[i?{...i,name:s,members:o}:{id:n,name:s,members:o}]}),me=new Set((o.groups??[]).filter(e=>s.includes(e.id)&&!ue.has(e.id)).map(e=>e.id)),he=new Set(O.map(e=>e.id));for(let e of o.groups??[]){if(!me.has(e.id))continue;let t=e.members.filter(e=>he.has(e)||me.has(e)||ue.has(e));t.length&&z.push(t.length===e.members.length?e:{...e,members:t})}let B=new Set([o.id,...O.map(e=>e.id),...le.map(e=>e.id),...L.map(e=>e.id),...z.map(e=>e.id)]),V=(o.policies??[]).filter(e=>e.scope===`graph`||B.has(e.scope.slice(e.scope.indexOf(`:`)+1))),ge=e=>e.bar?.answerKeyFrom!==void 0&&!B.has(e.bar.answerKeyFrom)?{...e,bar:(({answerKeyFrom:e,...t})=>t)(e.bar)}:e,H=e=>e.stops.map(e=>e.then!==void 0&&!B.has(e.then)?(({then:e,...t})=>t)(e):e),_e=o.layout?Object.fromEntries(Object.entries(o.layout).filter(([e])=>B.has(e))):void 0,U={...o,nodes:j(O,o.nodes),edges:j(le,o.edges),loops:j(L,o.loops).map(e=>({...ge(e),stops:H(e)}))};V.length?U.policies=V:delete U.policies,z.length?U.groups=j(z,o.groups??[]):delete U.groups,_e&&Object.keys(_e).length?U.layout=_e:delete U.layout;let W=l(U);if(!W.doc)return{error:`The drawing made a graph grooph cannot keep: ${W.issues[0]?.message??`it does not match the schema`}`};let q=[...re.guesses.filter(e=>!k.has(e.slice(0,e.indexOf(`: `)))).map(e=>e.replace(`: a stadium, so `,`: an oval, so `)),...de],be=[c.size?`${c.size===1?`The start dot is`:`${c.size} start dots are`} not a step: a run starts at the steps nothing leads to.`:``,_?`${_===1?`A line that ends`:`${_} lines that end`} on a box with no other step in it ${_===1?`was`:`were`} left out.`:``].filter(Boolean).join(` `)||void 0;return{doc:U,guesses:q,became:se,counts:{added:A,kept:S.size,removed:o.nodes.length-S.size},mermaid:E,...be?{left:be}:{}}}var ke=`
|
|
3
|
+
<section class="sk-draw" aria-label="Drawing">
|
|
4
|
+
<div class="sk-bar" role="toolbar" aria-label="Drawing tools">
|
|
5
|
+
<div class="sk-tools-row">
|
|
6
|
+
<div class="sk-tools">
|
|
7
|
+
<div class="sk-seg" role="radiogroup" aria-label="Tool">
|
|
8
|
+
<button type="button" role="radio" aria-checked="true" data-tool="draw" title="Pen (D)">
|
|
9
|
+
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M3.5 16.5 4.4 13 13 4.4a1.8 1.8 0 0 1 2.6 2.6L7 15.6Z" /><path d="m11.6 5.8 2.6 2.6" /></svg><span>Pen</span>
|
|
10
|
+
</button>
|
|
11
|
+
<button type="button" role="radio" aria-checked="false" data-tool="erase" data-options="eraser" title="Eraser (E). Tap it again to erase whole strokes or only what it passes over" aria-describedby="sk-tool-kinds">
|
|
12
|
+
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M8.2 16.5h8.3M3.9 12.2l7.5-7.5a1.6 1.6 0 0 1 2.3 0l2.6 2.6a1.6 1.6 0 0 1 0 2.3l-6.3 6.3a2 2 0 0 1-1.4.6H6.8a2 2 0 0 1-1.4-.6l-1.5-1.5a1.6 1.6 0 0 1 0-2.2Z" /><path d="m7.3 8.8 4.8 4.8" /></svg><span>Eraser</span>
|
|
13
|
+
</button>
|
|
14
|
+
<button type="button" role="radio" aria-checked="false" data-tool="select" data-options="select" title="Select (V): press a stroke to move it, or drag a box around strokes. Tap it again for a lasso" aria-describedby="sk-tool-kinds">
|
|
15
|
+
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M4.5 3.2 15.3 9l-4.7 1.3-2.2 4.4Z" /><path d="m10.6 10.3 3.6 4.9" /></svg><span>Select</span>
|
|
16
|
+
</button>
|
|
17
|
+
<button type="button" role="radio" aria-checked="false" data-tool="hand" title="Hand (H): drag to move around the drawing. Space and a drag does the same">
|
|
18
|
+
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M7 10.5V5.2a1.2 1.2 0 0 1 2.4 0v4.3M9.4 9.5V4a1.2 1.2 0 0 1 2.4 0v5.5M11.8 9.5V5a1.2 1.2 0 0 1 2.4 0v6.2c0 3.2-2 5.3-4.8 5.3-2 0-3.2-.9-4.3-2.6L3.5 11.2a1.2 1.2 0 0 1 2-1.3L7 12" /></svg><span>Hand</span>
|
|
19
|
+
</button>
|
|
20
|
+
</div>
|
|
21
|
+
<ul class="sk-menu sk-tool-menu" id="sk-tool-menu" role="menu" hidden></ul>
|
|
22
|
+
<span class="sr-only" id="sk-tool-kinds">Once chosen, press again for its kinds.</span>
|
|
23
|
+
</div>
|
|
24
|
+
<span class="sk-rule" aria-hidden="true"></span>
|
|
25
|
+
<fieldset class="sk-inks" id="sk-inks">
|
|
26
|
+
<legend class="sr-only">Ink</legend>
|
|
27
|
+
</fieldset>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="sk-tools-row">
|
|
30
|
+
<button class="sk-icon" type="button" id="sk-undo" aria-label="Undo" title="Undo (Ctrl+Z)" disabled>
|
|
31
|
+
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M7.5 5 4 8.5 7.5 12" /><path d="M4.5 8.5h7.2a4.3 4.3 0 0 1 0 8.6H9" /></svg>
|
|
32
|
+
</button>
|
|
33
|
+
<button class="sk-icon" type="button" id="sk-redo" aria-label="Redo" title="Redo (Ctrl+Shift+Z)" disabled>
|
|
34
|
+
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M12.5 5 16 8.5 12.5 12" /><path d="M15.5 8.5H8.3a4.3 4.3 0 0 0 0 8.6H11" /></svg>
|
|
35
|
+
</button>
|
|
36
|
+
<button class="sk-icon" type="button" id="sk-clear" aria-label="Clear the drawing" title="Clear the drawing (Undo brings it back)" disabled>
|
|
37
|
+
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M3.8 5.8h12.4M8 5.8V4.2h4v1.6M5.4 5.8l.8 10a1.4 1.4 0 0 0 1.4 1.3h4.8a1.4 1.4 0 0 0 1.4-1.3l.8-10M8.6 9v4.8M11.4 9v4.8" /></svg>
|
|
38
|
+
</button>
|
|
39
|
+
<span class="sk-rule" aria-hidden="true"></span>
|
|
40
|
+
<div class="sk-more sk-add">
|
|
41
|
+
<button class="sk-icon" type="button" id="sk-add" aria-haspopup="menu" aria-expanded="false" aria-controls="sk-add-list" aria-label="Add a step, an arrow, or a template" title="Add a step, an arrow, or a template">
|
|
42
|
+
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M10 4.2v11.6M4.2 10h11.6" /></svg>
|
|
43
|
+
</button>
|
|
44
|
+
<div class="sk-menu sk-add-menu" id="sk-add-list" role="menu" aria-label="Add" hidden></div>
|
|
45
|
+
</div>
|
|
46
|
+
<div class="sk-more">
|
|
47
|
+
<button class="sk-icon" type="button" id="sk-more" aria-haspopup="menu" aria-expanded="false" aria-controls="sk-more-list" aria-label="More" title="More">
|
|
48
|
+
<svg viewBox="0 0 20 20" aria-hidden="true"><circle cx="4.5" cy="10" r="1.4" /><circle cx="10" cy="10" r="1.4" /><circle cx="15.5" cy="10" r="1.4" /></svg>
|
|
49
|
+
</button>
|
|
50
|
+
<ul class="sk-menu" id="sk-more-list" role="menu" aria-label="More" hidden>
|
|
51
|
+
<li role="none"><button type="button" role="menuitem" data-act="example">Load the example</button></li>
|
|
52
|
+
<li role="none"><button type="button" role="menuitem" data-act="redraw">Draw the graph again</button></li>
|
|
53
|
+
<li role="none"><button type="button" role="menuitem" data-act="fit">Fit the drawing to the screen</button></li>
|
|
54
|
+
<li role="none"><button type="button" role="menuitemcheckbox" aria-checked="true" data-act="snap">Snap shapes and arrows when you hold</button></li>
|
|
55
|
+
<li role="none"><button type="button" role="menuitemcheckbox" aria-checked="true" data-act="names">Show names on the drawing</button></li>
|
|
56
|
+
<li role="none"><button type="button" role="menuitemcheckbox" aria-checked="true" data-act="outlines">Show what it read</button></li>
|
|
57
|
+
<li role="separator"></li>
|
|
58
|
+
<li role="none"><button type="button" role="menuitem" data-act="save-drawing">Save the drawing (.json)</button></li>
|
|
59
|
+
<li role="none"><button type="button" role="menuitem" data-act="open-drawing">Open a drawing…</button></li>
|
|
60
|
+
</ul>
|
|
61
|
+
<input type="file" id="sk-open-file" accept=".json,application/json" hidden />
|
|
62
|
+
</div>
|
|
63
|
+
<span class="sk-spacer"></span>
|
|
64
|
+
<button class="sk-go" type="button" id="sk-go" data-stale="false" title="Make it a graph (Ctrl+Enter)">
|
|
65
|
+
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M3 10.2c1.6-3.4 3.4-3.4 5 0s3.4 3.4 5 0" /><path d="m13.5 6.5 3.5 3.7-3.5 3.7" /></svg>Make it a graph
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="sk-pad" id="sk-pad-wrap">
|
|
70
|
+
<canvas id="sk-pad" role="img" aria-label="Drawing area. Draw the steps and the arrows that join them, then press Make it a graph."></canvas>
|
|
71
|
+
<div class="sk-hint" id="sk-hint">
|
|
72
|
+
<p><strong>Draw a graph here.</strong> Boxes, ovals, diamonds, and the other shapes, joined by arrows, in any order. Hold still at the end of a shape to tidy it, then press Make it a graph. The plus adds steps, arrows, and templates.</p>
|
|
73
|
+
<button class="btn" type="button" id="sk-hint-example">Load the example</button>
|
|
74
|
+
</div>
|
|
75
|
+
<p class="sk-chip" id="sk-pen-chip" hidden>
|
|
76
|
+
<span>Pen draws; fingers move the drawing.</span>
|
|
77
|
+
<button type="button" id="sk-fingers-draw">Let fingers draw</button>
|
|
78
|
+
</p>
|
|
79
|
+
<div class="sk-corner">
|
|
80
|
+
<button class="sk-zoom" type="button" id="sk-zoom" title="Fit the drawing to the screen" hidden></button>
|
|
81
|
+
<button class="sk-full" type="button" id="sk-full" aria-pressed="false" aria-label="Full screen" title="Full screen (F)">
|
|
82
|
+
<svg viewBox="0 0 20 20" aria-hidden="true"><path class="sk-enter" d="M3.5 7.5v-4h4M12.5 3.5h4v4M16.5 12.5v4h-4M7.5 16.5h-4v-4" /><path class="sk-leave" d="M7.5 3.5v4h-4M16.5 7.5h-4v-4M12.5 16.5v-4h4M3.5 12.5h4v4" /></svg>
|
|
83
|
+
</button>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="sk-sel-bar" id="sk-sel-bar" role="toolbar" aria-label="Chosen strokes" hidden>
|
|
86
|
+
<button type="button" data-sel="cut">Cut</button>
|
|
87
|
+
<button type="button" data-sel="copy">Copy</button>
|
|
88
|
+
<button type="button" data-sel="paste">Paste</button>
|
|
89
|
+
<button type="button" data-sel="duplicate">Duplicate</button>
|
|
90
|
+
<button type="button" data-sel="group">Group</button>
|
|
91
|
+
<button type="button" data-sel="snap" title="Make the chosen shapes and arrows clean">Snap</button>
|
|
92
|
+
<button type="button" data-sel="delete">Delete</button>
|
|
93
|
+
</div>
|
|
94
|
+
<form class="sk-name-edit" id="sk-name-edit" hidden>
|
|
95
|
+
<label class="sr-only" for="sk-name-input" id="sk-name-label">Name</label>
|
|
96
|
+
<input id="sk-name-input" type="text" autocomplete="off" enterkeyhint="done" maxlength="120" data-own-undo />
|
|
97
|
+
</form>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="sk-read-row">
|
|
100
|
+
<p class="sk-read" id="sk-read" aria-live="polite">Nothing read yet.</p>
|
|
101
|
+
<label class="sk-check"><input type="checkbox" id="sk-show-read" checked /> Show what it read</label>
|
|
102
|
+
</div>
|
|
103
|
+
</section>
|
|
104
|
+
|
|
105
|
+
<section class="sk-result" id="sk-result" aria-label="The graph">
|
|
106
|
+
<a class="sk-back" href="#sk-pad-wrap" id="sk-back">Back to the drawing</a>
|
|
107
|
+
<div class="sk-panel">
|
|
108
|
+
<div class="sk-panel-head">
|
|
109
|
+
<h2>Graph</h2>
|
|
110
|
+
<span id="sk-graph-hint">Tap a step to open it</span>
|
|
111
|
+
</div>
|
|
112
|
+
<div class="sk-diagram" id="sk-diagram"><p class="sk-empty">The graph appears here after Make it a graph.</p></div>
|
|
113
|
+
<ul class="sk-guesses" id="sk-guesses" aria-label="What was guessed" hidden></ul>
|
|
114
|
+
<div class="sk-row">
|
|
115
|
+
<button class="btn" type="button" id="sk-undo-make" hidden>Undo Make it a graph</button>
|
|
116
|
+
<button class="btn" type="button" id="sk-save-svg" disabled>Save SVG</button>
|
|
117
|
+
<button class="btn" type="button" id="sk-save-png" disabled>Save PNG</button>
|
|
118
|
+
<button class="btn" type="button" id="sk-export" title="Share a link, embed it, or download the package">Export…</button>
|
|
119
|
+
<span class="sk-status" id="sk-save-status" role="status"></span>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
<div class="sk-panel">
|
|
123
|
+
<div class="sk-panel-head">
|
|
124
|
+
<h2>Names</h2>
|
|
125
|
+
<span id="sk-names-note">Each step's and line's name, and what each shape makes</span>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="sk-names" id="sk-names"><p class="sk-status">Shapes appear here after Make it a graph.</p></div>
|
|
128
|
+
<p class="sk-note">Name a line <strong>pass</strong> or <strong>fail</strong> and it is followed only on that result; <strong>approval</strong> asks a person first.</p>
|
|
129
|
+
</div>
|
|
130
|
+
<div class="sk-panel">
|
|
131
|
+
<div class="sk-panel-head">
|
|
132
|
+
<h2><label for="sk-code">Mermaid code</label></h2>
|
|
133
|
+
<span>The graph as Mermaid, as grooph writes it</span>
|
|
134
|
+
</div>
|
|
135
|
+
<textarea class="sk-code" id="sk-code" readonly spellcheck="false" autocapitalize="off" autocomplete="off" autocorrect="off" rows="12"></textarea>
|
|
136
|
+
<div class="sk-row">
|
|
137
|
+
<button class="btn" type="button" id="sk-copy">Copy code</button>
|
|
138
|
+
<button class="btn" type="button" id="sk-save-mmd">Save .mmd</button>
|
|
139
|
+
<span class="sk-status" id="sk-copy-status" role="status"></span>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</section>`;function Ae(e,t=1){if(e.length<3)return!1;let n=t>=.01&&t<=100?t:1,r=e.map(([e,t])=>[e*n,t*n]),i=b(r),a=x(r);return Math.max(a.w,a.h)>=28&&Math.min(a.w,a.h)>=18&&i>1.3*(a.w+a.h)&&le(r,i)<Math.max(14,.22*Math.hypot(a.w,a.h))}function je(e,t,n,r,i=3){let a=new Map,o=[];if(!t.length||!(n>0))return{strokes:e.slice(),pieces:a};let s=x(t),c=e=>{if(e[0]<s.x0-n||e[0]>s.x1+n||e[1]<s.y0-n||e[1]>s.y1+n)return!1;if(t.length===1)return y(e,t[0])<=n;for(let r=0;r<t.length-1;r++)if(C(e,t[r],t[r+1])<=n)return!0;return!1};for(let t of e){let e=x(t.pts);if(!t.pts.length||e.x1<s.x0-n||e.x0>s.x1+n||e.y1<s.y0-n||e.y0>s.y1+n){o.push(t);continue}let l=[],u=[];for(let e=0;e<t.pts.length;e++){let r=t.pts[e],i=t.pts[e+1];if(l.push(r),u.push(!0),!i)break;let a=Math.ceil(y(r,i)/(n/4));for(let e=1;e<a;e++)l.push([r[0]+(i[0]-r[0])*e/a,r[1]+(i[1]-r[1])*e/a]),u.push(!1)}let d=l.map(c);if(!d.some(Boolean)){o.push(t);continue}let f=[],p=[];l.forEach((e,t)=>{d[t]?(p.length&&f.push(p),p=[]):(u[t]||d[t-1]||d[t+1])&&p.push(e)}),p.length&&f.push(p),f.length>=2&&!t.open&&!d[0]&&!d[l.length-1]&&Ae(t.pts,t.zoom)&&f.unshift([...f.pop(),...f.shift()]);let m=[];for(let e of f)if(e.length>=2&&b(e)>=i){let n={...t,id:r(),pts:e,open:!0};m.push(n.id),o.push(n)}a.set(t.id,m)}return{strokes:o,pieces:a}}var Me=`mermaidify-drawing`,Ne=new Set([`ink`,`green`,`blue`,`red`,`amber`]),Pe=new Set([`pen`,`touch`,`mouse`]),Fe=new Set([`rect`,`subroutine`,`stadium`,`circle`,`double`,`diamond`,`hexagon`,`trapezoid`,`inv-trapezoid`,`lean-right`,`lean-left`,`triangle`,`flip-triangle`,`dot`,`bullseye`]),Ie=new Set([`plain`,`dotted`,`thick`]),Le=new Set([`state`,`choice`,`dot`]),Re=e=>Math.round(e*10)/10,ze=e=>typeof e==`number`&&Number.isInteger(e)&&e>=1&&e<=1e9?e:void 0,Be=e=>typeof e==`number`&&e>=.01&&e<=100&&Math.abs(e-1)>.001?Math.round(e*1e3)/1e3:void 0,Ve=1e5;function He(e,t,n,r,i={},a={},o=`flowchart`,s={}){return{format:Me,version:1,saved:new Date().toISOString(),strokes:e.map(e=>({color:e.color,by:e.by,pts:e.pts.map(([e,t])=>[Re(e),Re(t)]),...e.open?{open:!0}:{},...Be(e.zoom)?{zoom:Be(e.zoom)}:{},...ze(e.group)?{group:ze(e.group)}:{}})),labels:t,...Object.keys(i).length?{shapes:i}:{},...Object.keys(a).length?{lines:a}:{},...o===`state`?{diagram:o}:{},...Object.keys(s).length?{roles:s}:{},mermaid:n,...r?{edited:!0}:{}}}function Ue(e){let t=e=>({ok:!1,error:e});if(!e||typeof e!=`object`)return t(`This file is not a drawing.`);let n=e;if(n.format!==`mermaidify-drawing`)return t(`This file is not a mermaidify drawing.`);if(n.version!==1)return t(`This drawing was saved by a newer version of mermaidify.`);if(!Array.isArray(n.strokes)||n.strokes.length>1e3)return t(`This drawing's strokes cannot be read.`);let r=[],i=0;for(let e of n.strokes){let n=e;if(!n||!Array.isArray(n.pts)||n.pts.length>1e4)return t(`This drawing's strokes cannot be read.`);if(i+=n.pts.length,i>15e4)return t(`This drawing is too large to open here.`);let a=[];for(let e of n.pts){if(!Array.isArray(e)||e.length<2||!Number.isFinite(e[0])||!Number.isFinite(e[1])||Math.abs(e[0])>1e6||Math.abs(e[1])>1e6)return t(`This drawing's strokes cannot be read.`);a.push([e[0],e[1]])}a.length&&r.push({color:Ne.has(n.color)?n.color:`ink`,by:Pe.has(n.by)?n.by:`mouse`,pts:a,...n.open===!0?{open:!0}:{},...Be(n.zoom)?{zoom:Be(n.zoom)}:{},...ze(n.group)?{group:ze(n.group)}:{}})}let a={};if(n.labels&&typeof n.labels==`object`)for(let[e,t]of Object.entries(n.labels))/^[A-Za-z0-9_]{1,12}$/.test(e)&&typeof t==`string`&&(a[e]=t.slice(0,200));let o={};if(n.shapes&&typeof n.shapes==`object`)for(let[e,t]of Object.entries(n.shapes))/^[A-Za-z0-9_]{1,12}$/.test(e)&&Fe.has(t)&&(o[e]=t);let s={};if(n.lines&&typeof n.lines==`object`)for(let[e,t]of Object.entries(n.lines))/^[A-Za-z0-9_]{1,12}$/.test(e)&&Ie.has(t)&&(s[e]=t);let c={};if(n.roles&&typeof n.roles==`object`)for(let[e,t]of Object.entries(n.roles))/^[A-Za-z0-9_]{1,12}$/.test(e)&&Le.has(t)&&(c[e]=t);let l=n.diagram===`state`?`state`:`flowchart`,u=typeof n.mermaid==`string`?n.mermaid.slice(0,Ve):``;return{ok:!0,file:{format:Me,version:1,saved:typeof n.saved==`string`?n.saved:``,strokes:r,labels:a,shapes:o,lines:s,diagram:l,roles:c,mermaid:u,edited:n.edited===!0}}}function We(e,t){let n=E(e,t,7,-1),r=E(e,t,6,1),i=[e[t][0]-n[0],e[t][1]-n[1]],a=[r[0]-e[t][0],r[1]-e[t][1]],o=Math.hypot(i[0],i[1]),s=Math.hypot(a[0],a[1]);return o<3||s<3?Ge:(i[0]*a[0]+i[1]*a[1])/(o*s)}var Ge=2;function Ke(e,t,n=0,r){let i=0,a=e.length-1;for(;a>n&&i<t;)i+=y(e[a],e[a-1]),a--;let o=-1,s=-.3;for(let t=Math.max(1,a);t<e.length-1;t++){let n=r?r[t]:NaN;if(Number.isNaN(n)&&(n=We(e,t),r&&(r[t]=n)),n!==Ge){if(n<s)o=t,s=n;else if(o>=0)break}}return o}function qe(e){let t=b(e),n=new Float64Array(e.length).fill(NaN),r=Ke(e,Math.min(.7*t,Math.max(60,.4*t)),0,n);if(r>=0){let n=e.slice(r),i=b(n),a=Math.max(...n.map(t=>y(t,e[r])));i>=6&&i<=90&&i>=1.5*a&&a<=Math.max(28,.5*(t-i))||(r=-1)}let i=r;for(let r of[Ze(e,t,n),Je(e,t,n)])r>=0&&(i<0||r<i)&&(i=r);return i}function Je(e,t,n){if(t>Xe)return-1;let r=Ke(e,.85*t,0,n);if(r<0)return-1;let i=e.slice(r),a=e[r],o=b(i),s=t-o,c=i.reduce((e,t)=>y(t,a)>y(e,a)?t:e),l=y(c,a);if(s<10||l>1.25*s||o<2.2*l||o>3.6*l||y(e[0],a)<.9*s||!Ye(i,a,l))return-1;let u=(a[0]-e[0][0])/y(e[0],a),d=(a[1]-e[0][1])/y(e[0],a),f=e=>(e[0]-a[0])*u+(e[1]-a[1])*d<-.2*l;return f(c)&&f(i[i.length-1])?r:-1}function Ye(e,t,n){let r=0;for(;r<e.length&&y(e[r],t)<.6*n;)r++;for(;r<e.length&&y(e[r],t)>Math.max(10,.25*n);)r++;let i=r;for(;r<e.length&&y(e[r],t)<.5*n;)r++;if(i>=e.length||r>=e.length)return!1;let a=0;for(let t=0,n=0;t<4;t++){let t=Ke(e,b(e.slice(n)),n);if(t<0||t<=n)break;a++,n=t+1}return a<=3}var Xe=480;function Ze(e,t,n){let r=Ke(e,Math.min(.7*t,Math.max(60,.6*t)),0,n);if(r<0)return-1;let i=e.slice(r),a=e[r],o=b(i),s=Math.max(...i.map(e=>y(e,a)));return o<=90||o>3.5*s||s>.5*(t-o)?-1:Ye(i,a,s)?r:-1}var Qe=40,$e=120,et=20;function tt(e,t=Qe,n=$e){let r=1/0,i=1/0,a=-1/0,o=-1/0,s=-1;for(let n=0;n<e.length&&(r=Math.min(r,e[n][0]),i=Math.min(i,e[n][1]),a=Math.max(a,e[n][0]),o=Math.max(o,e[n][1]),!(Math.max(a-r,o-i)>t));n++)s=n;if(s<2||s===e.length-1)return null;let c=e.slice(0,s+1),l=b(c),u=b(e)-l;if(l<n||u<et)return null;let d=e[e.length-1];return{at:s,tip:c.reduce((e,t)=>y(t,d)>y(e,d)?t:e)}}function nt(e){let t=e.slice(),n=!1,r=!1,i=tt(t);i&&(t=[i.tip,...t.slice(i.at)],r=!0);let a=tt(t.slice().reverse());a&&(t=[...t.slice(0,t.length-a.at),a.tip],n=!0);let o=n?-1:qe(t);o>=0&&(t=t.slice(0,o+1),n=!0);let s=t.slice().reverse(),c=r?-1:qe(s);return c>=0&&(t=s.slice(0,c+1).reverse(),r=!0),{pts:t,headEnd:n,headStart:r}}function rt(e){let t=e.length,n=e[t-1],r=0,i=-1;for(let a=t-2;a>0;a--){if(r+=y(e[a],e[a+1]),r<24)continue;let t=y(e[a],n);if(t<=Math.max(8,.12*r))(i<0||t<y(e[i],n))&&(i=a);else if(i>=0)break}if(i<0)return null;let a=e.slice(i),o=x(a),s=Math.max(o.w,o.h),c=b(a),l=b(e.slice(0,i+1));if(s<8||l<Math.max(20,s/.55)||c<2.4*s||c>4.2*s)return null;let u=ie(a),d=re(u);if(!(d>0)||re(a)<.75*d||it(u)<.75*d)return null;let f=E(e,i,Math.min(40,.5*l),-1),p=y(f,e[i]);if(p<1)return null;let m=(e[i][0]-f[0])/p,h=(e[i][1]-f[1])/p,g=a[0],_=-1/0,v=0,S=0;for(let t of a){let n=(t[0]-e[i][0])*m+(t[1]-e[i][1])*h,r=(t[0]-e[i][0])*h-(t[1]-e[i][1])*m;n>_&&(_=n,g=t),v=Math.max(v,r),S=Math.max(S,-r)}return Math.min(v,S)<.25*s?null:Math.abs((g[0]-e[i][0])*h-(g[1]-e[i][1])*m)<=.6*s?{at:i,tip:g}:null}function it(e){let t=e.length>48?e.filter((t,n)=>n%Math.ceil(e.length/48)===0):e,n=0;for(let e=0;e<t.length;e++)for(let r=e+1;r<t.length;r++)for(let i=r+1;i<t.length;i++){let a=Math.abs((t[r][0]-t[e][0])*(t[i][1]-t[e][1])-(t[i][0]-t[e][0])*(t[r][1]-t[e][1]))/2;a>n&&(n=a)}return n}function at(e){let t=e=>{let t=b(e),n=e[0],r=e[e.length-1];return t>=30&&y(n,r)>=.85*t?{tail:n,tip:r}:null},n=rt(e),r=n&&t([...e.slice(0,n.at+1),n.tip]);if(r)return r;let i=nt(e);return i.headEnd&&!i.headStart?t(i.pts):null}var ot=(e=0,t=0)=>({dx:0,dy:0,angle:0,scale:1,cx:e,cy:t});function st(e,t){let n=(e[0]-t.cx)*t.scale,r=(e[1]-t.cy)*t.scale,i=Math.cos(t.angle),a=Math.sin(t.angle);return[t.cx+n*i-r*a+t.dx,t.cy+n*a+r*i+t.dy]}function ct(e){if(e.pts.length<8)return!1;let t=x(e.pts);return Math.min(t.w,t.h)>8&&y(e.pts[0],e.pts[e.pts.length-1])<Math.max(14,.25*Math.hypot(t.w,t.h))}function lt(e,t){let n=new Set(t);for(let t=!0;t;){t=!1;let r=new Set(e.filter(e=>n.has(e.id)&&e.group!==void 0).map(e=>e.group)),i=e.filter(e=>n.has(e.id)&&ct(e));for(let a of e){if(n.has(a.id))continue;let e=x(a.pts),o=i.some(t=>{let n=x(t.pts);return e.x0>=n.x0&&e.x1<=n.x1&&e.y0>=n.y0&&e.y1<=n.y1&&a.pts.every((e,n)=>n%4!=0||ne(e,t.pts))});(a.group!==void 0&&r.has(a.group)||o)&&(n.add(a.id),t=!0)}}return n}function ut(e,t){if(t.length<3)return new Set;let n=x(t),r=[],i=Math.max(2,Math.min(n.w,n.h)/4);for(let a of e){let e=x(a.pts);e.x1<n.x0||e.x0>n.x1||e.y1<n.y0||e.y0>n.y1||(a.pts.length>1?T(a.pts,i):a.pts).some(e=>ne(e,t))&&r.push(a.id)}return lt(e,r)}function dt(e,t,n){let r=null;for(let i of e){let e=i.pts;for(let a=0;a<e.length;a++){let o=e.length===1?y(t,e[0]):C(t,e[a],e[Math.min(a+1,e.length-1)]);o<=n&&(!r||o<r.d)&&(r={id:i.id,d:o})}}return r?.id??null}function ft(e,t){let n=null,r=e.filter(ct);for(let e of r){let r=x(e.pts);t[0]<r.x0||t[0]>r.x1||t[1]<r.y0||t[1]>r.y1||!ne(t,e.pts)||(!n||r.w*r.h<n.b.w*n.b.h)&&(n={s:e,b:r})}if(!n)return null;let{s:i,b:a}=n;return r.some(e=>{if(e===i)return!1;let t=x(e.pts);return t.x0>=a.x0&&t.x1<=a.x1&&t.y0>=a.y0&&t.y1<=a.y1})?null:i.id}var pt=(e,t)=>[e,[t[0],e[1]],t,[e[0],t[1]],e];function mt(e,t){let n=e.filter(e=>t.has(e.id)).flatMap(e=>e.pts);return n.length?x(n):null}function ht(e,t,n){return e.map(e=>t.has(e.id)?{...e,pts:e.pts.map(e=>st(e,n)),open:e.open}:e)}function gt(e,t,n,r,i,a=e){let o=new Map,s=new Map,c=[],l=Math.max(0,...a.map(e=>e.group??0));for(let a of e){if(!t.has(a.id))continue;let e=i(),u=a.group;u!==void 0&&(o.has(u)||o.set(u,++l),u=o.get(u)),c.push({...a,id:e,pts:a.pts.map(([e,t])=>[e+n,t+r]),...u===void 0?{}:{group:u}}),s.set(e,a.id)}return{copies:c,from:s}}var _t=e=>Math.round(e/(Math.PI/12))*(Math.PI/12),vt=.1,yt=4,X=e=>getComputedStyle(document.documentElement).getPropertyValue(e).trim();function bt(e,t){let n=e.getContext(`2d`),r=0,i=0,a=!1,o=[],s=null,c=!0,l=[],u=!0,d=`draw`,f=`ink`,p={scale:1,x:0,y:0},m=1,h=!1,g=-1e9,_=(e,t)=>[(e-p.x)/p.scale,(t-p.y)/p.scale],v=t=>{let n=e.getBoundingClientRect();return[t.clientX-n.left,t.clientY-n.top]};function x(){a||(a=!0,requestAnimationFrame(()=>{a=!1,re()}))}function S(){let t=e.getBoundingClientRect(),a=Math.min(window.devicePixelRatio||1,3),s=t.width!==r||t.height!==i;r=t.width,i=t.height,e.width=Math.max(1,Math.round(r*a)),e.height=Math.max(1,Math.round(i*a)),n.setTransform(a,0,0,a,0,0),s&&o.length&&!w()&&ne(),re()}function w(){let e=te();if(!e)return!0;let[t,n]=[e[0]*p.scale+p.x,e[1]*p.scale+p.y],[a,o]=[e[2]*p.scale+p.x,e[3]*p.scale+p.y];return t>=-2&&n>=-2&&a<=r+2&&o<=i+2}function te(){let e=1/0,t=1/0,n=-1/0,r=-1/0;for(let i of o)for(let[a,o]of i.pts)a<e&&(e=a),o<t&&(t=o),a>n&&(n=a),o>r&&(r=o);return e===1/0?null:[e,t,n,r]}function ne(){let e=te();if(!e||!r||!i){T({scale:1,x:0,y:0});return}let t=e[2]-e[0],n=e[3]-e[1],a=Math.max(vt,Math.min(1,(r-32)/Math.max(t,1),(i-32)/Math.max(n,1)));a===1&&e[0]>=14&&e[1]>=14&&e[2]<=r-16+2&&e[3]<=i-16+2?T({scale:1,x:0,y:0}):T({scale:a,x:(r-t*a)/2-e[0]*a,y:(i-n*a)/2-e[1]*a})}function T(e){p=e,t.view(p),x()}function E(e){n.beginPath(),n.moveTo(e[0][0],e[0][1]),e.length===1&&n.lineTo(e[0][0]+.01,e[0][1]);for(let t=1;t<e.length-1;t++)n.quadraticCurveTo(e[t][0],e[t][1],(e[t][0]+e[t+1][0])/2,(e[t][1]+e[t+1][1])/2);e.length>1&&n.lineTo(e[e.length-1][0],e[e.length-1][1])}function re(){n.save(),n.clearRect(0,0,r,i);let e=24;for(;e*p.scale<10;)e*=2;let t=e*p.scale;n.fillStyle=X(`--dots`);let a=(p.x%t+t)%t,l=(p.y%t+t)%t,f=Math.max(.6,Math.min(1,p.scale));for(let e=a;e<r;e+=t)for(let r=l;r<i;r+=t)n.fillRect(e-f,r-f,2*f,2*f);n.translate(p.x,p.y),n.scale(p.scale,p.scale),n.lineCap=`round`,n.lineJoin=`round`;let m=Math.max(3/Math.sqrt(p.scale),1.3/p.scale),h=s&&c?s.reading:null;if(h){n.save(),n.lineWidth=m+8/p.scale,n.globalAlpha=.42,n.strokeStyle=X(`--accent`);for(let e of h.edges)for(let t of e.strokes)o[t]&&(E(o[t].pts),n.stroke());n.globalAlpha=.5,n.strokeStyle=X(`--warning`);for(let e of h.unused)o[e]&&(E(o[e].pts),n.stroke());n.restore()}let g=e=>q&&U.has(e.id)?e.pts.map(e=>st(e,q.m)):e.pts;if(U.size&&d===`select`){n.save(),n.lineWidth=m+6/p.scale,n.globalAlpha=.28,n.strokeStyle=X(`--accent`);for(let e of o)U.has(e.id)&&(E(g(e)),n.stroke());n.restore()}n.lineWidth=m;for(let e of o)n.globalAlpha=j.has(e.id)?.2:1,n.strokeStyle=X(`--draw-`+e.color)||X(`--draw-ink`),E(g(e)),n.stroke();if(n.globalAlpha=1,G&&(W===`lasso`||G.length>1)){if(n.save(),n.lineWidth=1.5/p.scale,n.setLineDash([5/p.scale,4/p.scale]),n.strokeStyle=n.fillStyle=X(`--accent`),n.beginPath(),W===`box`){let[e,t]=[G[0],G[G.length-1]];n.rect(Math.min(e[0],t[0]),Math.min(e[1],t[1]),Math.abs(t[0]-e[0]),Math.abs(t[1]-e[1]))}else E(G),n.closePath();n.stroke(),n.globalAlpha=.06,n.fill(),n.restore()}N&&(n.save(),n.globalAlpha=.22,n.strokeStyle=X(`--error`),n.lineWidth=2*D/p.scale,E(N),n.stroke(),n.restore());for(let e of[...A?.done??[],...O?[O]:[]])n.strokeStyle=X(`--draw-`+e.color),E(e.pts),n.stroke();h&&s&&!q?se(h,s.labels):!h&&u&&ie(),n.restore(),be(),ce&&(d===`erase`||d===`cut`)&&(n.save(),n.strokeStyle=X(`--ink-3`),n.setLineDash([3,3]),n.beginPath(),n.arc(ce[0],ce[1],D,0,Math.PI*2),n.stroke(),n.restore())}function ie(){if(!l.length||14*p.scale<7)return;let e=new Map(o.map(e=>[e.id,e]));n.save(),n.font=`600 14px ${X(`--font`)}`,n.textAlign=`center`,n.textBaseline=`middle`;for(let t of l){let r=t.strokes.flatMap(t=>e.get(t)??[]);if(!r.length)continue;let i=q&&r.some(e=>U.has(e.id))?st(t.at,q.m):t.at,a=Math.max(40,t.w-12),o=t.text;for(;o.length>1&&n.measureText(o).width>a;)o=o.slice(0,-2)+`…`;if(t.line){let e=n.measureText(o).width+10;n.fillStyle=X(`--surface`),n.beginPath(),n.roundRect(i[0]-e/2,i[1]-10,e,20,6),n.fill()}n.fillStyle=X(`--draw-`+r[0].color)||X(`--draw-ink`),n.fillText(o,i[0],i[1]+.5)}n.restore()}function ae(e,t,r=1){let i=t.w*r,a=t.h*r,o=t.cx-i/2,s=t.cy-a/2,c=k[e];n.beginPath(),c===`ellipse`?n.ellipse(t.cx,t.cy,i/2,a/2,0,0,Math.PI*2):(oe[c].forEach(([e,t],r)=>r?n.lineTo(o+e*i,s+t*a):n.moveTo(o+e*i,s+t*a)),n.closePath()),n.stroke()}function se(e,t){let r=1/p.scale,i=X(`--accent`);n.lineWidth=1.5*r,n.setLineDash([5*r,5*r]),n.strokeStyle=i;for(let t of[...e.groups,...e.nodes])ae(t.kind,t.bb),t.kind===`double`&&ae(`circle`,t.bb,.64),t.kind===`subroutine`&&ae(`rect`,t.bb,.8);n.setLineDash([]),n.lineWidth=2*r;for(let t of e.edges){if(!t.assumed||t.pts.length<2)continue;let e=t.pts[t.pts.length-1],i=t.pts.length-2;for(;i>0&&y(t.pts[i],e)<10*r;)i--;let a=Math.atan2(e[1]-t.pts[i][1],e[0]-t.pts[i][0]),o=9*r;n.beginPath(),n.moveTo(e[0]-o*Math.cos(a-.5),e[1]-o*Math.sin(a-.5)),n.lineTo(e[0],e[1]),n.lineTo(e[0]-o*Math.cos(a+.5),e[1]-o*Math.sin(a+.5)),n.stroke()}n.textBaseline=`middle`;for(let a of e.edges){let e=t[a.id]?.trim();if(!e||a.pts.length<2)continue;n.font=`600 ${12*r}px ${X(`--font`)}`;let o=e;for(;o.length>1&&n.measureText(o).width>160*r;)o=o.slice(0,-2)+`…`;let[s,c]=ee(a.pts),l=n.measureText(o).width+12*r;n.fillStyle=X(`--surface`),n.strokeStyle=i,n.lineWidth=1.5*r,n.beginPath(),n.roundRect(s-l/2,c-10*r,l,20*r,6*r),n.fill(),n.stroke(),n.fillStyle=X(`--ink`),n.textAlign=`center`,n.fillText(o,s,c+.5*r),n.textAlign=`start`}for(let a of[...e.groups,...e.nodes]){if(a.role===`dot`)continue;n.font=`600 ${11*r}px ${X(`--mono`)}`;let o=n.measureText(a.id).width+10*r,s=a.bb.x0-4*r,c=a.bb.y0-9*r;n.fillStyle=i,n.beginPath(),n.roundRect(s,c,o,18*r,5*r),n.fill(),n.fillStyle=X(`--accent-ink`),n.fillText(a.id,s+5*r,c+9.5*r);let l=a.role===`choice`?void 0:t[a.id]?.trim();if(l){n.font=`600 ${13*r}px ${X(`--font`)}`,n.fillStyle=X(`--ink`),n.textAlign=`center`;let t=Math.max(40*r,a.bb.w-12*r),i=l;for(;i.length>1&&n.measureText(i).width>t;)i=i.slice(0,-2)+`…`;let o=e.groups.includes(a)?a.bb.y0+14*r:a.bb.cy;n.fillText(i,a.bb.cx,o),n.textAlign=`start`}}}let D=14,O=null,A=null,j=new Set,M=null,ce=null,N=null,P=``,le=[0,0],F=new Map,I=null,L=null,R=!1,de=e=>e.pointerType===`pen`&&!!(e.buttons&34),fe=e=>d===`erase`||d===`cut`||de(e);function pe(e){let t=_(e[0],e[1]),n=14/p.scale;for(let e of o){if(j.has(e.id))continue;let r=e.pts;for(let i=0;i<r.length;i++)if((r.length===1?y(t,r[0]):C(t,r[i],r[Math.min(i+1,r.length-1)]))<=n){j.add(e.id);break}}}function me(){let e=[...F.values()];if(e.length>=2){let[t,n]=e;I={d:Math.max(1,y(t,n)),c:[(t[0]+n[0])/2,(t[1]+n[1])/2],view:{...p}}}else I=e.length===1?{d:0,c:e[0],view:{...p}}:null}function he(){if(!I)return;let e=[...F.values()];if(I.d&&e.length>=2){let[t,n]=e,r=[(t[0]+n[0])/2,(t[1]+n[1])/2],i=Math.max(vt,Math.min(yt,I.view.scale*y(t,n)/I.d)),a=(I.c[0]-I.view.x)/I.view.scale,o=(I.c[1]-I.view.y)/I.view.scale;T({scale:i,x:r[0]-a*i,y:r[1]-o*i})}else!I.d&&e.length===1&&T({scale:I.view.scale,x:I.view.x+e[0][0]-I.c[0],y:I.view.y+e[0][1]-I.c[1]})}function B(){clearTimeout(ge),O=null,A=null}let V=!0,ge;function H(){clearTimeout(ge),V&&d===`draw`&&(ge=setTimeout(_e,500))}function _e(){let e=A,t=O;if(!e||!t||e.aim)return;let n=t.zoom??1,r=at(t.pts.slice(e.anchor).map(e=>[e[0]*n,e[1]*n]));if(r){let i=[r.tail[0]/n,r.tail[1]/n],a=[r.tip[0]/n,r.tip[1]/n];e.aim={before:t.pts.slice(0,e.anchor),tail:i,tip:a,from:t.pts[t.pts.length-1]},t.pts=[...e.aim.before,...z(i,a,p.scale)];try{navigator.vibrate?.(12)}catch{}x();return}let i=ue(t.pts,e.anchor,t.zoom);if(i){if(i.kind===`line`)t.pts=[...t.pts.slice(0,i.from),...i.pts],e.anchor=t.pts.length-1;else{let n=t.pts.slice(0,i.from+1),r=4/p.scale;b(n)*p.scale>=12&&!n.every(t=>[e.snapped,i.box].some(e=>e&&t[0]>=e.x0-r&&t[0]<=e.x1+r&&t[1]>=e.y0-r&&t[1]<=e.y1+r))&&e.done.push({id:m++,color:t.color,pts:n,by:t.by,zoom:t.zoom}),e.done.push({id:m++,color:t.color,pts:i.pts,by:t.by,zoom:t.zoom}),O={id:0,color:t.color,pts:[t.pts[t.pts.length-1]],by:t.by,zoom:t.zoom},e.anchor=0,e.snapped=i.box}try{navigator.vibrate?.(12)}catch{}x()}}let U=new Set,W=`box`,G=null,K=null,q=null,ve=/Mac|iPhone|iPad/.test(navigator.userAgent),J=e=>[e[0]*p.scale+p.x,e[1]*p.scale+p.y];function ye(){let e=mt(o,U);if(!e)return null;let[t,n]=J([e.x0,e.y0]),[r,i]=J([e.x1,e.y1]);return{x0:t-8,y0:n-8,x1:r+8,y1:i+8,turn:[(t+r)/2,n-8-26],grow:[r+8,i+8]}}function be(){let e=ye();if(!e||d!==`select`)return;let t=e=>q?J(st(_(e[0],e[1]),q.m)):e,r=[[e.x0,e.y0],[e.x1,e.y0],[e.x1,e.y1],[e.x0,e.y1]].map(t);n.save(),n.strokeStyle=X(`--accent`),n.fillStyle=X(`--surface`),n.lineWidth=1.25,n.setLineDash([4,4]),n.beginPath(),r.forEach((e,t)=>t?n.lineTo(e[0],e[1]):n.moveTo(e[0],e[1])),n.closePath(),n.stroke(),n.setLineDash([]);let i=t([(e.x0+e.x1)/2,e.y0]),a=t(e.turn),o=t(e.grow);n.beginPath(),n.moveTo(i[0],i[1]),n.lineTo(a[0],a[1]),n.stroke(),n.lineWidth=1.5,n.beginPath(),n.arc(a[0],a[1],7,0,2*Math.PI),n.fill(),n.stroke(),n.beginPath(),n.rect(o[0]-6,o[1]-6,12,12),n.fill(),n.stroke(),n.restore()}function xe(e,n){let r=e.shiftKey||(ve?e.metaKey:e.ctrlKey),i=K={id:e.pointerId,by:e.pointerType,at:n,last:n,moved:0,adding:r},a=ye(),s=mt(o,U),c=_(n[0],n[1]),l=e.pointerType===`touch`?22:14,u=e=>q={mode:`move`,box:e,from:c,m:ot((e.x0+e.x1)/2,(e.y0+e.y1)/2)},d=!!a&&n[0]>=a.x0&&n[0]<=a.x1&&n[1]>=a.y0&&n[1]<=a.y1;if(a&&s&&!r&&(y(n,a.turn)<=l?q={mode:`turn`,box:s,from:c,m:ot((s.x0+s.x1)/2,(s.y0+s.y1)/2)}:y(n,a.grow)<=l&&(q={mode:`grow`,box:s,from:c,m:ot(s.x0,s.y0)})),!q){let n=(e.pointerType===`touch`?14:8)/p.scale,a=dt(o,c,n)??(d||r?null:ft(o,c));if(a!==null){let e=lt(o,[a]),n=[...e].every(e=>U.has(e));i.took={ids:e,was:n},n||(U=r?new Set([...U,...e]):e,t.select([...U])),u(mt(o,U))}else d&&s&&!r&&u(s)}q||(G=[c]),x()}function Se(e){let t=K,n=_(e[0],e[1]);if(t.moved=Math.max(t.moved,y(e,t.at)),t.last=e,G&&W===`box`)G=[G[0],n];else if(G&&y(n,G[G.length-1])*p.scale>=2)G.push(n);else if(q){let e=q,t=e.box;if(e.mode===`move`)e.m={...e.m,dx:n[0]-e.from[0],dy:n[1]-e.from[1]};else if(e.mode===`turn`){let t=Math.atan2(n[1]-e.m.cy,n[0]-e.m.cx)-Math.atan2(e.from[1]-e.m.cy,e.from[0]-e.m.cx);e.m={...e.m,angle:_t(t)}}else{let r=y(e.from,[t.x0,t.y0]);r>0&&(e.m={...e.m,scale:Math.max(.2,Math.min(5,y(n,[t.x0,t.y0])/r))})}}x()}function Y(e){let n=K,r=G,i=q;K=null,G=null,q=null;let a=n.moved<4;if(e&&r){let e=a?new Set:ut(o,W===`box`?pt(r[0],r[r.length-1]):r),i=a&&n.adding?ft(o,r[0]):null;i!==null&&(e=lt(o,[i]),[...e].every(e=>U.has(e))&&(U=new Set([...U].filter(t=>!e.has(t))),e=new Set)),a&&!n.adding&&t.empty(),U=n.adding?new Set([...U,...e]):e,t.select([...U])}else if(e&&i&&!a&&(i.m.dx||i.m.dy||i.m.angle||i.m.scale!==1))l=l.map(e=>e.strokes.some(e=>U.has(e))?{...e,at:st(e.at,i.m)}:e),t.edit(ht(o,U,i.m));else if(e&&a&&n.took?.was){let e=n.took.ids;U=n.adding?new Set([...U].filter(t=>!e.has(t))):e,t.select([...U])}x()}e.addEventListener(`pointerdown`,n=>{let r=v(n);if(we=n.pointerType,n.pointerType===`pen`&&(g=n.timeStamp,h||(h=!0,t.penMode(!0)),F.size&&(F.clear(),I=null),A&&A.by===`touch`&&(B(),x()),K&&K.by===`touch`&&(K=G=q=null,x())),n.pointerType===`touch`){if(n.timeStamp-g<600)return;let t=()=>{F.set(n.pointerId,r);try{e.setPointerCapture(n.pointerId)}catch{}me(),n.preventDefault()};if(h||F.size||d===`hand`)return t();if(M!==null&&P===`touch`){let e=ce??le;return y(e,le)>14?void 0:(F.set(M,e),M=null,ce=null,j.clear(),N=null,x(),t())}if(A&&A.by===`touch`)return A.moved>14?void 0:(F.set(A.id,A.last),B(),x(),t());if(K&&K.by===`touch`)return K.moved>14?void 0:(F.set(K.id,K.last),K=G=q=null,x(),t())}if(n.pointerType===`mouse`&&n.button===1||n.button===0&&(d===`hand`||R)&&!A&&M===null&&!K){L={id:n.pointerId,at:r,view:{...p}},e.dataset.panning=``,e.setPointerCapture(n.pointerId),n.preventDefault();return}if(!(n.pointerType===`mouse`&&n.button!==0||A||M!==null||K)){Te=n.pointerType===`mouse`&&n.ctrlKey;try{e.setPointerCapture(n.pointerId)}catch{}if(n.preventDefault(),fe(n)){M=n.pointerId,P=n.pointerType,le=r,ce=r,d===`cut`&&!de(n)?N=[_(r[0],r[1])]:pe(r),x();return}if(d===`select`){xe(n,r);return}A={id:n.pointerId,by:n.pointerType,start:n.timeStamp,moved:0,at:r,last:r,still:r,anchor:0,snapped:null,done:[]},O={id:0,color:f,pts:[_(r[0],r[1])],by:n.pointerType,zoom:p.scale},t.begin(),H(),x()}}),e.addEventListener(`pointermove`,n=>{let r=v(n);if(n.pointerType===`pen`&&(g=n.timeStamp),n.pointerType===`pen`&&!h&&n.buttons===0&&(h=!0,t.penMode(!0)),F.has(n.pointerId)){F.set(n.pointerId,r),n.timeStamp-g>=600&&he();return}if(L&&L.id===n.pointerId){if(n.buttons===0){L=null,delete e.dataset.panning;return}T({scale:L.view.scale,x:L.view.x+r[0]-L.at[0],y:L.view.y+r[1]-L.at[1]});return}if(n.pointerType===`mouse`&&n.buttons===0&&(M===n.pointerId||A?.id===n.pointerId||K?.id===n.pointerId)&&Ce(n,!0),(d===`erase`||d===`cut`)&&n.pointerType===`mouse`&&(ce=r,x()),d===`select`&&n.pointerType===`mouse`&&!K){let t=_(r[0],r[1]),n=dt(o,t,8/p.scale)!==null;n!==`over`in e.dataset&&(n?e.dataset.over=``:delete e.dataset.over)}if(M===n.pointerId){let e=n.getCoalescedEvents?.()??[];for(let t of e.length?e:[n]){let e=v(t);N?y(_(e[0],e[1]),N[N.length-1])*p.scale>=1&&N.push(_(e[0],e[1])):pe(e)}ce=r,x();return}if(K&&K.id===n.pointerId){Se(r);return}if(!A||A.id!==n.pointerId||!O)return;if(A.aim){let e=A.aim,t=_(r[0],r[1]),n=[e.tip[0]+t[0]-e.from[0],e.tip[1]+t[1]-e.from[1]];y(e.tail,n)*p.scale>=12&&(O.pts=[...e.before,...z(e.tail,n,p.scale)]),A.moved=Math.max(A.moved,y(r,A.at)),x();return}let i=n.getCoalescedEvents?.()??[];for(let e of i.length?i:[n]){let t=v(e),n=_(t[0],t[1]),r=O.pts[O.pts.length-1];A.moved=Math.max(A.moved,y(t,A.at)),A.last=t,y(n,r)*p.scale>=1.5&&O.pts.push(n)}y(r,A.still)>(A.by===`touch`?6:4)&&(A.still=r,H()),x()});function Ce(n,r){if(F.has(n.pointerId)){F.delete(n.pointerId),me();return}if(L&&L.id===n.pointerId){r&&y(v(n),L.at)<4&&t.empty(),L=null,delete e.dataset.panning;return}if(M===n.pointerId){M=null,n.pointerType!==`mouse`&&(ce=null),r&&j.size?t.erase([...j]):r&&!N&&y(v(n),le)<4&&t.empty(),r&&N&&t.cut(N,14/p.scale),j.clear(),N=null,x();return}if(K&&K.id===n.pointerId){Y(r);return}if(!A||A.id!==n.pointerId)return;let i=O,a=A;if(B(),r&&i){let e=v(n);a.moved=Math.max(a.moved,y(e,a.at)),a.snapped?(b(i.pts)*p.scale>=10&&a.done.push({...i,id:m++}),t.stroke(...a.done)):a.moved<6&&n.timeStamp-a.start<500&&b(i.pts)*p.scale<8?t.tap(i.pts[0]):(i.id=m++,t.stroke(i))}x()}e.addEventListener(`pointerup`,e=>Ce(e,!0));let we=`mouse`,Te=!1;return e.addEventListener(`contextmenu`,e=>{if(we===`mouse`&&Te&&(A||M!==null||K)){B(),M=null,j.clear(),N=null,K=G=q=null,x();return}(we!==`mouse`||A||M!==null||K)&&e.preventDefault()}),e.addEventListener(`pointercancel`,e=>Ce(e,!1)),e.addEventListener(`lostpointercapture`,e=>{K?.id===e.pointerId&&(K=G=q=null,x())}),e.addEventListener(`pointerleave`,e=>{e.pointerType===`mouse`&&M===null&&(ce=null,x())}),e.addEventListener(`wheel`,e=>{e.preventDefault();let t=e.deltaMode===1?16:e.deltaMode===2?i:1,n=e.deltaX*t,r=e.deltaY*t;if(!e.ctrlKey&&Math.abs(n)>Math.abs(r)){T({...p,x:p.x-n});return}let[a,o]=v(e),s=Math.max(vt,Math.min(yt,p.scale*Math.exp(-r*(e.ctrlKey?.01:.002)))),c=(a-p.x)/p.scale,l=(o-p.y)/p.scale;T({scale:s,x:a-c*s,y:o-l*s})},{passive:!1}),new ResizeObserver(()=>S()).observe(e),{setStrokes(e){o=e;let t=new Set(e.map(e=>e.id));U=new Set([...U].filter(e=>t.has(e)));for(let t of e)t.id>=m&&(m=t.id+1);x()},setOverlay(t){s=t,t?e.dataset.read=``:delete e.dataset.read,x()},setShowOverlay(e){c=e,x()},get overlaid(){return!!s&&c},setNames(e){l=e,x()},setShowNames(e){u=e,x()},setTool(n){d=n,n!==`erase`&&n!==`cut`&&(ce=null),delete e.dataset.over,n!==`select`&&U.size&&(U=new Set,t.select([])),e.dataset.tool=n,x()},setColor(e){f=e},setChooseBy(e){W=e},setSpace(t){R=t,t?e.dataset.space=``:delete e.dataset.space},setPenMode(e){h=e},setSnap(e){V=e,e||clearTimeout(ge)},fitContent:ne,resetView:()=>T({scale:1,x:0,y:0}),get pressing(){return!!A||M!==null||F.size>0||!!L||!!K},get chosen(){return[...U]},choose(e){U=new Set(e),t.select([...U]),x()},chosenBox:ye,get view(){return p},get size(){return{w:r/p.scale,h:i/p.scale}},toScreen:e=>[e[0]*p.scale+p.x,e[1]*p.scale+p.y],nextId:()=>m++,repaint:x}}var xt=new Set([`rect`,`stadium`,`circle`,`diamond`,`hexagon`,`trapezoid`,`inv-trapezoid`,`lean-right`,`lean-left`,`triangle`,`flip-triangle`]),St=(e,t)=>e.map(([e,n])=>[e*t,n*t]);function Ct(e,t,n,r){let i=new Map,a=(e,t)=>i.set(e,[...i.get(e)??[],t]),o=n=>n.length>0&&n.every(n=>e[n]&&t.has(e[n].id)),s=0,c=0,l=new Map;for(let t of[...n.nodes,...n.groups])for(let n of t.strokes)e[n]&&l.set(e[n],t);let u=e.filter(e=>t.has(e.id)),d=u.length>1?Et(u):null,f=(e,t)=>{let n=l.get(e);return!n||(n.kind===`triangle`||n.kind===`flip-triangle`)&&n.strokes.length===1&&Math.max(n.bb.w,n.bb.h)<=.55*t},p=d&&!l.has(d.shaft)&&u.every(e=>e===d.shaft||f(e,y(d.tail,d.tip)))?d:null;if(p){a(p.shaft.id,z(p.tail,p.tip,p.shaft.zoom??1));for(let e of u)e!==p.shaft&&i.set(e.id,[]);c++}let m=e=>n.edges.filter(t=>t.strokes.includes(e));for(let t of p?[]:n.nodes){if(!o(t.strokes)||t.strokes.length!==1||!xt.has(t.kind)||t.role===`dot`)continue;let n=e[t.strokes[0]],r=m(t.strokes[0]).length>0;if(r&&!m(t.strokes[0]).every(e=>o(e.strokes)))continue;let i=r?null:ue(n.pts,0,n.zoom);a(n.id,i&&i.kind!==`line`&&i.from<=2?i.pts:R(t.kind,t.bb)),s++}for(let t of p?[]:n.edges){if(!o(t.strokes)||t.pts.length<2||t.style!==`plain`)continue;let[n,...r]=t.strokes.map(t=>e[t]),s=t.pts[0],l=t.assumed?t.pts[t.pts.length-1]:wt(t.pts,t.strokes.map(t=>e[t].pts)),u=y(s,l)>=.9*b(t.pts),d=n.zoom??1;if(!u&&t.assumed){i.has(n.id)&&a(n.id,t.pts.slice());continue}a(n.id,u?t.assumed?[s,l]:z(s,l,d,t.both):Tt([...t.pts.slice(0,-1),l],d,t.both));for(let e of r)i.has(e.id)||i.set(e.id,[]);c++}let h=new Set([...n.nodes,...n.groups,...n.edges].flatMap(t=>t.strokes.map(t=>e[t]))),g=e.filter(e=>t.has(e.id)&&!i.has(e.id)&&!h.has(e)),_=g.length>1?Et(g):null;if(_&&!l.has(_.shaft)&&g.every(e=>e===_.shaft||f(e,y(_.tail,_.tip)))){a(_.shaft.id,z(_.tail,_.tip,_.shaft.zoom??1));for(let e of g)e!==_.shaft&&i.set(e.id,[]);c++}else for(let e of g){let t=e.zoom??1,n=at(St(e.pts,t));if(n){a(e.id,z(St([n.tail],1/t)[0],St([n.tip],1/t)[0],t)),c++;continue}let r=ue(e.pts,0,t);r&&(r.kind!==`line`&&r.from>2&&a(e.id,e.pts.slice(0,r.from+1)),a(e.id,r.pts),r.kind===`line`?c++:s++)}let v=[],x=new Map;for(let t of e){let e=i.get(t.id);if(!e){v.push(t);continue}e.forEach((e,n)=>{let i=n?r():t.id;n&&x.set(i,t.id),v.push({...t,id:i,pts:e,open:void 0})})}return{strokes:v,from:x,shapes:s,arrows:c}}function wt(e,t){let n=e[e.length-1],r=e.length-2;for(;r>0&&y(e[r],n)<12;)r--;let i=y(e[r],n);if(i<1)return n;let a=(n[0]-e[r][0])/i,o=(n[1]-e[r][1])/i,s=n,c=0;for(let e of t)for(let t of e){let e=(t[0]-n[0])*a+(t[1]-n[1])*o,r=Math.abs((t[0]-n[0])*o-(t[1]-n[1])*a);e>c&&e<=40&&r<=Math.max(6,.5*e)&&(c=e,s=t)}return s}function Tt(e,t,n){let r=e=>{let n=e[e.length-1],r=e.length-2;for(;r>0&&y(e[r],n)<14/t;)r--;let i=z(e[r],n,t);return i.slice(i.findIndex((e,t)=>t>0&&y(e,n)<1e-6)+1)},i=[...e,...r(e)];return n?[...r([...e].reverse()).reverse(),...i]:i}function Et(e){let{s:t,t:n}=e.map(e=>({s:e,t:nt(e.pts).pts})).sort((e,t)=>y(t.t[0],t.t[t.t.length-1])-y(e.t[0],e.t[e.t.length-1]))[0],r=b(n);if(r<20||y(n[0],n[n.length-1])<.85*r)return null;let i=e.filter(e=>e!==t),a=Math.max(40,.4*r);for(let[e,o]of[[n[0],n[n.length-1]],[n[n.length-1],n[0]]]){if(!i.every(e=>e.pts.every(e=>y(e,o)<=a)))continue;let n=x(i.flatMap(e=>e.pts));if(Math.max(n.w,n.h)>r)return null;let s=(o[0]-e[0])/y(e,o),c=(o[1]-e[1])/y(e,o),l=o,u=0;for(let e of i)for(let t of e.pts){let e=(t[0]-o[0])*s+(t[1]-o[1])*c;e>u&&(u=e,l=t)}return{shaft:t,tail:e,tip:l}}return null}function Dt(e){let t=7,n=()=>(t=t*1664525+1013904223>>>0)/4294967296,r=Math.round(e/2),i=[],a=(e,t,r=1.6)=>{let a=n()*6,o=n()*6;i.push({color:t,pts:e.map(([e,t],i)=>[e+Math.sin(i*.13+a)*r+(n()-.5)*.8,t+Math.cos(i*.11+o)*r+(n()-.5)*.8])})},o=(e,t,r,i)=>{let a=n()*6.28,o=[];for(let n=0;n<=68;n++){let s=a+n/64*Math.PI*2;o.push([e+r*Math.cos(s),t+i*Math.sin(s)])}return o},s=(e,t,n,r)=>T([[e,t],[e+n,t],[e+n,t+r],[e,t+r],[e,t+3]],4),c=(e,t,n,r)=>T([[e,t-r/2],[e+n/2,t],[e,t+r/2],[e-n/2,t],[e+2,t-r/2+2]],4),l=e=>{let[t,n]=e[e.length-1],[r,i]=e[e.length-2],a=Math.atan2(n-i,t-r),o=e=>[t-11*Math.cos(a+e),n-11*Math.sin(a+e)];return T(e,4).concat(T([[t,n],o(.5),[t,n],o(-.5)],2))};return a(o(r,46,58,22),`ink`),a(s(r-65,104,130,50),`ink`),a(c(r,234,136,86),`amber`),a(o(r,352,25,25),`red`,1),a(o(r,352,16,16),`red`,.6),a(l([[r,72],[r,101]]),`ink`,.8),a(l([[r,158],[r,188]]),`ink`,.8),a(l([[r,280],[r,324]]),`ink`,.8),a(l([[r+70,234],[r+112,234],[r+112,129],[r+69,129]]),`green`,1),i}var Z=e=>e.bb.w*e.bb.h,Ot=(e,t)=>e!==t&&Z(e)>Z(t)&&t.bb.x0>=e.bb.x0-6&&t.bb.x1<=e.bb.x1+6&&t.bb.y0>=e.bb.y0-6&&t.bb.y1<=e.bb.y1+6,kt=(e,t,n)=>e[0]>=t.x0-n&&e[0]<=t.x1+n&&e[1]>=t.y0-n&&e[1]<=t.y1+n,Q=(e,t)=>ne(e,t.poly)?0:w(e,t.poly),At=(e,t,n)=>kt(e,t.bb,n)&&Q(e,t)<n,jt=e=>Math.max(18,Math.min(44,.3*Math.max(e.bb.w,e.bb.h))),Mt=(e,t)=>{let n=Math.max(...e.map(e=>Q(e,t))),r=Math.max(Q(e[0],t),Q(e[e.length-1],t));return n>22&&n>r+15},Nt=(e,t,n,r)=>({kind:t.kind,unsure:t.unsure,bb:t.bb,poly:t.poly,pts:e,color:n,diag:Math.hypot(t.bb.w,t.bb.h),strokes:r}),Pt=()=>typeof performance<`u`?performance.now():Date.now();function Ft(e){let t=e.filter(e=>e&&Array.isArray(e.pts)).map(e=>typeof e.zoom==`number`&&e.zoom>=.01&&e.zoom<=100?e.zoom:1).sort((e,t)=>e-t);return t.length?t[t.length>>1]:1}function It(e,t={}){let n=Ft(e);if(n===1)return Lt(e,t);let r=(e,t)=>e.map(e=>Array.isArray(e)?[e[0]*t,e[1]*t]:[NaN,NaN]),i=Lt(e.map(e=>e&&Array.isArray(e.pts)?{...e,pts:r(e.pts,n)}:e),t),a=e=>({x0:e.x0/n,y0:e.y0/n,x1:e.x1/n,y1:e.y1/n,w:e.w/n,h:e.h/n,cx:e.cx/n,cy:e.cy/n}),o=e=>({...e,bb:a(e.bb),poly:r(e.poly,1/n)});return{...i,nodes:i.nodes.map(o),groups:i.groups.map(o),edges:i.edges.map(e=>({...e,pts:r(e.pts,1/n)}))}}function Lt(e,t){let n=Pt(),r=t.diagram===`state`?`state`:`flowchart`,i=[];e.forEach((e,t)=>{if(!e||!Array.isArray(e.pts)||e.pts.length<2)return;let n=b(e.pts);if(!(n>=8))return;let r=x(e.pts);i.push({index:t,color:e.color??`ink`,pts:e.pts,len:n,bb:r,diag:Math.hypot(r.w,r.h)})});let a=[],o=[];for(let e of i){let t=e.pts,n=[!1,!1],r=[];for(let i=0;i<2;i++){let i=mn(t);if(!i||n[i.end])break;let o=Nt(i.loop,i.fit,e.color,[e.index]);o.line={it:e,end:i.end},a.push(o),r.push(o),n=i.end?[n[0],!0]:[!0,n[1]],t=i.line}if(r.length){let i=x(t),a=b(t),s={index:e.index,color:e.color,pts:t,len:a,bb:i,diag:Math.hypot(i.w,i.h),joints:n};for(let e of r)e.line.it=s;o.push(s);continue}let i=un(e.pts);i?a.push(Nt(e.pts,i,e.color,[e.index])):o.push(e)}let s=[],c=new Set,l=()=>{for(let e of a.slice()){let t=Math.max(e.bb.w,e.bb.h),n=[e.bb.cx,e.bb.cy];if(t>(e.line?cn:sn))continue;let r=a.find(r=>r!==e&&Z(r)>=(e.line?4:6)*Z(e)&&w(n,r.poly)<.5*t+10&&e.pts.some(t=>Q(t,r)<=(e.line?jt(r):10))&&!a.some(t=>t!==r&&t!==e&&Ot(r,t)));if(!r)continue;let i=t=>kt(t,e.bb,10)&&Q(t,e)<=10,l=t=>ne(t,e.poly)||Q(t,r)>Q(n,r),u,d=0,f=1/0;if(e.line)[u,d]=[e.line.it,e.line.end];else for(let n of o){if(c.has(n)||n.len<=t)continue;let r=i(n.pts[0]),a=i(n.pts[n.pts.length-1]),o=r?n.pts[0]:n.pts[n.pts.length-1];r!==a&&l(o)&&Q(o,e)<f&&([u,d,f]=[n,+!r,Q(o,e)])}if(!u)continue;let p=e.pts.reduce((e,t)=>Q(t,r)<Q(e,r)?t:e);u.pts=d?[...u.pts,p]:[p,...u.pts],u.len=b(u.pts),a=a.filter(t=>t!==e),s.push({pts:e.pts,color:e.color,len:b(e.pts),strokes:e.strokes})}};l();let u=[];for(let e of a.slice()){let t=e.pts[0],n=e.pts[e.pts.length-1],r=a.find(r=>r!==e&&At(t,r,8)&&At(n,r,8)&&!Ot(e,r)&&!Ot(r,e));r&&(a=a.filter(t=>t!==e),u.push({pts:e.pts,color:e.color,len:b(e.pts),strokes:e.strokes,host:r}))}let d=e=>a.some(t=>At(e,t,jt(t))),f=o.filter(e=>e.len>=20&&!a.some(t=>At(e.pts[0],t,10)||At(e.pts[e.pts.length-1],t,10))&&!(d(e.pts[0])&&d(e.pts[e.pts.length-1])));for(let e of f){if(c.has(e))continue;let t=[e],n=e.pts.slice();for(let r=0;r<3;r++){let r=n[0],i=n[n.length-1],o=x(n),s=Math.max(14,.18*Math.hypot(o.w,o.h)),l=null;for(let e of f){if(c.has(e)||t.includes(e))continue;let n=e.pts[0],a=e.pts[e.pts.length-1],o=[[y(i,n),`tail`,!1],[y(i,a),`tail`,!0],[y(r,a),`head`,!1],[y(r,n),`head`,!0]];for(let[t,n,r]of o)t<s&&(!l||t<l.d)&&(l={b:e,d:t,end:n,rev:r})}if(!l)break;let u=l.rev?l.b.pts.slice().reverse():l.b.pts;n=l.end===`tail`?n.concat(u):u.concat(n),t.push(l.b);let d=x(n);if(y(n[0],n[n.length-1])<Math.max(14,.18*Math.hypot(d.w,d.h))&&Math.min(d.w,d.h)>=14){let r=ce(n);r&&(a.push(Nt(n,r,e.color,t.map(e=>e.index))),t.forEach(e=>c.add(e)));break}}}l(),a.sort((e,t)=>Z(t)-Z(e));let p=new Set,m=new Set(a.filter(e=>{let t=a.filter(t=>Ot(e,t));return t.filter(e=>!t.some(t=>Ot(t,e))).length>=2}));for(let e of a)for(let t of a){if(p.has(e)||p.has(t)||!Ot(e,t)||m.has(e)||r===`state`&&Math.max(e.bb.w,e.bb.h)>Kt)continue;let n=Z(e)/Z(t),i=y([e.bb.cx,e.bb.cy],[t.bb.cx,t.bb.cy])<.2*e.diag,a=Math.max(e.bb.w,e.bb.h)/Math.max(t.bb.w,t.bb.h);i&&(n<3.2||a<1.9)&&(A.has(e.kind)||A.has(t.kind))?(e.kind=Math.max(t.bb.w,t.bb.h)<=Bt&&Qt(t.pts)?`bullseye`:`double`,e.strokes.push(...t.strokes),p.add(t)):i&&n<2&&e.kind===`rect`&&t.kind===`rect`&&r===`flowchart`&&(e.kind=`subroutine`,e.strokes.push(...t.strokes),p.add(t))}let h=a.filter(e=>!p.has(e));for(let e of h)e.isGroup=h.some(t=>Ot(e,t));let g=h.filter(e=>!e.isGroup),_=h.filter(e=>e.isGroup);for(let e of h)e.parent=_.filter(t=>Ot(t,e)).sort((e,t)=>Z(e)-Z(t))[0];let v=e=>_.filter(t=>Ot(t,e)).sort((e,t)=>Z(e)-Z(t))[0],S=r===`state`,C=new Set,te=(e,t,n)=>{let r=Nt(e,$t(e),t,n);return r.kind=`dot`,r.parent=v(r),g.push(r),C.add(r),r},T=(e,t)=>zt.has(e.kind)&&Math.max(e.bb.w,e.bb.h)<=t&&e.bb.w<1.6*e.bb.h&&e.bb.h<1.6*e.bb.w,re=e=>h.some(t=>t.isGroup?kt(e,t.bb,Jt)&&w(e,t.poly)<Jt:At(e,t,qt)),ie=(e,t)=>g.some(n=>!C.has(n)&&e.some(e=>At(e,n,jt(n)))&&!t.some(e=>At(e,n,jt(n))));for(let e of g)C.has(e)||(Math.max(e.bb.w,e.bb.h)<=Bt&&Qt(e.pts)?(e.kind=`dot`,C.add(e)):S&&(e.kind===`double`||T(e,Gt))&&C.add(e));for(let e of o){let t=Math.max(e.bb.w,e.bb.h),n=[e.bb.cx,e.bb.cy];if(c.has(e)||t>Bt||e.len<Vt*t||!(Qt(e.pts)||S&&le(e.pts,e.len)<.3*t))continue;let r=g.find(r=>ne(n,r.poly)&&T(r,Kt)&&(S||y(n,[r.bb.cx,r.bb.cy])<.2*Math.max(r.bb.w,r.bb.h)&&e.len>=Ht*t));if(r){r.kind=`bullseye`,C.add(r),r.strokes.push(e.index),c.add(e);continue}if(!S)continue;let i=e=>h.some(t=>t.isGroup?kt(e,t.bb,jt(t))&&w(e,t.poly)<=jt(t):At(e,t,jt(t))),a=e=>{let t=nt(e.pts).pts;return y(t[0],t[t.length-1])>=.7*b(t)},s=o.filter(t=>t!==e&&!c.has(t)&&t.len>=Zt).flatMap(e=>[[e.pts[0],e.pts[e.pts.length-1],e],[e.pts[e.pts.length-1],e.pts[0],e]]).filter(([e,r,o])=>y(e,n)<=Xt+t/2&&i(r)&&a(o)).map(([,e])=>e);s.length&&!e.pts.some(re)&&!ie(e.pts,s)&&(te(e.pts,e.color,[e.index]),c.add(e))}let ae=e=>C.has(e)?Math.max(Xt,jt(e)):jt(e),oe=e=>{let t=null;for(let n of g){if(!kt(e,n.bb,ae(n)))continue;let r=Q(e,n);r<=ae(n)&&(!t||r<t.d||r===t.d&&Z(n)<Z(t.s))&&(t={s:n,d:r})}if(t)return _.find(n=>Ot(n,t.s)&&!ne(e,n.poly)&&w(e,n.poly)<t.d)??t.s;for(let n of _){if(!kt(e,n.bb,jt(n)))continue;let r=w(e,n.poly);r<=jt(n)&&(!t||r<t.d)&&(t={s:n,d:r})}return t?.s},se=(e,t)=>{if(b(e)<nn)return;let n=t?e.length-1:0,r=e[n],i=E(e,n,20,t?-1:1),a=r[0]-i[0],o=r[1]-i[1],s=Math.hypot(a,o);if(s<10)return;let c=Math.min(tn,en*b(e));for(let e=3;e<=c;e+=3){let t=[r[0]+a/s*e,r[1]+o/s*e],n=g.find(e=>At(t,e,2));if(n)return n}},D=e=>({pts:e.pts,color:e.color,len:e.len,strokes:[e.index],joints:e.joints}),O=o.filter(e=>!c.has(e)),k=_n(O,(e,t)=>g.some(n=>At(e,n,t))),j=new Map(k.map(e=>[e.reduce((e,t)=>t.it.index<e.it.index?t:e).it,e])),M=new Set(k.flat().map(e=>e.it)),N=[];for(let e of O){let t=j.get(e);if(t){let e=t.flatMap(e=>e.flip?e.it.pts.slice().reverse():e.it.pts);N.push({pts:e,color:t[0].it.color,len:b(e),strokes:t.map(e=>e.it.index),dashes:t.map(e=>e.it)})}else M.has(e)||N.push(D(e))}N.push(...u);for(let e of N)if(!(!S||e.host||e.dashes))for(let t of[0,1]){let n=t?e.pts.slice().reverse():e.pts,r=tt(n,$,Yt);if(!r)continue;let i=n.slice(0,r.at+1),a=x(i),o=[a.cx,a.cy];if(i.some(re)||ie(i,[n[n.length-1]]))continue;te(i,e.color,e.strokes.slice(0,1));let s=[o,...n.slice(r.at)];e.pts=t?s.reverse():s,e.len=b(e.pts),e.joints=t?[e.joints?.[0]??!1,!0]:[!0,e.joints?.[1]??!1]}let P=[],F=[],I=[],L=new Set,R=[],ue=new Map,de=e=>{let t=e.pts,n={...ue.get(t)??ue.set(t,nt(t)).get(t)};return e.joints?.[0]&&n.headStart&&([n.pts,n.headStart]=[[t[0],...n.pts],!1]),e.joints?.[1]&&n.headEnd&&([n.pts,n.headEnd]=[[...n.pts,t[t.length-1]],!1]),n};for(let e of N){let t=de(e),n=e.host||oe(t.pts[0]),r=e.host||oe(t.pts[t.pts.length-1]),i={from:n,to:r,pts:t.pts,headEnd:t.headEnd,headStart:t.headStart,color:e.color,line:e};n&&r&&n!==r||n&&r&&(e.host||e.len>50&&Mt(t.pts,n)&&!(an(t.pts)>=0&&Q(t.pts[0],n)>10&&Q(t.pts[t.pts.length-1],n)>10))?P.push(i):e.dashes?N.push(...e.dashes.map(D)):e.len<70?F.push(e):Math.max(x(e.pts).w,x(e.pts).h)<=sn?(F.push(e),L.add(e)):R.push(e)}for(let e of s)F.push(e),L.add(e);let fe=e=>y(e.pts[0],e.pts[e.pts.length-1])<.8*e.len;for(let e of P.slice()){let t=e.line,n=fe(t),r=x(t.pts),i=e.from===e.to&&(Math.max(r.w,r.h)<.5*Math.max(e.from.bb.w,e.from.bb.h)||an(t.pts)>=0);if(t.host||t.dashes||e.from===e.to&&!i||t.len>=(i?160:n?70:45))continue;let a=i?22:n?10:8,o=i?8:a;P.some(i=>i!==e&&(kt(i.pts[0],r,o)||kt(i.pts[i.pts.length-1],r,o))&&(n===fe(i.line)?i.line.len>t.len:n)&&t.pts.some(e=>y(e,i.pts[0])<a||y(e,i.pts[i.pts.length-1])<a)&&!(y(e.pts[0],e.pts[e.pts.length-1])>=.8*b(e.pts)&&bn(e.pts,i.pts)))&&(P.splice(P.indexOf(e),1),F.push(t))}let pe=(e,t)=>{let n=null,r=x(e.pts);for(let i of t)for(let[t,a]of[[`start`,i.pts[0]],[`end`,i.pts[i.pts.length-1]]]){if(!kt(a,r,L.has(e)?8:22))continue;let o=1/0;for(let t of e.pts)o=Math.min(o,y(a,t));o<22&&(!n||o<n.d)&&(n={e:i,end:t,d:o})}return n?(n.end===`end`?n.e.headEnd=!0:n.e.headStart=!0,n.e.line.strokes.push(...e.strokes.filter(e=>!n.e.line.strokes.includes(e))),!0):!1};for(let e of F)pe(e,P)||R.push(e);let z=new Set,me=new Map,he=new Map,B=e=>me.get(e)??me.set(e,an(e.pts)).get(e),V=e=>he.get(e)??he.set(e,x(e.pts)).get(e),ge=(e,t,n,r)=>{let i=r?t.length-1:0,a=t[i];if(!kt(a,V(e),Math.max(40,.5*n)+12))return null;let o=B(e);if(o>=0&&on(e.pts,o,t,n,r))return e.pts[o];if(!F.includes(e)||!(L.has(e)||y(e.pts[0],e.pts[e.pts.length-1])<.8*e.len))return null;let s=E(t,i,20,r?-1:1),c=Math.hypot(a[0]-s[0],a[1]-s[1]);if(c<10||!kt(a,V(e),12)||!e.pts.some(e=>y(e,a)<12))return null;let l=(a[0]-s[0])/c,u=(a[1]-s[1])/c,d=e.pts.reduce((e,t)=>(t[0]-a[0])*l+(t[1]-a[1])*u>(e[0]-a[0])*l+(e[1]-a[1])*u?t:e),f=(d[0]-a[0])*l+(d[1]-a[1])*u,p=Math.abs((d[1]-a[1])*l-(d[0]-a[0])*u);return f>=8&&p<=.5*f+6?d:null},H=P.filter(e=>e.from===e.to&&!e.line.host&&!e.line.dashes&&B(e.line)>=0);for(let e of R){if(z.has(e)||e.dashes||e.host||e.len<rn||e.len<nn&&!g.some(t=>kt(e.pts[0],t.bb,jt(t)+40)||kt(e.pts[e.pts.length-1],t.bb,jt(t)+40)))continue;let t=de(e),n=[oe(t.pts[0]),oe(t.pts[t.pts.length-1])],r=b(t.pts);if(e.len<nn&&!n[0]==!n[1])continue;let i=[];for(let a of[0,1]){if(n[a])continue;let o=null,s=n=>n!==e&&!z.has(n)&&!i.includes(n)&&!!(o=ge(n,t.pts,r,a)),c=R.find(s)??H.find(e=>P.includes(e)&&s(e.line))?.line;c&&o&&(t.pts=a?[...t.pts,o]:[o,...t.pts],a?t.headEnd=!0:t.headStart=!0,i.push(c),n[a]=oe(o))}let a=n[0]||se(t.pts,0),o=n[1]||se(t.pts,1);if(a&&o&&a!==o){for(let t of i){z.add(t),e.strokes.push(...t.strokes);let n=P.findIndex(e=>e.line===t);n>=0&&P.splice(n,1)}P.push({from:a,to:o,pts:t.pts,headEnd:t.headEnd,headStart:t.headStart,color:e.color,line:e}),z.add(e)}}let _e=e=>{let t=B(e);if(t<0)return!1;let n=e.pts[t],r=V(e),i=(e.pts[0][0]+e.pts[e.pts.length-1][0])/2,a=(e.pts[0][1]+e.pts[e.pts.length-1][1])/2;for(let t of P)for(let o of[0,1]){let s=o?t.pts.length-1:0,c=t.pts[s];if(!kt(c,r,22)||y(n,c)>=22)continue;let l=E(t.pts,s,20,o?-1:1);if(!(Math.hypot(c[0]-l[0],c[1]-l[1])<10||(i-n[0])*(c[0]-l[0])+(a-n[1])*(c[1]-l[1])>=0))return o?t.headEnd=!0:t.headStart=!0,t.line.strokes.push(...e.strokes.filter(e=>!t.line.strokes.includes(e))),!0}return!1};for(let e of R)!z.has(e)&&(F.includes(e)?pe(e,P):_e(e))&&z.add(e);for(let e of R)z.has(e)||I.push(...e.strokes);let U=new Map(P.map(e=>[e,{at:ee(e.pts),len:b(e.pts)}]));for(let e=0;e<P.length;e++)for(let t=e+1;t<P.length;t++){let n=P[e],r=P[t],i=U.get(n),a=U.get(r);if(n.line.dashes||r.line.dashes||y(i.at,a.at)>2*yn+Math.abs(i.len-a.len)/2)continue;let o;if(n.from===r.from&&n.to===r.to)o=n.from!==n.to||y(n.pts[0],r.pts[0])<=y(n.pts[0],r.pts[r.pts.length-1]);else if(n.from===r.to&&n.to===r.from)o=!1;else continue;let s=o?r.headEnd:r.headStart,c=o?r.headStart:r.headEnd;n.headEnd&&!n.headStart&&c&&!s||n.headStart&&!n.headEnd&&s&&!c||!bn(n.pts,r.pts)||(n.headEnd||=s,n.headStart||=c,n.thick=!0,n.line.strokes.push(...r.line.strokes),P.splice(t--,1))}for(let e of P)e.headStart&&!e.headEnd&&([e.from,e.to]=[e.to,e.from]),e.both=e.headStart&&e.headEnd,e.assumed=!e.headStart&&!e.headEnd;let W=0,G=0,K=0,q=0;for(let e of P)if(e.from!==e.to){let t=e.to.bb.cx-e.from.bb.cx,n=e.to.bb.cy-e.from.bb.cy;W+=Math.abs(t),G+=Math.abs(n),K+=t,q+=n}let ve;if(W+G===0){let e=x(g.flatMap(e=>[[e.bb.x0,e.bb.y0],[e.bb.x1,e.bb.y1]]).concat([[0,0]]));ve=e.w>e.h*1.2?`LR`:`TD`}else ve=G>=W?q>=0?`TD`:`BT`:K>=0?`LR`:`RL`;let J=ve===`TD`||ve===`BT`,ye=ve===`BT`||ve===`RL`?-1:1,be=g.map(e=>J?e.bb.h:e.bb.w).sort((e,t)=>e-t),xe=be[be.length>>1]||40,Se=e=>J?[Math.round(ye*e.bb.cy/xe),e.bb.cx]:[Math.round(ye*e.bb.cx/xe),e.bb.cy];if(g.sort((e,t)=>{let n=Se(e),r=Se(t);return n[0]-r[0]||n[1]-r[1]}),g.forEach((e,t)=>{e.id=t<26?String.fromCharCode(65+t):`N`+(t+1),e.label=`Node `+(t+1)}),r===`state`){let e=0,t=0;for(let n of g)n.role=C.has(n)?`dot`:n.kind===`diamond`?`choice`:`state`,n.id=n.role===`dot`?`dot`+ ++t:e<26?String.fromCharCode(65+e++):`N`+ ++e;for(let e of _)e.role=`state`}_.sort((e,t)=>Z(t)-Z(e)).forEach((e,t)=>{e.id=`G`+(t+1),e.label=`Group `+(t+1)});let Y=e=>({id:e.id,kind:e.kind,label:e.label,color:e.color,bb:e.bb,poly:e.poly,unsure:e.unsure,strokes:e.strokes.slice().sort((e,t)=>e-t),parent:e.parent?.id??null,...e.role?{role:e.role}:{}}),Ce=g.map(Y);return r===`state`&&Rt(Ce),{diagram:r,direction:ve,nodes:Ce,groups:_.map(Y),edges:P.map((e,t)=>({id:`L`+(t+1),from:e.from.id,to:e.to.id,both:e.both,assumed:e.assumed,style:e.line.dashes?`dotted`:e.thick?`thick`:`plain`,color:e.color,pts:e.pts,strokes:e.line.strokes.slice().sort((e,t)=>e-t)})),unused:I.sort((e,t)=>e-t),loops:xn(g,P),ms:Pt()-n}}function Rt(e){let t=0;for(let n of e)n.label=n.role===`state`?`State `+ ++t:``}var zt=new Set([`circle`,`double`,`hexagon`,`stadium`,`dot`,`bullseye`]),Bt=44,Vt=2.5,Ht=5,Ut=3,Wt=.25,Gt=50,Kt=70,qt=16,Jt=8,$=24,Yt=96,Xt=26,Zt=16;function Qt(e){let t=x(e),n=Math.max(t.w,t.h),r=b(e),i=[t.cx,t.cy];if(!e.some((t,r)=>r>0&&C(i,e[r-1],t)<Wt*n))return!1;if(r>=Ht*n)return!0;if(r<Vt*n)return!1;let a=Math.max(6,.3*n),o=0,s=1/0;for(let t=1,n=0;t<e.length-1;t++){if(n+=y(e[t-1],e[t]),s+=y(e[t-1],e[t]),n<a||r-n<a)continue;let i=E(e,t,a,-1),c=E(e,t,a,1),l=e[t][0]-i[0],u=e[t][1]-i[1],d=c[0]-e[t][0],f=c[1]-e[t][1],p=Math.hypot(l,u)*Math.hypot(d,f);p>0&&(l*d+u*f)/p<-.4&&s>a&&(o++,s=0)}return o>=Ut}function $t(e){let t=x(e),n=Math.max(t.w,t.h)/2+2,r=[];for(let e=0;e<24;e++)r.push([t.cx+n*Math.cos(e/24*2*Math.PI),t.cy+n*Math.sin(e/24*2*Math.PI)]);return{kind:`circle`,score:0,unsure:!1,bb:x(r),poly:r}}var en=.4,tn=90,nn=60,rn=20;function an(e){if(e.length<5)return-1;let t=e[0],n=e[e.length-1],r=-1,i=0;for(let a=1;a<e.length-1;a++){let o=C(e[a],t,n);o>i&&([r,i]=[a,o])}if(r<0)return-1;let a=y(t,e[r]),o=y(e[r],n);if(a<8||o<8||Math.max(a,o)>3*Math.min(a,o)||b(e.slice(0,r+1))>1.25*a||b(e.slice(r))>1.25*o)return-1;let s=((t[0]-e[r][0])*(n[0]-e[r][0])+(t[1]-e[r][1])*(n[1]-e[r][1]))/(a*o);return s<.94&&s>-.5?r:-1}function on(e,t,n,r,i){let a=i?n.length-1:0,o=n[a],s=E(n,a,20,i?-1:1),c=Math.hypot(o[0]-s[0],o[1]-s[1]);if(c<10)return!1;let l=(o[0]-s[0])/c,u=(o[1]-s[1])/c,d=e[t],f=(d[0]-o[0])*l+(d[1]-o[1])*u,p=Math.abs((d[1]-o[1])*l-(d[0]-o[0])*u);if(f<-8||f>Math.max(40,.5*r)||p>12+.5*Math.max(0,f))return!1;let m=(e[0][0]+e[e.length-1][0])/2,h=(e[0][1]+e[e.length-1][1])/2;return(m-d[0])*l+(h-d[1])*u<0}var sn=50,cn=80,ln=160;function un(e){if(!dn(e))return null;let t=tt(e),n=tt(e.slice().reverse());if((t||n)&&!dn(e.slice(t?t.at:0,n?e.length-n.at:e.length)))return null;let r=x(e);if(Math.max(r.w,r.h)<=ln){let t=nt(e),n=b(t.pts);if(t.headEnd!==t.headStart&&n>=10&&y(t.pts[0],t.pts[t.pts.length-1])>=.9*n)return null}let i=P(e),a=ce(dn(i)?i:e);return a&&!(a.unsure&&Math.max(a.bb.w,a.bb.h)<50)?a:null}function dn(e){if(e.length<3)return!1;let t=b(e),n=x(e);return Math.max(n.w,n.h)>=28&&Math.min(n.w,n.h)>=18&&t>1.3*(n.w+n.h)&&le(e,t)<Math.max(14,.22*Math.hypot(n.w,n.h))}var fn=45,pn=60;function mn(e){for(let t of[e,e.slice().reverse()]){let n=t.length,r=t[n-1],i=b(t),a=-1,o=1/0,s=0;for(let e=1;e<n-1&&(s+=y(t[e-1],t[e]),!(i-s<pn));e++)s>=fn&&y(t[e],r)<o&&(o=y(t[e],r),a=e);if(a<0)continue;let c=t.slice(a),l=x(c),u=t.slice(0,a+1);if(o>=Math.max(14,.22*Math.hypot(l.w,l.h))||Math.max(l.w,l.h)<=sn)continue;let d=x(u);if(Math.max(l.x0-t[0][0],t[0][0]-l.x1,l.y0-t[0][1],t[0][1]-l.y1)<Math.max(20,.2*Math.hypot(l.w,l.h))||y(t[0],t[a])<Math.max(14,.22*Math.hypot(d.w,d.h)))continue;let f=un(c);if(!(!f||ne(t[0],f.poly)||w(t[0],f.poly)<20))return t===e?{loop:c,line:u,end:1,fit:f}:{loop:c.reverse(),line:u.reverse(),end:0,fit:f}}return null}var hn=44,gn=.65;function _n(e,t){let n=(e,t)=>{let n=y(e,t)||1;return[(t[0]-e[0])/n,(t[1]-e[1])/n]},r=[];for(let i of e){if(i.len>132)continue;let e=nt(i.pts),a=e.pts;if(e.headEnd!==e.headStart){let t=e.headEnd?i.pts:i.pts.slice().reverse(),n=Math.max(...t.map(e=>y(e,t[0]))),r=t.findIndex(e=>y(e,t[0])>=n-3);a=e.headEnd?t.slice(0,r+1):t.slice(0,r+1).reverse()}let o=b(a),s=a[0],c=a[a.length-1];if(a.length<2||o<6||o>hn||y(s,c)<gn*o||e.headStart&&e.headEnd)continue;let l=[n(E(a,0,6,1),s),n(E(a,a.length-1,6,-1),c)];r.push({it:i,end:[s,c],out:l,hook:[e.headStart,e.headEnd],atShape:[t(s,6),t(c,6)],len:o})}if(r.length<2)return[];let i=(e,t)=>e[0]*t[0]+e[1]*t[1],a=[];for(let e=0;e<r.length;e++)for(let o=e+1;o<r.length;o++)for(let s of[0,1])for(let c of[0,1]){let l=r[e],u=r[o];if(l.hook[s]||u.hook[c]||l.atShape[s]||u.atShape[c])continue;let d=l.end[s],f=u.end[c],p=y(d,f);if(p<3||p>Math.min(48,Math.max(16,1.8*Math.max(l.len,u.len))))continue;let m=l.out[s],h=n(d,f),g=[-u.out[c][0],-u.out[c][1]],_=i(m,h)>=-.1&&i(h,g)>=-.1&&i(m,h)+i(h,g)>=.9&&i(m,g)>=-.4,v=e=>[d[0]+e*(f[0]-d[0]),d[1]+e*(f[1]-d[1])];_&&![.25,.5,.75].some(e=>t(v(e),3))&&a.push([p,e,s,o,c])}a.sort((e,t)=>e[0]-t[0]);let o=r.map(()=>[null,null]),s=r.map((e,t)=>t),c=e=>s[e]===e?e:s[e]=c(s[e]);for(let[,e,t,n,r]of a)o[e][t]||o[n][r]||c(e)===c(n)||(o[e][t]=[n,r],o[n][r]=[e,t],s[c(e)]=c(n));let l=[],u=new Set;return r.forEach((e,t)=>{let n=o[t][0]?o[t][1]?-1:1:0;if(u.has(t)||n<0||!o[t][1-n])return;let i=[],a=[t,n];for(;a&&!u.has(a[0]);){let[e,t]=a;u.add(e),i.push({it:r[e].it,flip:t===1}),a=o[e][1-t]}if(i[0].it.index>i[i.length-1].it.index){i.reverse();for(let e of i)e.flip=!e.flip}l.push(i)}),l}var vn=8,yn=10;function bn(e,t){let n=e=>Math.max(20,y(e[0],e[e.length-1]));if(Math.min(n(e),n(t))<.6*Math.max(n(e),n(t)))return!1;let r=Math.min(yn,Math.max(vn,.04*Math.min(b(e),b(t)))),i=(e,t)=>S(e,16).slice(3,13).every(e=>te(e,t)<=r);return i(e,t)&&i(t,e)}function xn(e,t){let n=new Map(e.map(e=>[e,[]])),r=new Map(e.map(e=>[e,[]]));for(let e of t)n.has(e.from)&&n.has(e.to)&&(n.get(e.from).push(e.to),r.get(e.to).push(e.from),e.both&&(n.get(e.to).push(e.from),r.get(e.from).push(e.to)));let i=[],a=new Set;for(let t of e){if(a.has(t))continue;a.add(t);let e=[[t,0]];for(;e.length;){let t=e[e.length-1],r=n.get(t[0]);if(t[1]<r.length){let n=r[t[1]++];a.has(n)||(a.add(n),e.push([n,0]))}else i.push(t[0]),e.pop()}}let o=new Set,s=0;for(let e of i.reverse()){if(o.has(e))continue;let t=[e],i=0;for(o.add(e);t.length;){let e=t.pop();i++;for(let n of r.get(e))o.has(n)||(o.add(n),t.push(n))}(i>1||n.get(e).includes(e))&&s++}return s}var Sn=[{key:`ink`,name:`Ink`},{key:`green`,name:`Green`},{key:`blue`,name:`Blue`},{key:`red`,name:`Red`},{key:`amber`,name:`Amber`}],Cn={rect:[`box`,`boxes`],subroutine:[`box in a box`,`boxes in boxes`],stadium:[`oval`,`ovals`],circle:[`circle`,`circles`],double:[`double circle`,`double circles`],diamond:[`diamond`,`diamonds`],hexagon:[`hexagon`,`hexagons`],trapezoid:[`trapezoid`,`trapezoids`],"inv-trapezoid":[`trapezoid wide at the top`,`trapezoids wide at the top`],"lean-right":[`parallelogram`,`parallelograms`],"lean-left":[`parallelogram leaning left`,`parallelograms leaning left`],triangle:[`triangle`,`triangles`],"flip-triangle":[`triangle pointing down`,`triangles pointing down`],dot:[`start dot`,`start dots`],bullseye:[`end ring`,`end rings`]},wn=[[`rect`,`Agent: box`],[`stadium`,`Researcher: oval`],[`diamond`,`Critic: diamond`],[`hexagon`,`Check: hexagon`],[`trapezoid`,`Human gate: trapezoid`],[`circle`,`Merge: circle`],[`double`,`Stop: double circle`],[`subroutine`,`Agent: box in a box`],[`lean-right`,`Agent: parallelogram`],[`lean-left`,`Agent: parallelogram, leaning left`],[`inv-trapezoid`,`Agent: trapezoid, wide at the top`],[`triangle`,`Agent: triangle`],[`flip-triangle`,`Agent: triangle, pointing down`]],Tn=[{kind:`rect`,label:`Agent`,w:150,h:64},{kind:`stadium`,label:`Researcher`,w:150,h:60},{kind:`diamond`,label:`Critic`,w:140,h:104},{kind:`hexagon`,label:`Check`,w:150,h:64},{kind:`trapezoid`,label:`Human gate`,w:170,h:64},{kind:`circle`,label:`Merge`,w:84,h:84},{kind:`double`,label:`Stop`,w:84,h:84}],En=(e,t,n)=>`${e} ${e===1?t:n}`,Dn=`groophSketch.v1`,On=16,kn=e=>({nodes:e.nodes.map(e=>({id:e.id,name:e.name||e.id,shape:q(e)})),edges:e.edges.map(e=>({id:e.id,from:e.from,to:e.to,name:ye(e)})),groups:(e.groups??[]).map(e=>({id:e.id,name:e.name||e.id,members:e.members}))}),An=e=>JSON.stringify(kn(e));function jn(e,t){let n;try{n=JSON.parse(e)}catch{return null}if(!Array.isArray(n?.nodes)||!Array.isArray(n.edges)||!Array.isArray(n.groups)||n.nodes.length!==t.nodes.length||n.edges.length!==t.edges.length||n.groups.length!==t.groups.length)return null;let r=new Map;for(let[e,i]of n.nodes.entries()){if(i.shape!==t.nodes[e].shape)return null;r.set(i.id,t.nodes[e].id)}for(let[e,i]of n.groups.entries())r.set(i.id,t.groups[e].id);for(let[e,i]of n.edges.entries()){let n=t.edges[e];if(r.get(i.from)!==n.from||r.get(i.to)!==n.to)return null;r.set(i.id,n.id)}for(let[e,i]of n.groups.entries())if(JSON.stringify(i.members.map(e=>r.get(e)))!==JSON.stringify(t.groups[e].members))return null;return r}function Mn(e){try{let t=localStorage.getItem(`${Dn}:${e}`);if(!t)return null;let n=JSON.parse(t),r=Ue(n.file);if(!r.ok)return null;let i=Array.isArray(n.marks)&&n.marks.length===r.file.strokes.length?n.marks:r.file.strokes.map(()=>null),a=Array.isArray(n.unboxed)?n.unboxed.filter(e=>typeof e==`string`):[];return{file:r.file,marks:i,synced:typeof n.synced==`string`?n.synced:``,unboxed:a}}catch{return null}}function Nn(e,t){try{let n=JSON.parse(localStorage.getItem(Dn)??`[]`).filter(t=>typeof t==`string`&&t!==e);for(t?(localStorage.setItem(`${Dn}:${e}`,JSON.stringify(t)),n.push(e)):localStorage.removeItem(`${Dn}:${e}`);n.length>On;)localStorage.removeItem(`${Dn}:${n.shift()}`);localStorage.setItem(Dn,JSON.stringify(n))}catch{}}function Pn(e,t){e.classList.add(`sk`),e.innerHTML=ke;let n=!1,r=t=>e.querySelector(`#sk-${t}`),i=[],a=(e,t,n,r)=>{e.addEventListener(t,n,r),i.push(()=>e.removeEventListener(t,n,r))},s={};function c(e,t,n){clearTimeout(s[e]),s[e]=setTimeout(t,n)}let l={strokes:[],undo:[],redo:[],reading:null,stale:!1,labels:{},tool:`draw`,color:`ink`,synced:``,made:null,unboxed:[]},d=r(`pad`),_=null,v=0,y=r(`sel-bar`),b=bt(d,{begin(){r(`hint`).hidden=!0},select(){F()},edit(e){x(e),F()},stroke(...e){x([...l.strokes,...e])},erase(e){let t=new Set(e);x(l.strokes.filter(e=>!t.has(e.id)))},cut(e,t){let n=je(l.strokes,e,t,b.nextId);if(!n.pieces.size)return;let r=[...P(),...le()];for(let[e,t]of n.pieces){V.set(e,t);for(let n of t)he.set(n,e);for(let n of r)if(n.has(e))for(let r of t)n.set(r,n.get(e))}x(n.strokes)},tap(e){if(!l.strokes.length)return;let t=t=>Me(e,`nodes`,t)??Ne(e,t)??Me(e,`groups`,t),n=!!l.reading&&!l.stale;if(!t(n?l.reading:Kt())){b.overlaid&&b.setOverlay(null);return}n?b.overlaid||b.setOverlay({reading:l.reading,labels:l.labels}):Se();let r=t(l.reading);r&&`kind`in r&&r.kind===`dot`?Y(`A start dot is not a step: a run starts at the steps nothing leads to.`):r&&Je(r)},empty(){b.overlaid&&b.setOverlay(null)},penMode(e){r(`pen-chip`).hidden=!e},view(e){if(n)return;let t=r(`zoom`);t.hidden=Math.abs(e.scale-1)<.01,t.textContent=Math.round(e.scale*100)+`%`,Ye(!0),F()}});function x(e){l.undo.push(l.strokes),l.undo.length>200&&l.undo.shift(),l.redo=[],S(e)}function S(e){l.strokes=e,b.setStrokes(e),l.stale=!0,r(`go`).dataset.stale=String(e.length>0),r(`hint`).hidden=e.length>0,r(`undo`).disabled=!l.undo.length,r(`clear`).disabled=!e.length,r(`redo`).disabled=!l.redo.length,b.setOverlay(null),Ye(!0),F(),Rt(),c(`names`,Ie,120)}function C(){let e=l.undo.pop();e&&(l.redo.push(l.strokes),S(e))}function w(){let e=l.redo.pop();e&&(l.undo.push(l.strokes),S(e))}r(`undo`).addEventListener(`click`,C),r(`redo`).addEventListener(`click`,w);let T=Array.from(e.querySelectorAll(`button[data-tool]`)),E=`groophSketch.eraser`,re=`groophSketch.select`,ie=`whole`,ae=`box`;try{localStorage.getItem(E)===`part`&&(ie=`part`),localStorage.getItem(re)===`lasso`&&(ae=`lasso`)}catch{}b.setChooseBy(ae);let se=e=>e.dataset.tool===`erase`&&ie===`part`?`cut`:e.dataset.tool;function D(e){l.tool=e,b.setTool(e);let t=e===`cut`?`erase`:e;for(let e of T)e.setAttribute(`aria-checked`,String(e.dataset.tool===t));j.open(!1),F()}let O={eraser:[[`whole`,`Erase whole strokes`,`A touch takes the whole stroke`],[`part`,`Erase only what it passes over`,`Cuts a line apart from its box`]],select:[[`box`,`Drag a box`,`Takes every stroke the box reaches into`],[`lasso`,`Draw a lasso`,`Takes every stroke the loop reaches into`]]},k=r(`tool-menu`),A=`eraser`,j={list:k,open(e,t=!0){k.hidden=!e,e&&t&&k.querySelector(`[aria-checked="true"]`)?.focus()},get isOpen(){return!k.hidden}};function M(e,t,n){A=e;let r=e===`eraser`?ie:ae;k.setAttribute(`aria-label`,e===`eraser`?`Eraser`:`Select`),k.innerHTML=O[e].map(([e,t,n])=>`<li role="none"><button type="button" role="menuitemradio" aria-checked="${e===r}" data-kind="${e}">${t}<small>${n}</small></button></li>`).join(``);let i=t.closest(`.sk-tools`).getBoundingClientRect(),a=t.getBoundingClientRect();k.style.left=ce()?``:`${Math.max(0,a.left-i.left)}px`;for(let e of rt)e.open(!1);j.open(!0,n)}let ce=()=>e.clientWidth<720;function N(e,t){e===`eraser`?(ie=t===`part`?`part`:`whole`,D(ie===`part`?`cut`:`erase`)):(ae=t===`lasso`?`lasso`:`box`,b.setChooseBy(ae),D(`select`));try{localStorage.setItem(e===`eraser`?E:re,t)}catch{}}for(let e of T)e.addEventListener(`click`,t=>{let n=se(e),r=e.dataset.options;r&&l.tool===n?j.isOpen&&A===r?j.open(!1):M(r,e,t.detail===0):D(n)});k.addEventListener(`click`,e=>{let t=e.target.closest(`[data-kind]`)?.dataset.kind;t&&(N(A,t),T.find(e=>e.dataset.options===A)?.focus())}),k.addEventListener(`keydown`,e=>{let t=Array.from(k.querySelectorAll(`button`)),n=t.indexOf(document.activeElement);e.key===`ArrowDown`||e.key===`ArrowUp`?(e.preventDefault(),t[(n+(e.key===`ArrowDown`?1:-1)+t.length)%t.length].focus()):e.key===`Escape`?(e.preventDefault(),j.open(!1),T.find(e=>e.dataset.options===A)?.focus()):e.key===`Tab`&&j.open(!1)});let P=()=>[W.shape,W.line,K],le=()=>[J.node,J.edge,J.group];function F(){let e=l.tool===`select`?b.chosenBox():null,t=e!==null;for(let e of y.querySelectorAll(`[data-sel]`))e.hidden=e.dataset.sel===`paste`?!_:!t;let n=t&&I(b.chosen)!==void 0,r=y.querySelector(`[data-sel="group"]`);if(r.textContent=n?`Ungroup`:`Group`,r.setAttribute(`aria-label`,n?`Ungroup the chosen strokes`:`Group the chosen strokes`),y.hidden=l.tool!==`select`||!t&&!_,y.hidden)return;let i=y.offsetWidth,a=y.offsetHeight,o=d.clientWidth,s=d.clientHeight,c=o/2-i/2,u=8;e&&(c=(e.x0+e.x1)/2-i/2,u=e.turn[1]-16-a>=4?e.turn[1]-16-a:e.y1+14,u+a>s-4&&(u=Math.max(4,Math.min(s-a-4,e.y0+4)))),y.style.left=d.offsetLeft+Math.max(4,Math.min(o-i-4,c))+`px`,y.style.top=d.offsetTop+u+`px`}function I(e){let t=new Set(l.strokes.filter(t=>e.includes(t.id)).map(e=>e.group));return t.size===1?[...t][0]:void 0}function L(){let e=new Set(b.chosen);if(!e.size)return!1;let t=l.strokes.filter(t=>e.has(t.id));return _={strokes:t,kept:P().map(e=>new Map(t.filter(t=>e.has(t.id)).map(t=>[t.id,e.get(t.id)])))},v=0,!0}function R(e,t,n,r){let{copies:i,from:a}=gt(e,new Set(e.map(e=>e.id)),n,r,b.nextId,[...l.strokes,...e]),o=P();for(let[e,n]of a)t.forEach((t,r)=>t.has(n)&&o[r].set(e,t.get(n)));x([...l.strokes,...i]),b.choose(i.map(e=>e.id))}function ue(){let e=new Set(b.chosen);e.size&&x(l.strokes.filter(t=>!e.has(t.id)))}function de(){if(!_)return;let e=mt(_.strokes,new Set(_.strokes.map(e=>e.id))),t=b.view,n=b.size,r=24/t.scale,i=-t.x/t.scale+n.w/2+v*r,a=-t.y/t.scale+n.h/2+v*r;v++,R(_.strokes,_.kept,i-e.cx,a-e.cy)}function fe(e){let t=b.chosen;if(e===`copy`&&L())Y(`Copied. Paste puts a copy in the middle of the screen.`);else if(e===`cut`&&L())ue(),Y(`Cut. Paste puts it back in the middle of the screen.`);else if(e===`paste`)de();else if(e===`duplicate`&&t.length){let e=l.strokes.filter(e=>t.includes(e.id)),n=24/b.view.scale;R(e,P().map(t=>new Map(e.filter(e=>t.has(e.id)).map(e=>[e.id,t.get(e.id)]))),n,n)}else if(e===`delete`)ue();else if(e===`snap`&&t.length){let e=Kt(),n=be(e).shapes,r={...e,nodes:e.nodes.map(e=>n[e.id]?{...e,kind:n[e.id]}:e)},i=Ct(l.strokes,new Set(t),r,b.nextId);if(!i.shapes&&!i.arrows)Y(`Nothing here to snap: hold a shape or an arrow still as you draw it, or draw it closer to one grooph knows.`);else{let e=[...P(),...le()];for(let[t,n]of i.from)for(let r of e)r.has(n)&&r.set(t,r.get(n));x(i.strokes);let n=new Set(i.strokes.map(e=>e.id));b.choose([...t.filter(e=>n.has(e)),...i.from.keys()]),Y(`Snapped ${[i.shapes&&En(i.shapes,`shape`,`shapes`),i.arrows&&En(i.arrows,`arrow`,`arrows`)].filter(Boolean).join(` and `)} clean. Undo brings back what was drawn.`)}}else if(e===`group`&&t.length){let e=I(t)!==void 0,n=1+Math.max(0,...l.strokes.map(e=>e.group??0));x(l.strokes.map(r=>t.includes(r.id)?e?{...r,group:void 0}:{...r,group:n}:r)),Y(e?`Ungrouped.`:`Grouped: tapping any of these strokes chooses them all.`)}F()}y.addEventListener(`click`,e=>{let t=e.target.closest(`[data-sel]`)?.dataset.sel;t&&fe(t)});let pe=r(`inks`);for(let e of Sn){let t=`sk-ink-`+e.key;pe.insertAdjacentHTML(`beforeend`,`<input type="radio" name="sk-ink" id="${t}" value="${e.key}"${e.key===`ink`?` checked`:``}><label for="${t}" title="${e.name}"><span class="sr-only">${e.name}</span><span class="sk-swatch" style="background:var(--draw-${e.key})"></span></label>`)}pe.addEventListener(`change`,e=>{l.color=e.target.value,b.setColor(l.color),D(`draw`)}),r(`fingers-draw`).addEventListener(`click`,()=>{b.setPenMode(!1),r(`pen-chip`).hidden=!0}),r(`zoom`).addEventListener(`click`,()=>b.fitContent());let me=new Map,he=new Map,V=new Map;function ge(e){let t=new Set([e]);for(let n=he.get(e);n!==void 0&&!t.has(n);n=he.get(n))t.add(n);let n=[e];for(;n.length;)for(let e of V.get(n.pop())??[])t.has(e)||(t.add(e),n.push(e));return[...t]}let H=e=>[...me.get(e)??[]].flatMap(ge),_e=new Set,W={shape:new Map,line:new Map};function G(e,t){let n=W[_e.has(e)?`line`:`shape`];for(let r of H(e))t.trim()?n.set(r,t):n.delete(r)}let K=new Map,q=new Map;function ve(e,t){for(let n of H(e))t===q.get(e)?K.delete(n):K.set(n,t)}let J={node:new Map,edge:new Map,group:new Map},ye=(e,t)=>t.bb.cx>e.bb.x0&&t.bb.cx<e.bb.x1&&t.bb.cy>e.bb.y0&&t.bb.cy<e.bb.y1;function be(e){let t=l.reading,n=l.labels,r=me,i=new Map([...e.nodes,...e.groups,...e.edges].map(e=>[e.id,new Set(e.strokes.map(e=>l.strokes[e]?.id).filter(e=>e!==void 0))])),a={},o={},s={nodes:{},edges:{},groups:{}},c=(e,t)=>e.map(e=>t.get(e)).find(e=>e!==void 0);for(let t of[...e.nodes,...e.groups,...e.edges]){let n=[...i.get(t.id)],r=e.edges.includes(t),l=W[r?`line`:`shape`],u=n.map(e=>l.get(e)).find(Boolean);if(u&&(a[t.id]=u),e.nodes.includes(t)){let e=n.map(e=>K.get(e)).find(Boolean);e&&(o[t.id]=e);let r=c(n,J.node);r&&(s.nodes[t.id]=r)}else if(r){let e=c(n,J.edge);e&&(s.edges[t.id]=e)}else{let e=c(n,J.group);e&&(s.groups[t.id]=e)}}if(t){let o=new Set(l.strokes.map(e=>e.id));for(let i of[`nodes`,`groups`]){let c=t[i].filter(e=>n[e.id]?.trim()&&![...r.get(e.id)??[]].some(e=>o.has(e)));for(let t of e[i]){if(a[t.id]||!c.length)continue;let e=c.filter(e=>ye(t,e)&&ye(e,t)).sort((e,n)=>Math.hypot(e.bb.cx-t.bb.cx,e.bb.cy-t.bb.cy)-Math.hypot(n.bb.cx-t.bb.cx,n.bb.cy-t.bb.cy))[0];if(!e)continue;a[t.id]=n[e.id],c.splice(c.indexOf(e),1);let r=i===`nodes`?xe.nodes[e.id]:xe.groups[e.id],o=i===`nodes`?s.nodes:s.groups;r&&!Object.values(o).includes(r)&&(o[t.id]=r)}}let c=t=>{let n=r.get(t)??new Set;return[...e.nodes,...e.groups].find(e=>[...i.get(e.id)].some(e=>n.has(e)))?.id},u=t.edges.filter(e=>n[e.id]?.trim()&&![...r.get(e.id)??[]].some(e=>o.has(e))),d=new Set([...r.values()].flatMap(e=>[...e]));for(let t of e.edges){if(a[t.id]||!u.length||[...i.get(t.id)].some(e=>d.has(e)))continue;let e=u.find(e=>{let n=c(e.from),r=c(e.to);return n===t.from&&r===t.to||n===t.to&&r===t.from});e&&(a[t.id]=n[e.id],u.splice(u.indexOf(e),1))}}return{drawnWith:i,labels:a,shapes:o,marks:s}}let xe={nodes:{},edges:{},groups:{}};function Se(){let e=It(l.strokes,{diagram:`flowchart`}),{labels:t,shapes:n,marks:i,drawnWith:a}=be(e);me=a,_e=new Set(e.edges.map(e=>e.id)),q=new Map(e.nodes.map(e=>[e.id,e.kind]));for(let t of e.nodes)n[t.id]&&(t.kind=n[t.id],t.unsure=!1);l.reading=e,l.labels=t,xe=i;for(let[e,n]of Object.entries(t))G(e,n);return l.stale=!1,r(`go`).dataset.stale=`false`,Ce(e),We(),b.setOverlay({reading:e,labels:t}),Ie(),i}function Y(e){let t=document.createElement(`span`);t.textContent=e,r(`read`).replaceChildren(t)}function Ce(e,t){let n={};for(let t of e.nodes)n[t.kind]=(n[t.kind]||0)+1;let i=Object.entries(n).map(([e,t])=>En(t,...Cn[e])),a=e.edges.length,o=e.edges.filter(e=>e.assumed).length,s=e.nodes.filter(e=>e.unsure).length,c=[],l=o?`, ${o} with no head, so pointed the way ${o===1?`it was`:`they were`} drawn`:``;c.push(e.nodes.length?`<strong>${En(e.nodes.length,`shape`,`shapes`)}</strong> (${i.join(`, `)})`:`<strong>no shapes</strong>`),e.groups.length&&c.push(En(e.groups.length,`box`,`boxes`)),c.push(En(a,`arrow`,`arrows`)+l),e.loops&&c.push(`<strong>${En(e.loops,`loop`,`loops`)}</strong>`),e.unused.length&&c.push(`${En(e.unused.length,`mark`,`marks`)} left out, shaded on the drawing`),s&&c.push(`${En(s,`shape`,`shapes`)} hard to read`);let u=t?` ${we(t)}`:``;r(`read`).innerHTML=`<span>Read ${c.join(` · `)}.${u}</span> <span class="sk-ms">${e.ms.toFixed(1)} ms</span> <a class="sk-to-result" href="#sk-result">See the graph</a>`}function we(e){let{added:t,kept:n,removed:r}=e.counts,i=[t&&En(t,`new step`,`new steps`),n&&`${n} kept`,r&&`${r} taken away`].filter(Boolean);return`Made the graph${i.length?`: ${i.join(`, `)}`:``}.`}function Ee(e=!1,n=!1){if(!l.strokes.length){Y(`Draw something first, or load the example from More.`);return}let r=l.reading&&!l.stale?xe:Se(),i=l.reading,a=t.doc(),o=Oe(i,l.labels,r,a,l.unboxed);if(`error`in o){Y(o.error);return}if(o.doc.nodes.length===0&&a.nodes.length>0){Y(`No step was read, so the graph is as it was.`);return}let s=(e,t,n)=>{for(let r of t){let t=e[r.id];if(t!==void 0)for(let e of r.strokes)l.strokes[e]&&n.set(l.strokes[e].id,t)}};s(o.became.nodes,i.nodes,J.node),s(o.became.edges,i.edges,J.edge),s(o.became.groups,i.groups,J.group),xe=o.became;let c=!De(o.doc,a),u=n&&l.made?l.made:null;l.made={...o,at:c?o.doc:a,before:u?u.before:a,changed:c||!!u?.changed},l.synced=An(o.doc),c&&t.apply(o.doc,e),Ce(i,o),et(o.doc,o),Rt()}r(`go`).addEventListener(`click`,()=>Ee());function Ae(t){b.setShowOverlay(t),r(`show-read`).checked=t,e.querySelector(`[data-act="outlines"]`).setAttribute(`aria-checked`,String(t))}r(`show-read`).addEventListener(`change`,e=>Ae(e.target.checked));function Me(e,t,n=l.reading){if(!n)return null;let r=e=>e.bb.w*e.bb.h;return n[t].filter(t=>ne(e,t.poly)).sort((e,t)=>r(e)-r(t))[0]??null}function Ne(e,t=l.reading){let n=16/b.view.scale;if(!t)return null;let r=null;for(let i of t.edges){let t=te(e,i.pts);t<=n&&(!r||t<r.d)&&(r={e:i,d:t})}return r?.e??null}let Pe=`groophSketch.names`,Fe=!0;try{Fe=localStorage.getItem(Pe)!==`off`}catch{}function Ie(){if(b.pressing)return c(`names`,Ie,200);if(!l.strokes.some(e=>W.shape.has(e.id)||W.line.has(e.id))||!Fe)return b.setNames([]);let e=!!l.reading&&!l.stale,t=e?l.reading:Kt(),n=e?l.labels:be(t).labels,r=[],i=e=>e.flatMap(e=>l.strokes[e]?[l.strokes[e].id]:[]);for(let e of[...t.nodes,...t.groups]){let a=n[e.id]?.trim();a&&e.kind!==`dot`&&r.push({strokes:i(e.strokes),at:[e.bb.cx,t.groups.includes(e)?e.bb.y0+16:e.bb.cy],text:a,w:e.bb.w,line:!1})}for(let e of t.edges){let t=n[e.id]?.trim();t&&e.pts.length>1&&r.push({strokes:i(e.strokes),at:ee(e.pts),text:t,w:180,line:!0})}b.setNames(r)}function Le(e){Fe=e,b.setShowNames(e),r(`more-list`).querySelector(`[data-act="names"]`).setAttribute(`aria-checked`,String(e));try{e?localStorage.removeItem(Pe):localStorage.setItem(Pe,`off`)}catch{}Ie()}function Re(e){l.made&&l.reading&&!l.stale&&c(`make`,()=>Ee(e,!0),e?250:0)}function ze(t,n){l.labels[t]=n,G(t,n),l.reading&&!l.stale&&b.setOverlay({reading:l.reading,labels:l.labels}),c(`names`,Ie,60);let r=e.querySelector(`#sk-name-${t}`);r&&r.value!==n&&(r.value=n),Re(!0),Rt()}function Be(t,n){let r=l.reading?.nodes.find(e=>e.id===t);r&&r.kind!==n&&(r.kind=n,r.unsure=!1,ve(t,n),e.querySelector(`#sk-name-${t}`)?.setAttribute(`aria-label`,`Name for ${t}, ${Cn[n][0]}`),l.stale||(b.setOverlay({reading:l.reading,labels:l.labels}),Ce(l.reading)),Re(!1),Rt())}let Ve=e=>xe.nodes[e.id];function We(){let e=r(`names`),t=l.reading;if(e.textContent=``,t){for(let n of[...t.nodes,...t.groups]){if(n.kind===`dot`)continue;let r=t.groups.includes(n),i=r?`box`:Cn[n.kind]?.[0]??`shape`,a=document.createElement(`label`),o=document.createElement(`span`),s=document.createElement(`input`);o.className=`sk-tag`,o.textContent=n.id,s.id=`sk-name-`+n.id,s.value=l.labels[n.id]??``,s.placeholder=n.label,s.autocomplete=`off`,s.dataset.ownUndo=``,s.setAttribute(`aria-label`,`Name for ${n.id}, ${i}`),s.addEventListener(`input`,()=>ze(n.id,s.value)),a.append(o,s);let c=document.createElement(`div`);if(c.className=`sk-name-row`,c.append(a),r){let e=document.createElement(`span`);e.className=`sk-shape-note`,e.textContent=`Box of steps`,c.append(e)}else{let e=document.createElement(`select`);e.id=`sk-shape-`+n.id,e.setAttribute(`aria-label`,`Shape for ${n.id}`);let t=n.kind===`bullseye`?[[`bullseye`,`Stop: end ring`],...wn]:wn;for(let[r,i]of t)e.add(new Option(i,r,!1,r===n.kind));e.addEventListener(`change`,()=>Be(n.id,e.value)),c.append(e),Ve(n)&&(c.dataset.step=Ve(n))}e.append(c)}for(let n of t.edges){let t=document.createElement(`label`),r=document.createElement(`span`),i=document.createElement(`input`);r.className=`sk-tag sk-line-tag`,r.textContent=`${n.from}${n.both?`↔`:`→`}${n.to}`,i.id=`sk-name-`+n.id,i.value=l.labels[n.id]??``,i.placeholder=`No name`,i.autocomplete=`off`,i.dataset.ownUndo=``,i.setAttribute(`aria-label`,`Name for the line from ${n.from} ${n.both?`and`:`to`} ${n.to}`),i.addEventListener(`input`,()=>ze(n.id,i.value)),t.append(r,i);let a=document.createElement(`div`);a.className=`sk-name-row`,a.append(t),e.append(a)}!t.nodes.length&&!t.groups.length&&(e.innerHTML=`<p class="sk-status">No shapes were read. Draw a closed shape, like a box or a circle.</p>`)}}let Ge=r(`name-edit`),Ke=r(`name-input`),qe=null;function Je(e){Ye(!0),qe=e;let t=`pts`in e&&`from`in e,n=t?ee(e.pts):[e.bb.cx,e.bb.cy],i=r(`pad-wrap`).getBoundingClientRect(),[a,o]=b.toScreen(n),s=Math.min(i.width-16,Math.max(200,t?0:e.bb.w*b.view.scale));Ge.style.width=s+`px`,Ge.style.left=Math.max(8,Math.min(i.width-s-8,a-s/2))+`px`,Ge.style.top=Math.max(8,Math.min(i.height-52,o-22))+`px`,r(`name-label`).textContent=t?`Name for the line from ${e.from} ${e.both?`and`:`to`} ${e.to}`:`Name for ${e.id}`,Ke.value=l.labels[e.id]??``,Ke.placeholder=t?`Name this line`:e.label,Ge.hidden=!1,Ke.focus({preventScroll:!0}),Ke.select()}function Ye(e){qe&&(e&&ze(qe.id,Ke.value),qe=null,Ge.hidden=!0)}Ge.addEventListener(`submit`,e=>{e.preventDefault(),Ye(!0)}),Ke.addEventListener(`keydown`,e=>{e.key===`Escape`&&(e.preventDefault(),Ye(!1),d.focus())}),Ke.addEventListener(`blur`,()=>Ye(!0)),d.addEventListener(`pointerdown`,()=>Ye(!0),{capture:!0});let Xe=r(`code`),Ze=r(`diagram`),Qe=``,$e=0;async function et(e,t){let i=++$e;Xe.value=e.nodes.length?o(e):``;let a=r(`guesses`),s=t?[...t.left?[t.left]:[],...t.guesses]:[];if(a.replaceChildren(...s.map(e=>Object.assign(document.createElement(`li`),{textContent:e}))),a.hidden=s.length===0,r(`undo-make`).hidden=!t||!l.made?.changed,!e.nodes.length){Ze.innerHTML=`<p class="sk-empty">The graph appears here after Make it a graph.</p>`,Qe=``,tt();return}let c=g(e,`auto`);try{if(document.querySelector(`main.stage[data-look]`)||h()){let e=(await f()).look();e&&(c=e.picture(c,matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`))}}catch{}i!==$e||n||(Ze.innerHTML=c,Qe=c,tt())}Ze.addEventListener(`click`,e=>{let n=e.target.closest(`[data-node]`)?.dataset.node;n&&t.open(n)});function tt(){r(`save-svg`).disabled=!Qe,r(`save-png`).disabled=!Qe}let nt=(e,t)=>{let n=r(e);n.textContent=t,c(`say-`+e,()=>n.textContent=``,4e3)};r(`undo-make`).addEventListener(`click`,()=>{if(!l.made)return;let e=l.made.before;l.made=null,l.synced=An(e),t.apply(e,!1),r(`go`).dataset.stale=`true`,r(`undo-make`).hidden=!0,r(`guesses`).hidden=!0,Y(`The graph is as it was before Make it a graph. The drawing is as you left it.`)}),r(`save-svg`).addEventListener(`click`,()=>{let e=t.doc();Qe&&u(m(e,`light`,`svg`).replace(`.light.`,`.`),Qe,`image/svg+xml`)}),r(`save-png`).addEventListener(`click`,async()=>{let e=t.doc();try{Qe&&u(m(e,`light`,`png`).replace(`.light.`,`.`),await p(Qe),`image/png`)}catch{nt(`save-status`,`The PNG could not be made here. Save SVG still works.`)}}),r(`export`).addEventListener(`click`,()=>t.exporting()),r(`copy`).addEventListener(`click`,async()=>{try{await navigator.clipboard.writeText(Xe.value),nt(`copy-status`,`Copied.`)}catch{Xe.focus(),Xe.select(),nt(`copy-status`,`Copy was blocked here; the code is selected, so copy it by hand.`)}}),r(`save-mmd`).addEventListener(`click`,()=>{Xe.value.trim()&&u(`${t.doc().id||`graph`}.mmd`,Xe.value.trimEnd()+`
|
|
143
|
+
`,`text/plain`)});let rt=[j];function it(e,t){let n=()=>Array.from(t.querySelectorAll(`[role^=menuitem]`)),r=(r,i=!0)=>{t.hidden=!r,e.setAttribute(`aria-expanded`,String(r)),r&&i&&n()[0].focus()};e.addEventListener(`click`,()=>{for(let e of rt)e.list!==t&&e.open(!1);r(e.getAttribute(`aria-expanded`)!==`true`,!1)}),e.addEventListener(`keydown`,t=>{t.key===`ArrowDown`?(t.preventDefault(),r(!0)):t.key===`Escape`&&e.getAttribute(`aria-expanded`)===`true`&&(t.preventDefault(),r(!1))}),t.addEventListener(`keydown`,t=>{let i=n(),a=i.indexOf(document.activeElement);t.key===`ArrowDown`||t.key===`ArrowUp`?(t.preventDefault(),i[(a+(t.key===`ArrowDown`?1:-1)+i.length)%i.length].focus()):t.key===`Escape`?(t.preventDefault(),r(!1),e.focus()):t.key===`Tab`&&r(!1)});let i={list:t,open:r,get isOpen(){return e.getAttribute(`aria-expanded`)===`true`}};return rt.push(i),i}let at=r(`more`),ot=r(`more-list`),st=it(at,ot);a(document,`pointerdown`,e=>{for(let t of rt)t.list.parentElement.contains(e.target)||t.open(!1)});let ct=r(`add`),lt=r(`add-list`);function ut(e){let t=e=>`<svg viewBox="0 0 28 20" aria-hidden="true">${e}</svg>`;if(e===`double`)return t(`<circle cx="14" cy="10" r="7.5" /><circle cx="14" cy="10" r="4.6" />`);if(e===`circle`)return t(`<circle cx="14" cy="10" r="7.5" />`);if(e===`stadium`)return t(`<rect x="2.5" y="3.5" width="23" height="13" rx="6.5" />`);if(e===`dot`||e===`bullseye`)return t(`<circle cx="14" cy="10" r="4.5" class="sk-fill" />`);let[n,r]=e===`diamond`||e===`triangle`?[18,15]:[23,13],i=14-n/2,a=10-r/2;return t(`<polygon points="${oe[e].map(([e,t])=>`${(i+e*n).toFixed(1)},${(a+t*r).toFixed(1)}`).join(` `)}" />`)}let dt=[{id:`arrow`,label:`Arrow`,icon:`M3 10h21M19 6l5 4-5 4`,parts:()=>[{pts:z([0,0],[140,0],1),line:!0}]},{id:`both`,label:`Two-way arrow`,icon:`M4 10h20M9 6l-5 4 5 4M19 6l5 4-5 4`,parts:()=>[{pts:z([0,0],[140,0],1,!0),line:!0}]},{id:`pair`,label:`Arrows both ways`,icon:`M3 7h21M20 4l4 3-4 3M25 13H4M8 10l-4 3 4 3`,parts:()=>[{pts:z([0,0],[140,0],1),line:!0},{pts:z([140,30],[0,30],1),line:!0}]}],ft=U.filter(e=>e.diagram===`flowchart`),pt=[...new Set(ft.map(e=>e.group))];lt.innerHTML=`<p class="sk-menu-head" id="sk-add-shapes" role="presentation">Steps</p><div class="sk-add-shapes" role="group" aria-labelledby="sk-add-shapes">`+Tn.map(e=>`<button type="button" role="menuitem" data-add="${e.kind}">${ut(e.kind)}<span>${e.label}</span></button>`).join(``)+`</div><p class="sk-menu-head" id="sk-add-arrows" role="presentation">Arrows</p><div class="sk-add-shapes sk-add-arrows" role="group" aria-labelledby="sk-add-arrows">`+dt.map(e=>`<button type="button" role="menuitem" data-arrow="${e.id}"><svg viewBox="0 0 28 20" aria-hidden="true"><path d="${e.icon}" /></svg><span>${e.label}</span></button>`).join(``)+`</div>`+pt.map((e,t)=>`<p class="sk-menu-head" id="sk-add-templates-${t}" role="presentation">${e}</p><div class="sk-add-templates" role="group" aria-labelledby="sk-add-templates-${t}">`+ft.filter(t=>t.group===e).map(e=>`<button type="button" role="menuitem" data-template="${e.id}"><span>${e.label}</span></button>`).join(``)+`</div>`).join(``);let ht=it(ct,lt);function _t(e){let t=b.view,n=e.flatMap(e=>e.pts),r=Math.min(...n.map(e=>e[0])),i=Math.max(...n.map(e=>e[0])),a=Math.min(...n.map(e=>e[1])),o=Math.max(...n.map(e=>e[1])),s=(r+i)/2,c=(a+o)/2,u=Math.max(.6,Math.min(1,.9*d.clientWidth/(i-r||1),.9*d.clientHeight/(o-a||1)))/t.scale,f=-t.x/t.scale+b.size.w/2,p=-t.y/t.scale+b.size.h/2,m=e.map(e=>{let n={id:b.nextId(),color:l.color,pts:e.pts.map(([e,t])=>[f+(e-s)*u,p+(t-c)*u]),by:`mouse`,zoom:t.scale};return e.name&&W[e.line?`line`:`shape`].set(n.id,e.name),n});x([...l.strokes,...m]),D(`select`),b.choose(m.map(e=>e.id))}lt.addEventListener(`click`,e=>{let t=e.target.closest(`[data-add], [data-arrow], [data-template]`);if(t){if(ht.open(!1),ct.focus(),t.dataset.arrow){let e=dt.find(e=>e.id===t.dataset.arrow);_t(e.parts()),Y(`Added: ${e.label.toLowerCase()}. Drag it between two steps; the plus adds those too.`)}else if(t.dataset.add){let e=Tn.find(e=>e.kind===t.dataset.add);_t(e.kind===`double`?[...B(`circle`,0,0,e.w,e.h),...B(`circle`,0,0,e.w*.72,e.h*.72)]:B(e.kind,0,0,e.w,e.h)),Y(`Added: ${e.label.toLowerCase()}. Drag it into place, or pick the pen to draw.`)}else{let e=ft.find(e=>e.id===t.dataset.template);_t(e.parts()),Y(`Added: ${e.label.toLowerCase()}, chosen so you can drag it into place. Press Make it a graph to read it.`)}}}),ot.addEventListener(`click`,e=>{let n=e.target.closest(`[data-act]`)?.dataset.act;n&&(st.open(!1),at.focus(),n===`example`&&X(),n===`redraw`&&Et(t.doc(),`Drawn from the graph as it is. Undo brings back the drawing it replaced.`),n===`fit`&&b.fitContent(),n===`snap`&&kt(!Ot),n===`outlines`&&Ae(!r(`show-read`).checked),n===`names`&&Le(!Fe),n===`save-drawing`&&wt(),n===`open-drawing`&&r(`open-file`).click())});function vt(){l.reading=null,l.labels={},l.made=null,xe={nodes:{},edges:{},groups:{}},We()}function yt(){l.strokes.length&&(x([]),vt(),Y(`Cleared. Undo brings the drawing back.`))}function X(){let e=Math.max(320,Math.min(b.size.w,520));vt(),x(Dt(e).map(e=>({id:b.nextId(),color:e.color??`ink`,pts:e.pts,by:`mouse`}))),b.resetView(),b.fitContent(),Se(),Y(`The example: a researcher, a builder, a critic that sends work back to it, and a stop. Press Make it a graph to make it the graph.`)}r(`hint-example`).addEventListener(`click`,X),r(`clear`).addEventListener(`click`,yt);function xt(){let e=new Date,t=e=>String(e).padStart(2,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}-${t(e.getHours())}${t(e.getMinutes())}`}function St(){l.stale&&l.strokes.length&&Se();let e={};for(let t of l.reading?.nodes??[]){let n=[...me.get(t.id)??[]].map(e=>K.get(e)).find(Boolean);n&&(e[t.id]=n)}return He(l.strokes,l.labels,Xe.value,!1,e)}function wt(){if(!l.strokes.length){Y(`There is no drawing to save yet.`);return}u(`drawing-${xt()}.json`,JSON.stringify(St()),`application/json`)}r(`open-file`).addEventListener(`change`,async e=>{let t=e.target,n=t.files?.[0];if(t.value=``,!n)return;if(n.size>5e6){Y(`That file is too large to be a drawing.`);return}let r;try{r=JSON.parse(await n.text())}catch{Y(`That file is not a drawing: it is not JSON.`);return}let i=Ue(r);if(!i.ok){Y(i.error.replace(`not a mermaidify drawing`,`not a drawing grooph or mermaidify saved`).replace(`a newer version of mermaidify`,`a newer version than this one opens`));return}Tt(i.file,i.file.strokes.map(()=>null)),Y(`Opened ${n.name}. Press Make it a graph to make it the graph.`)});function Tt(e,t){vt();let n=e.strokes.map(e=>({id:b.nextId(),color:e.color,pts:e.pts,by:e.by,...e.open?{open:e.open}:{},...e.zoom?{zoom:e.zoom}:{},...e.group?{group:e.group}:{}}));if(n.forEach((e,n)=>{let r=t[n];r&&(`node`in r?J.node.set(e.id,r.node):`edge`in r?J.edge.set(e.id,r.edge):J.group.set(e.id,r.group))}),x(n),b.fitContent(),n.length){Se();for(let[t,n]of Object.entries(e.labels))me.has(t)&&(l.labels[t]=n,G(t,n));for(let[t,n]of Object.entries(e.shapes??{})){let e=l.reading.nodes.find(e=>e.id===t);e&&(e.kind=n,e.unsure=!1,ve(t,n))}Ce(l.reading),b.setOverlay({reading:l.reading,labels:l.labels}),We(),Ie()}}function Et(e,n){let{parts:r,unboxed:i}=Te(e,t.places(e));vt(),l.unboxed=i;let a=r.map(e=>{let t={id:b.nextId(),color:`ink`,pts:e.pts,by:`mouse`};return e.name&&W[e.line?`line`:`shape`].set(t.id,e.name),`node`in e.mark?J.node.set(t.id,e.mark.node):`edge`in e.mark?J.edge.set(t.id,e.mark.edge):J.group.set(t.id,e.mark.group),t});(a.length||l.strokes.length)&&x(a),b.resetView(),b.fitContent(),l.synced=An(e),a.length&&(Se(),n&&Y(n)),et(e),Rt()}let Z=`groophSketch.snap`,Ot=!0;try{Ot=localStorage.getItem(Z)!==`off`}catch{}function kt(e){Ot=e,b.setSnap(e),ot.querySelector(`[data-act="snap"]`).setAttribute(`aria-checked`,String(e));try{e?localStorage.removeItem(Z):localStorage.setItem(Z,`off`)}catch{}}kt(Ot),Le(Fe);let Q=e.querySelector(`.sk-bar`),At=new ResizeObserver(()=>e.style.setProperty(`--sk-toolbar`,Q.offsetHeight+`px`));At.observe(Q),i.push(()=>At.disconnect());let jt=r(`full`),Mt=()=>e.classList.contains(`is-full`),Nt=[];function Pt(t){if(Mt()!==t){e.classList.toggle(`is-full`,t),document.documentElement.classList.toggle(`sk-full-page`,t),jt.setAttribute(`aria-pressed`,String(t)),jt.title=t?`Leave full screen (F or Esc)`:`Full screen (F)`;for(let e of Nt)e.inert=!1;if(Nt=[],t){let e=r(`result`).previousElementSibling;for(let t=e;t&&t!==document.body;t=t.parentElement)for(let e of t.parentElement?.children??[])e!==t&&e instanceof HTMLElement&&!e.inert&&Nt.push(e);for(let e of Nt)e.inert=!0}for(let e of rt)e.open(!1);Ye(!0),t&&!document.fullscreenElement?document.documentElement.requestFullscreen?.({navigationUI:`hide`}).catch(()=>void 0):!t&&document.fullscreenElement&&document.exitFullscreen().catch(()=>void 0)}}jt.addEventListener(`click`,()=>Pt(!Mt())),a(document,`fullscreenchange`,()=>{document.fullscreenElement?Mt()||document.exitFullscreen().catch(()=>void 0):Pt(!1)}),r(`read`).addEventListener(`click`,e=>{if(!e.target.closest(`.sk-to-result`))return;e.preventDefault();let t=()=>n||r(`result`).scrollIntoView({block:`start`,behavior:matchMedia(`(prefers-reduced-motion: reduce)`).matches?`auto`:`smooth`});if(!Mt())return t();if(!document.fullscreenElement)return Pt(!1),t();let i=!1,a=()=>{i||(i=!0,requestAnimationFrame(t))};document.addEventListener(`fullscreenchange`,a,{once:!0}),setTimeout(a,1e3),Pt(!1)}),r(`back`).addEventListener(`click`,e=>{e.preventDefault(),r(`pad-wrap`).scrollIntoView({block:`center`})});let Ft=!0,Lt=!1;function Rt(){Ft||(Lt=!0,c(`keep`,zt,500))}function zt(){if(!Lt)return;if(b.pressing&&document.visibilityState===`visible`)return c(`keep`,zt,500);if(Lt=!1,clearTimeout(s.keep),!l.strokes.length)return Nn(t.key,null);let e=l.strokes.map(e=>{let t=J.node.get(e.id),n=J.edge.get(e.id),r=J.group.get(e.id);return t===void 0?n===void 0?r===void 0?null:{group:r}:{edge:n}:{node:t}});Nn(t.key,{file:St(),marks:e,synced:l.synced,unboxed:l.unboxed})}a(window,`pagehide`,zt),a(document,`visibilitychange`,()=>{document.visibilityState===`hidden`&&zt()}),a(document,`keydown`,t=>{let n=t.target;if(!e.contains(n)&&n!==document.body)return;let r=n.closest(`input, textarea, select, [contenteditable]`),i=t.metaKey||t.ctrlKey,a=()=>{t.preventDefault(),t.stopPropagation()};if(i&&t.key===`Enter`){a(),Ee();return}if(!r&&!(t.key===`Escape`&&t.defaultPrevented)){if(t.key===`Escape`&&rt.some(e=>e.isOpen)){a();for(let e of rt)e.open(!1)}else t.key===`Escape`&&l.tool===`select`&&b.chosen.length?(a(),b.choose([])):t.key===`Escape`&&b.overlaid?(a(),b.setOverlay(null)):t.key===`Escape`&&Mt()?(a(),Pt(!1)):t.key===` `&&!i&&Bt?(a(),Vt=!0,b.setSpace(!0)):!i&&!t.altKey&&t.key.toLowerCase()===`f`?t.repeat||Pt(!Mt()):i&&t.key.toLowerCase()===`z`?(a(),t.shiftKey?w():C()):i&&t.key.toLowerCase()===`y`?(a(),w()):l.tool===`select`&&i&&([`c`,`x`,`d`].includes(t.key.toLowerCase())?b.chosen.length>0:t.key.toLowerCase()===`v`&&_)?(a(),fe({c:`copy`,x:`cut`,v:`paste`,d:`duplicate`}[t.key.toLowerCase()])):l.tool===`select`&&(t.key===`Delete`||t.key===`Backspace`)&&b.chosen.length?(a(),fe(`delete`)):!i&&!t.altKey&&t.key.toLowerCase()===`d`?D(`draw`):!i&&!t.altKey&&t.key.toLowerCase()===`e`?N(`eraser`,`whole`):!i&&!t.altKey&&(t.key.toLowerCase()===`s`||t.key.toLowerCase()===`c`)?N(`eraser`,`part`):!i&&!t.altKey&&t.key.toLowerCase()===`v`?D(`select`):!i&&!t.altKey&&t.key.toLowerCase()===`h`&&D(`hand`)}});let Bt=!1,Vt=!1;d.addEventListener(`pointermove`,()=>Bt=!0),d.addEventListener(`pointerleave`,()=>Bt=!1),a(document,`keyup`,e=>{e.key===` `&&(b.setSpace(!1),Vt&&e.preventDefault(),Vt=!1)}),a(window,`blur`,()=>{b.setSpace(!1),Vt=!1});let Ht=matchMedia(`(prefers-color-scheme: dark)`),Ut=()=>{b.repaint(),et(t.doc(),l.made&&l.made.at===t.doc()?l.made:void 0)};Ht.addEventListener(`change`,Ut),i.push(()=>Ht.removeEventListener(`change`,Ut));let Wt=new MutationObserver(Ut);Wt.observe(document.documentElement,{attributes:!0,attributeFilter:[`data-theme`]}),i.push(()=>Wt.disconnect());let Gt=null;function Kt(){if(Gt?.strokes===l.strokes)return Gt.m;let e=It(l.strokes,{diagram:`flowchart`});return Gt={strokes:l.strokes,m:e},e}function qt(e,t){let n=kn(t),r=jn(e,n);if(!r)return!1;for(let e of[J.node,J.edge,J.group])for(let[t,n]of e)r.has(n)&&e.set(t,r.get(n));l.unboxed=l.unboxed.map(e=>r.get(e)??e);let i=new Map([...n.nodes,...n.groups].map(e=>[e.id,e.name]));for(let[e,t]of J.node)i.has(t)&&W.shape.set(e,i.get(t));for(let[e,t]of J.group)i.has(t)&&W.shape.set(e,i.get(t));let a=new Map(n.edges.map(e=>[e.id,e.name]));for(let[e,t]of J.edge)a.has(t)&&(a.get(t)?W.line.set(e,a.get(t)):W.line.delete(e));return!0}let Jt=t.doc(),$=Mn(t.key);return $&&($.synced===An(Jt)||jn($.synced,kn(Jt)))?(Tt($.file,$.marks),l.unboxed=$.unboxed,$.synced!==An(Jt)&&qt($.synced,Jt)&&Se(),l.undo=[],r(`undo`).disabled=!0,et(Jt),l.reading&&Ce(l.reading)):Jt.nodes.length?($&&$.file.strokes.length&&(Tt($.file,$.marks),l.undo=[]),Et(Jt,$&&$.file.strokes.length?`The graph has changed since you last drew it, so this is the graph as it is now. Undo brings back your drawing.`:void 0),(!$||!$.file.strokes.length)&&(l.undo=[],r(`undo`).disabled=!0)):$&&$.file.strokes.length?(Tt($.file,$.marks),l.unboxed=$.unboxed,l.undo=[],r(`undo`).disabled=!0,et(Jt)):et(Jt),l.synced=An(Jt),Ft=!1,{update(e){if(l.made?.at===e)return;l.made&&(l.made=null,r(`undo-make`).hidden=!0,r(`guesses`).hidden=!0);let t=An(e);if(t===l.synced){et(e);return}if(qt(l.synced,e)){l.synced=t,l.reading&&Se(),et(e),Rt();return}l.made=null,Et(e,`The graph changed, so this is the graph as it is now. Undo brings back the drawing before it.`)},destroy(){zt(),Pt(!1),n=!0;for(let e of Object.values(s))clearTimeout(e);for(let e of i)e();e.replaceChildren(),e.classList.remove(`sk`,`is-full`)}}}var Fn=n(),In=!1;function Ln({doc:e,host:t}){let n=(0,_.useRef)(null),r=(0,_.useRef)(void 0),i=(0,_.useRef)(t);if(i.current=t,!In){let e=document.createElement(`style`);e.textContent=v,document.head.append(e),In=!0}return(0,_.useEffect)(()=>{let e=Pn(n.current,{key:t.key,doc:()=>i.current.doc(),places:e=>i.current.places(e),apply:(e,t)=>i.current.apply(e,t),open:e=>i.current.open(e),exporting:()=>i.current.exporting()});return r.current=e,()=>{e.destroy(),r.current=void 0}},[t.key]),(0,_.useEffect)(()=>r.current?.update(e),[e]),(0,Fn.jsx)(`div`,{className:`graph-sketch`,children:(0,Fn.jsx)(`div`,{ref:n})})}export{Ln as SketchView};
|