@graphty/webgpu-graph-algorithms 0.6.26 → 0.6.28
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 +56 -6
- package/dist/acquire.d.ts +2 -0
- package/dist/browser.js +18 -1
- package/dist/browser.js.map +1 -1
- package/dist/chunks/accelerator-B-FjQwaA.js +19173 -0
- package/dist/chunks/accelerator-B-FjQwaA.js.map +1 -0
- package/dist/chunks/managed-D_GdQtnu.js +98 -0
- package/dist/chunks/managed-D_GdQtnu.js.map +1 -0
- package/dist/node.js +18 -1
- package/dist/node.js.map +1 -1
- package/dist/src/accelerator.d.ts.map +1 -1
- package/dist/src/accelerator.js +5 -3
- package/dist/src/accelerator.js.map +1 -1
- package/dist/src/algorithms/all-pairs.d.ts.map +1 -1
- package/dist/src/algorithms/all-pairs.js +72 -47
- package/dist/src/algorithms/all-pairs.js.map +1 -1
- package/dist/src/algorithms/betweenness.d.ts +1 -1
- package/dist/src/algorithms/betweenness.js +2 -2
- package/dist/src/algorithms/closeness.d.ts +45 -42
- package/dist/src/algorithms/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/closeness.js +295 -226
- package/dist/src/algorithms/closeness.js.map +1 -1
- package/dist/src/browser/index.d.ts +10 -0
- package/dist/src/browser/index.d.ts.map +1 -1
- package/dist/src/browser/index.js +22 -0
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/constants.d.ts +13 -3
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +13 -3
- package/dist/src/constants.js.map +1 -1
- package/dist/src/kernels.d.ts +14 -4
- package/dist/src/kernels.d.ts.map +1 -1
- package/dist/src/kernels.js +62 -28
- package/dist/src/kernels.js.map +1 -1
- package/dist/src/layouts/force-simulation.d.ts.map +1 -1
- package/dist/src/layouts/force-simulation.js +0 -1
- package/dist/src/layouts/force-simulation.js.map +1 -1
- package/dist/src/layouts/forceatlas2.d.ts.map +1 -1
- package/dist/src/layouts/forceatlas2.js +0 -1
- package/dist/src/layouts/forceatlas2.js.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.d.ts.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.js +0 -1
- package/dist/src/layouts/fruchterman-reingold.js.map +1 -1
- package/dist/src/layouts/repulsion-grid.d.ts +1 -3
- package/dist/src/layouts/repulsion-grid.d.ts.map +1 -1
- package/dist/src/layouts/repulsion-grid.js +1 -6
- package/dist/src/layouts/repulsion-grid.js.map +1 -1
- package/dist/src/layouts/spring-electrical.d.ts.map +1 -1
- package/dist/src/layouts/spring-electrical.js +0 -1
- package/dist/src/layouts/spring-electrical.js.map +1 -1
- package/dist/src/managed.d.ts +11 -0
- package/dist/src/managed.d.ts.map +1 -0
- package/dist/src/managed.js +129 -0
- package/dist/src/managed.js.map +1 -0
- package/dist/src/node/index.d.ts +11 -0
- package/dist/src/node/index.d.ts.map +1 -1
- package/dist/src/node/index.js +21 -0
- package/dist/src/node/index.js.map +1 -1
- package/dist/src/primitives/grid-pyramid.d.ts +16 -15
- package/dist/src/primitives/grid-pyramid.d.ts.map +1 -1
- package/dist/src/primitives/grid-pyramid.js +20 -28
- package/dist/src/primitives/grid-pyramid.js.map +1 -1
- package/dist/src/types/accelerator.d.ts +2 -0
- package/dist/src/types/accelerator.d.ts.map +1 -1
- package/dist/src/types/managed.d.ts +81 -0
- package/dist/src/types/managed.d.ts.map +1 -0
- package/dist/src/types/managed.js +7 -0
- package/dist/src/types/managed.js.map +1 -0
- package/dist/src/wgsl/bc-forward.wgsl.d.ts +1 -1
- package/dist/src/wgsl/bc-forward.wgsl.js +1 -1
- package/dist/src/wgsl/closeness-level.wgsl.d.ts +37 -0
- package/dist/src/wgsl/closeness-level.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/closeness-level.wgsl.js +204 -0
- package/dist/src/wgsl/closeness-level.wgsl.js.map +1 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.d.ts +11 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.js +42 -0
- package/dist/src/wgsl/closeness-rowsum.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts +2 -2
- package/dist/src/wgsl/grid-centroid-hub.wgsl.js +2 -2
- package/dist/webgpu-graph-algorithms.js +142 -15586
- package/dist/webgpu-graph-algorithms.js.map +1 -1
- package/package.json +10 -4
- package/src/accelerator.ts +5 -3
- package/src/algorithms/all-pairs.ts +86 -56
- package/src/algorithms/betweenness.ts +2 -2
- package/src/algorithms/closeness.ts +353 -256
- package/src/browser/index.ts +37 -0
- package/src/constants.ts +13 -3
- package/src/kernels.ts +65 -36
- package/src/layouts/force-simulation.ts +0 -1
- package/src/layouts/forceatlas2.ts +0 -1
- package/src/layouts/fruchterman-reingold.ts +0 -1
- package/src/layouts/repulsion-grid.ts +2 -7
- package/src/layouts/spring-electrical.ts +0 -1
- package/src/managed.ts +172 -0
- package/src/node/index.ts +36 -0
- package/src/primitives/grid-pyramid.ts +29 -41
- package/src/types/accelerator.ts +2 -0
- package/src/types/managed.ts +86 -0
- package/src/wgsl/bc-forward.wgsl.ts +1 -1
- package/src/wgsl/closeness-level.wgsl.ts +203 -0
- package/src/wgsl/closeness-rowsum.wgsl.ts +41 -0
- package/src/wgsl/grid-centroid-hub.wgsl.ts +2 -2
- package/dist/chunks/context-BZY6SMsM.js +0 -3615
- package/dist/chunks/context-BZY6SMsM.js.map +0 -1
- package/dist/src/wgsl/closeness-reduce.wgsl.d.ts +0 -20
- package/dist/src/wgsl/closeness-reduce.wgsl.d.ts.map +0 -1
- package/dist/src/wgsl/closeness-reduce.wgsl.js +0 -69
- package/dist/src/wgsl/closeness-reduce.wgsl.js.map +0 -1
- package/dist/src/wgsl/closeness-sweep.wgsl.d.ts +0 -22
- package/dist/src/wgsl/closeness-sweep.wgsl.d.ts.map +0 -1
- package/dist/src/wgsl/closeness-sweep.wgsl.js +0 -106
- package/dist/src/wgsl/closeness-sweep.wgsl.js.map +0 -1
- package/src/wgsl/closeness-reduce.wgsl.ts +0 -68
- package/src/wgsl/closeness-sweep.wgsl.ts +0 -105
package/README.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# @graphty/webgpu-graph-algorithms
|
|
2
2
|
|
|
3
3
|
WebGPU-accelerated graph algorithms and layouts over the `@graphty/graph-format` snapshot, for Node
|
|
4
|
-
(Dawn, through the `webgpu` npm package) and browsers (Chromium). One code base,
|
|
4
|
+
(Dawn, through the `webgpu` npm package) and browsers (Chromium). One code base, four entry points:
|
|
5
5
|
|
|
6
|
-
| Entry | Import
|
|
7
|
-
| ------------------------------------------ |
|
|
8
|
-
| `@graphty/webgpu-graph-algorithms` | the core
|
|
9
|
-
| `@graphty/webgpu-graph-algorithms/node` | Node only
|
|
10
|
-
| `@graphty/webgpu-graph-algorithms/browser` | browsers only
|
|
6
|
+
| Entry | Import | What it gives you |
|
|
7
|
+
| ------------------------------------------ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
8
|
+
| `@graphty/webgpu-graph-algorithms` | the core | the layouts (`createForceAtlas2`, `createFruchtermanReingold`, `createSpringElectrical`, `seedPositions`), the algorithms (`pageRank`, `personalizedPageRank`, `hits`, `eigenvectorCentrality`, `katzCentrality`, `connectedComponents`, `degree`), `createAccelerator`, `calibrateLayout`, `verifyDevice`, `GpuContext`, `WebGpuGraphError`, `isSoftwareAdapter`, the constants (`EXACT_MAX_NODES`, `FA2_DEFAULTS`, `FR_DEFAULTS`, `SE_DEFAULTS`, `LAYOUT_TUNING_DEFAULTS`, ...) and the option / stats / accelerator types |
|
|
9
|
+
| `@graphty/webgpu-graph-algorithms/node` | Node only | `createNodeGpuContext`, `probeNodeWebGpu`, `createNodeGpu` (Dawn), `dawnFlags`, `acquireAccelerator` |
|
|
10
|
+
| `@graphty/webgpu-graph-algorithms/browser` | browsers only | `probeBrowserWebGpu`, `requestGpuContext`, `acquireAccelerator` |
|
|
11
|
+
| `@graphty/webgpu-graph-algorithms/acquire` | Node and browsers | `acquireAccelerator`: the managed accelerator. The `browser` export condition resolves it to the browser build and `node` to the Node build, so one import line serves both and the two builds never meet in one bundle |
|
|
11
12
|
|
|
12
13
|
**Status: three force layouts and six algorithms, on the exact and the grid repulsion tiers.**
|
|
13
14
|
ForceAtlas2, Fruchterman-Reingold and ngraph's spring-electrical preset run from Node (`run()`) and from a
|
|
@@ -319,6 +320,55 @@ or a non-finite `center` component is `E_INVALID_ARGUMENT`; the function returns
|
|
|
319
320
|
|
|
320
321
|
## Acquisition
|
|
321
322
|
|
|
323
|
+
### One call: `acquireAccelerator`
|
|
324
|
+
|
|
325
|
+
Most applications want "a working GPU accelerator, or the reason there is none". `acquireAccelerator` is that
|
|
326
|
+
call, the same in Node and in a browser:
|
|
327
|
+
|
|
328
|
+
```ts
|
|
329
|
+
import { accelerated } from "@graphty/algorithms";
|
|
330
|
+
import { acquireAccelerator } from "@graphty/webgpu-graph-algorithms/acquire";
|
|
331
|
+
|
|
332
|
+
const gpu = acquireAccelerator(); // nothing is probed until the first current()
|
|
333
|
+
|
|
334
|
+
const result = await gpu.current();
|
|
335
|
+
if (!result.ok) {
|
|
336
|
+
console.warn(`running on the CPU: ${result.reason}`, result.fix ?? "");
|
|
337
|
+
}
|
|
338
|
+
// the GPU when there is one, the CPU otherwise
|
|
339
|
+
const ranks = await accelerated(result.ok ? result.accelerator : null).pageRank(snapshot);
|
|
340
|
+
|
|
341
|
+
gpu.dispose(); // when you are done: releases the device
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
The first `current()` probes for an adapter, opens a context, runs the device self-check (below) and builds the
|
|
345
|
+
accelerator. Later calls return the same accelerator. After the device is lost, or after you dispose the
|
|
346
|
+
accelerator, the next `current()` acquires a new device; a run that was in flight when the device was lost still
|
|
347
|
+
fails with `E_DEVICE_LOST`, because finishing it somewhere else would hide the failure.
|
|
348
|
+
|
|
349
|
+
`result.ok === false` is a decision made before any work runs, so running a CPU implementation then is detection,
|
|
350
|
+
not a fallback. `result.code` says why:
|
|
351
|
+
|
|
352
|
+
| Code | Meaning | `result.fix` |
|
|
353
|
+
| -------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
354
|
+
| `E_NO_WEBGPU` | no WebGPU in this runtime; in Node, the optional `webgpu` package is missing | Node: the install command; a browser page that is not a secure context: serve it over https or from localhost |
|
|
355
|
+
| `E_NO_ADAPTER` | WebGPU exists but no adapter answered | null |
|
|
356
|
+
| `E_SOFTWARE_ONLY` | the adapter is a software renderer (llvmpipe, SwiftShader, WARP) | pass `acceptSoftware: true` |
|
|
357
|
+
| `E_DEVICE_INCORRECT` | the device got a known prefix sum wrong; `result.check` says where | null |
|
|
358
|
+
|
|
359
|
+
Options: `acceptSoftware` (default `false`: a software adapter is usually slower than the CPU), `powerPreference`
|
|
360
|
+
(default `"high-performance"`), `accelerator` (passed to `createAccelerator`: layout tuning, betweenness
|
|
361
|
+
defaults), `warnUnreleasedSnapshots`, and in Node `adapter` (a substring of the Dawn adapter name, such as
|
|
362
|
+
`"4070"`; ignored in a browser). A decline is remembered for the life of the handle; create a new handle to ask
|
|
363
|
+
again. Any other failure (a device request that failed) rejects `current()`, and the next call tries again.
|
|
364
|
+
|
|
365
|
+
`@graphty/webgpu-graph-algorithms/acquire` has no build of its own: the `browser` export condition (and the
|
|
366
|
+
default) resolves it to the `./browser` build, `node` to the `./node` build. The `./browser` and `./node`
|
|
367
|
+
subpaths export the same `acquireAccelerator` for code that is only ever one or the other.
|
|
368
|
+
|
|
369
|
+
The lower-level calls below are what it is made of, for when you need a context without an accelerator, your own
|
|
370
|
+
device, or control over limits and features.
|
|
371
|
+
|
|
322
372
|
### Node
|
|
323
373
|
|
|
324
374
|
```ts
|
package/dist/browser.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { G as GpuContext, W as WebGpuGraphError } from "./chunks/
|
|
1
|
+
import { G as GpuContext, W as WebGpuGraphError } from "./chunks/accelerator-B-FjQwaA.js";
|
|
2
|
+
import { m as manageAccelerator } from "./chunks/managed-D_GdQtnu.js";
|
|
2
3
|
function navigatorGpu() {
|
|
3
4
|
if (typeof navigator === "undefined") {
|
|
4
5
|
return void 0;
|
|
@@ -25,7 +26,23 @@ function requestGpuContext(options) {
|
|
|
25
26
|
}
|
|
26
27
|
return GpuContext.create({ powerPreference: "high-performance", ...options, gpu, runtime: "browser" });
|
|
27
28
|
}
|
|
29
|
+
function acquireAccelerator(options) {
|
|
30
|
+
return manageAccelerator(
|
|
31
|
+
{
|
|
32
|
+
probe: (o, rejectSoftware) => probeBrowserWebGpu({ powerPreference: o.powerPreference, rejectSoftware }),
|
|
33
|
+
open: (o, probe, rejectSoftware) => requestGpuContext({
|
|
34
|
+
adapter: probe.adapter ?? void 0,
|
|
35
|
+
powerPreference: o.powerPreference,
|
|
36
|
+
rejectSoftware,
|
|
37
|
+
warnUnreleasedSnapshots: o.warnUnreleasedSnapshots
|
|
38
|
+
}),
|
|
39
|
+
noWebGpuFix: () => globalThis.isSecureContext === false ? "serve the page over https or from localhost: WebGPU needs a secure context" : null
|
|
40
|
+
},
|
|
41
|
+
options
|
|
42
|
+
);
|
|
43
|
+
}
|
|
28
44
|
export {
|
|
45
|
+
acquireAccelerator,
|
|
29
46
|
probeBrowserWebGpu,
|
|
30
47
|
requestGpuContext
|
|
31
48
|
};
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sources":["../src/browser/index.ts"],"sourcesContent":["/// <reference types=\"@webgpu/types\" preserve=\"true\" />\n/**\n * The ./browser entry (spec 2.1, 2.3, 3.4; contract 3.6): the only directory of the package allowed to read\n * navigator.gpu. probeBrowserWebGpu never throws; requestGpuContext tags the context runtime \"browser\".\n */\n\nimport { GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport type { GpuContextOptions, ProbeResult } from \"../types/context.js\";\n\n/** Options of the browser helpers (spec 3.4); a type alias, not an empty `extends` interface, which strictTypeChecked's no-empty-object-type (allowInterfaces \"never\") reports. */\nexport type BrowserGpuOptions = Omit<GpuContextOptions, \"gpu\" | \"device\" | \"runtime\">;\n\n/**\n * navigator.gpu, or undefined when the runtime has no navigator or no WebGPU (Node 22 has a navigator\n * without gpu; browsers without WebGPU have navigator.gpu undefined).\n * @returns the GPU object or undefined\n */\nfunction navigatorGpu(): GPU | undefined {\n if (typeof navigator === \"undefined\") {\n return undefined;\n }\n const candidate: { readonly gpu?: GPU | undefined } = navigator;\n return candidate.gpu;\n}\n\n/**\n * navigator.gpu absent -> { ok: false, code: \"E_NO_WEBGPU\" }; else GpuContext.probe. Never throws.\n * @param options - the power preference and the software policy\n * @returns the probe result\n */\nexport function probeBrowserWebGpu(options?: BrowserGpuOptions): Promise<ProbeResult> {\n return GpuContext.probe({\n gpu: navigatorGpu(),\n powerPreference: options?.powerPreference ?? \"high-performance\",\n rejectSoftware: options?.rejectSoftware,\n });\n}\n\n/**\n * GpuContext.create({ gpu: navigator.gpu, powerPreference: \"high-performance\", runtime: \"browser\", ...options });\n * pass `{ adapter: probe.adapter }` to reuse the probed adapter; create() honours rejectSoftware.\n * @param options - see BrowserGpuOptions\n * @returns the context\n */\nexport function requestGpuContext(options?: BrowserGpuOptions): Promise<GpuContext> {\n const gpu = navigatorGpu();\n if (gpu === undefined && options?.adapter === undefined) {\n return Promise.reject(\n new WebGpuGraphError(\"E_NO_WEBGPU\", \"navigator.gpu is undefined: this browser or context has no WebGPU\", {\n reason: \"navigator.gpu is undefined\",\n hint: \"WebGPU needs a supporting browser and a secure context (https or localhost)\",\n }),\n );\n }\n return GpuContext.create({ powerPreference: \"high-performance\", ...options, gpu, runtime: \"browser\" });\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"browser.js","sources":["../src/browser/index.ts"],"sourcesContent":["/// <reference types=\"@webgpu/types\" preserve=\"true\" />\n/**\n * The ./browser entry (spec 2.1, 2.3, 3.4; contract 3.6): the only directory of the package allowed to read\n * navigator.gpu. probeBrowserWebGpu never throws; requestGpuContext tags the context runtime \"browser\".\n */\n\nimport { GpuContext } from \"../context.js\";\nimport { WebGpuGraphError } from \"../errors.js\";\nimport { manageAccelerator } from \"../managed.js\";\nimport type { GpuContextOptions, ProbeResult } from \"../types/context.js\";\nimport type { AcquireAcceleratorOptions, ManagedAccelerator } from \"../types/managed.js\";\n\nexport type {\n AcceleratorDeclined,\n AcceleratorReady,\n AcquireAcceleratorOptions,\n AcquireResult,\n ManagedAccelerator,\n} from \"../types/managed.js\";\n\n/** Options of the browser helpers (spec 3.4); a type alias, not an empty `extends` interface, which strictTypeChecked's no-empty-object-type (allowInterfaces \"never\") reports. */\nexport type BrowserGpuOptions = Omit<GpuContextOptions, \"gpu\" | \"device\" | \"runtime\">;\n\n/**\n * navigator.gpu, or undefined when the runtime has no navigator or no WebGPU (Node 22 has a navigator\n * without gpu; browsers without WebGPU have navigator.gpu undefined).\n * @returns the GPU object or undefined\n */\nfunction navigatorGpu(): GPU | undefined {\n if (typeof navigator === \"undefined\") {\n return undefined;\n }\n const candidate: { readonly gpu?: GPU | undefined } = navigator;\n return candidate.gpu;\n}\n\n/**\n * navigator.gpu absent -> { ok: false, code: \"E_NO_WEBGPU\" }; else GpuContext.probe. Never throws.\n * @param options - the power preference and the software policy\n * @returns the probe result\n */\nexport function probeBrowserWebGpu(options?: BrowserGpuOptions): Promise<ProbeResult> {\n return GpuContext.probe({\n gpu: navigatorGpu(),\n powerPreference: options?.powerPreference ?? \"high-performance\",\n rejectSoftware: options?.rejectSoftware,\n });\n}\n\n/**\n * GpuContext.create({ gpu: navigator.gpu, powerPreference: \"high-performance\", runtime: \"browser\", ...options });\n * pass `{ adapter: probe.adapter }` to reuse the probed adapter; create() honours rejectSoftware.\n * @param options - see BrowserGpuOptions\n * @returns the context\n */\nexport function requestGpuContext(options?: BrowserGpuOptions): Promise<GpuContext> {\n const gpu = navigatorGpu();\n if (gpu === undefined && options?.adapter === undefined) {\n return Promise.reject(\n new WebGpuGraphError(\"E_NO_WEBGPU\", \"navigator.gpu is undefined: this browser or context has no WebGPU\", {\n reason: \"navigator.gpu is undefined\",\n hint: \"WebGPU needs a supporting browser and a secure context (https or localhost)\",\n }),\n );\n }\n return GpuContext.create({ powerPreference: \"high-performance\", ...options, gpu, runtime: \"browser\" });\n}\n\n/**\n * The managed accelerator on navigator.gpu: probe, context, device self-check and accelerator on the first\n * `current()`, a new device after a loss, disposal by `dispose()`. A software adapter is declined unless\n * `acceptSoftware` is set. The same function as the `./acquire` subpath resolves to in a browser.\n * @param options - see AcquireAcceleratorOptions; `adapter` is ignored here\n * @returns the handle; nothing is probed until `current()` is called\n */\nexport function acquireAccelerator(options?: AcquireAcceleratorOptions): ManagedAccelerator {\n return manageAccelerator(\n {\n probe: (o, rejectSoftware) => probeBrowserWebGpu({ powerPreference: o.powerPreference, rejectSoftware }),\n open: (o, probe, rejectSoftware) =>\n requestGpuContext({\n adapter: probe.adapter ?? undefined,\n powerPreference: o.powerPreference,\n rejectSoftware,\n warnUnreleasedSnapshots: o.warnUnreleasedSnapshots,\n }),\n noWebGpuFix: () =>\n (globalThis as { isSecureContext?: boolean }).isSecureContext === false\n ? \"serve the page over https or from localhost: WebGPU needs a secure context\"\n : null,\n },\n options,\n );\n}\n"],"names":[],"mappings":";;AA4BA,SAAS,eAAgC;AACrC,MAAI,OAAO,cAAc,aAAa;AAClC,WAAO;AAAA,EACX;AACA,QAAM,YAAgD;AACtD,SAAO,UAAU;AACrB;AAOO,SAAS,mBAAmB,SAAmD;AAClF,SAAO,WAAW,MAAM;AAAA,IACpB,KAAK,aAAA;AAAA,IACL,iBAAiB,SAAS,mBAAmB;AAAA,IAC7C,gBAAgB,SAAS;AAAA,EAAA,CAC5B;AACL;AAQO,SAAS,kBAAkB,SAAkD;AAChF,QAAM,MAAM,aAAA;AACZ,MAAI,QAAQ,UAAa,SAAS,YAAY,QAAW;AACrD,WAAO,QAAQ;AAAA,MACX,IAAI,iBAAiB,eAAe,qEAAqE;AAAA,QACrG,QAAQ;AAAA,QACR,MAAM;AAAA,MAAA,CACT;AAAA,IAAA;AAAA,EAET;AACA,SAAO,WAAW,OAAO,EAAE,iBAAiB,oBAAoB,GAAG,SAAS,KAAK,SAAS,WAAW;AACzG;AASO,SAAS,mBAAmB,SAAyD;AACxF,SAAO;AAAA,IACH;AAAA,MACI,OAAO,CAAC,GAAG,mBAAmB,mBAAmB,EAAE,iBAAiB,EAAE,iBAAiB,gBAAgB;AAAA,MACvG,MAAM,CAAC,GAAG,OAAO,mBACb,kBAAkB;AAAA,QACd,SAAS,MAAM,WAAW;AAAA,QAC1B,iBAAiB,EAAE;AAAA,QACnB;AAAA,QACA,yBAAyB,EAAE;AAAA,MAAA,CAC9B;AAAA,MACL,aAAa,MACR,WAA6C,oBAAoB,QAC5D,+EACA;AAAA,IAAA;AAAA,IAEd;AAAA,EAAA;AAER;"}
|