esoul-sdk 0.7.0 → 0.16.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.
Files changed (67) hide show
  1. package/README.md +575 -153
  2. package/api-reference.md +3291 -0
  3. package/dist/assets.d.ts +72 -0
  4. package/dist/assets.js +139 -0
  5. package/dist/audience.d.ts +2 -0
  6. package/dist/audience.js +2 -0
  7. package/dist/bindings.d.ts +3 -0
  8. package/dist/bindings.js +3 -0
  9. package/dist/chart-font.d.ts +19 -0
  10. package/dist/chart-font.js +15 -0
  11. package/dist/chart.d.ts +83 -0
  12. package/dist/chart.js +247 -0
  13. package/dist/computer.d.ts +191 -0
  14. package/dist/computer.js +226 -0
  15. package/dist/db/client-core.d.ts +38 -0
  16. package/dist/db/client-core.js +68 -1
  17. package/dist/db/compile-rules.d.ts +60 -2
  18. package/dist/db/compile-rules.js +178 -30
  19. package/dist/db/custom-roles.d.ts +156 -0
  20. package/dist/db/custom-roles.js +280 -0
  21. package/dist/db/memory-client.d.ts +0 -15
  22. package/dist/db/memory-client.js +13 -23
  23. package/dist/db/schema-gen.js +2 -8
  24. package/dist/editor-sync.d.ts +130 -0
  25. package/dist/editor-sync.js +413 -0
  26. package/dist/files.d.ts +70 -0
  27. package/dist/files.js +48 -0
  28. package/dist/helpers.d.ts +10 -0
  29. package/dist/helpers.js +10 -0
  30. package/dist/index.d.ts +24 -0
  31. package/dist/index.js +25 -0
  32. package/dist/labelme.d.ts +84 -0
  33. package/dist/labelme.js +118 -0
  34. package/dist/manifest.d.ts +400 -106
  35. package/dist/manifest.js +59 -5
  36. package/dist/ops.d.ts +115 -0
  37. package/dist/ops.js +120 -0
  38. package/dist/react.d.ts +280 -4
  39. package/dist/react.js +100 -3
  40. package/dist/server.d.ts +268 -10
  41. package/dist/server.js +120 -4
  42. package/dist/testing/db.d.ts +6 -0
  43. package/dist/testing/db.js +3 -8
  44. package/dist/testing/files.d.ts +22 -0
  45. package/dist/testing/files.js +175 -0
  46. package/dist/testing/index.d.ts +2 -0
  47. package/dist/testing/index.js +1 -0
  48. package/dist/types.d.ts +47 -0
  49. package/docs/02-manifest.md +2 -0
  50. package/docs/03-events-and-state.md +8 -0
  51. package/docs/04-tools.md +58 -26
  52. package/docs/05-ui.md +35 -0
  53. package/docs/06-server.md +121 -7
  54. package/docs/07-background-tasks.md +7 -9
  55. package/docs/09-files.md +126 -17
  56. package/docs/10-testing.md +6 -0
  57. package/docs/11-shipping.md +10 -2
  58. package/docs/13-people-and-access.md +180 -0
  59. package/docs/14-database.md +6 -0
  60. package/docs/15-realtime.md +3 -0
  61. package/docs/17-editing-and-merging.md +155 -0
  62. package/llms-full.txt +1296 -214
  63. package/llms.txt +3 -3
  64. package/package.json +9 -4
  65. package/schemas/plugin.schema.json +134 -15
  66. package/scripts/build-api-reference.mjs +104 -0
  67. package/scripts/build-llms.mjs +1 -2
@@ -0,0 +1,72 @@
1
+ /**
2
+ * APP ASSETS — images, films, fonts an app ships with (forge-assets-and-mcp-parity.md).
3
+ *
4
+ * The bytes never live in the app's package: they are content-addressed objects the platform
5
+ * holds, and the package carries `assets.json`, written by the platform when an asset is put
6
+ * (`put_app_asset` on the board, `forge_put_asset` over MCP, `Workbench.put_asset` in the SDK).
7
+ * An app resolves a name to its URL with `assetUrl(assets, "hero.mp4")` — the same URL in the
8
+ * workbench preview, on production and on a custom domain, so no app ever branches on where it
9
+ * runs. The address IS the version: re-put the same bytes and nothing changes; put new bytes
10
+ * and every reader sees them at once (the old address stays valid — nothing is ever deleted).
11
+ *
12
+ * import assets from "./assets.json";
13
+ * <video src={assetUrl(assets, "hero.mp4")} poster={assetUrl(assets, "hero.jpg")} />
14
+ *
15
+ * Pure — vendored byte-for-byte on both sides of the import wall.
16
+ */
17
+ export interface AssetEntry {
18
+ /** sha256 of the bytes, hex — computed by the platform, never declared by a client. */
19
+ sha256: string;
20
+ bytes: number;
21
+ /** The media type the object is served with. */
22
+ type: string;
23
+ /** When it was put (ms). Informational. */
24
+ at?: number;
25
+ }
26
+ export interface AssetsManifest {
27
+ pluginId: string;
28
+ files: Record<string, AssetEntry>;
29
+ }
30
+ /** What may be served as an asset — media and fonts, never scripts, never HTML. */
31
+ export declare const ASSET_TYPES: Readonly<Record<string, string>>;
32
+ /** A single asset may be a film; an app may be a small site's worth of them. Owner-billed storage. */
33
+ export declare const ASSET_MAX_BYTES: number;
34
+ /** The most one app's assets may add up to (summed from its manifest). */
35
+ export declare const ASSET_APP_MAX_BYTES: number;
36
+ /** Inline base64 in a tool argument stays small: a model cannot emit more reliably. */
37
+ export declare const ASSET_INLINE_MAX_BYTES: number;
38
+ /** A plugin id as the serving route accepts it: lower-case, digits, dashes. */
39
+ export declare const PLUGIN_ID_RE: RegExp;
40
+ /** The extension of an asset name, lower-case, or null when the name is not an asset name. */
41
+ export declare function assetExt(name: string): string | null;
42
+ /** The object an asset is stored and served as: `<sha256>.<ext>`. */
43
+ export declare function assetObject(sha256: string, ext: string): string;
44
+ /** `<sha256>.<ext>` → its parts, or null for anything else (the serving route's only door). */
45
+ export declare function parseAssetObject(object: string): {
46
+ sha256: string;
47
+ ext: string;
48
+ type: string;
49
+ } | null;
50
+ /** The public, immutable, same-origin address of an object. */
51
+ export declare function assetPath(pluginId: string, sha256: string, ext: string): string;
52
+ /** Why a name has no asset, in words an author can act on. */
53
+ export declare function missingAssetMessage(assets: AssetsManifest | null | undefined, name: string): string;
54
+ /**
55
+ * The URL an app renders for one of its assets. NEVER throws (2026-09-24): an unknown name used to
56
+ * throw "a missing asset is a bug", and the homepage went down whole when a visitor opened an app
57
+ * whose film had not been recorded yet — a render-time throw takes the page with it. Now an unknown
58
+ * name logs once (the author sees it in the console and the Forge's journal) and returns an address
59
+ * that answers 404, so an `<img>` is simply empty and its `onError` fires. For an asset that may
60
+ * legitimately be absent, use `assetUrlOrNull` and render a fallback.
61
+ */
62
+ export declare function assetUrl(assets: AssetsManifest, name: string): string;
63
+ /** Like `assetUrl` for an OPTIONAL asset: null instead of a throw. */
64
+ export declare function assetUrlOrNull(assets: AssetsManifest, name: string): string | null;
65
+ /** The bytes an app's assets add up to — what the per-app cap is measured against. */
66
+ export declare function assetsTotalBytes(assets: AssetsManifest | null | undefined): number;
67
+ /** A manifest with one entry added or replaced. Pure. */
68
+ export declare function withAsset(assets: AssetsManifest | null | undefined, pluginId: string, name: string, entry: AssetEntry): AssetsManifest;
69
+ /** A manifest with one entry removed (the bytes stay; they may be shared). Pure. */
70
+ export declare function withoutAsset(assets: AssetsManifest | null | undefined, pluginId: string, name: string): AssetsManifest;
71
+ /** Parse `assets.json` text leniently: a missing or broken file is an empty manifest. */
72
+ export declare function parseAssetsManifest(text: string | null | undefined, pluginId: string): AssetsManifest;
package/dist/assets.js ADDED
@@ -0,0 +1,139 @@
1
+ /**
2
+ * APP ASSETS — images, films, fonts an app ships with (forge-assets-and-mcp-parity.md).
3
+ *
4
+ * The bytes never live in the app's package: they are content-addressed objects the platform
5
+ * holds, and the package carries `assets.json`, written by the platform when an asset is put
6
+ * (`put_app_asset` on the board, `forge_put_asset` over MCP, `Workbench.put_asset` in the SDK).
7
+ * An app resolves a name to its URL with `assetUrl(assets, "hero.mp4")` — the same URL in the
8
+ * workbench preview, on production and on a custom domain, so no app ever branches on where it
9
+ * runs. The address IS the version: re-put the same bytes and nothing changes; put new bytes
10
+ * and every reader sees them at once (the old address stays valid — nothing is ever deleted).
11
+ *
12
+ * import assets from "./assets.json";
13
+ * <video src={assetUrl(assets, "hero.mp4")} poster={assetUrl(assets, "hero.jpg")} />
14
+ *
15
+ * Pure — vendored byte-for-byte on both sides of the import wall.
16
+ */
17
+ /** What may be served as an asset — media and fonts, never scripts, never HTML. */
18
+ export const ASSET_TYPES = {
19
+ webp: "image/webp",
20
+ png: "image/png",
21
+ jpg: "image/jpeg",
22
+ jpeg: "image/jpeg",
23
+ gif: "image/gif",
24
+ avif: "image/avif",
25
+ svg: "image/svg+xml",
26
+ mp4: "video/mp4",
27
+ webm: "video/webm",
28
+ mp3: "audio/mpeg",
29
+ m4a: "audio/mp4",
30
+ woff2: "font/woff2",
31
+ woff: "font/woff",
32
+ pdf: "application/pdf",
33
+ json: "application/json",
34
+ };
35
+ /** A single asset may be a film; an app may be a small site's worth of them. Owner-billed storage. */
36
+ export const ASSET_MAX_BYTES = 64 * 1024 * 1024;
37
+ /** The most one app's assets may add up to (summed from its manifest). */
38
+ export const ASSET_APP_MAX_BYTES = 256 * 1024 * 1024;
39
+ /** Inline base64 in a tool argument stays small: a model cannot emit more reliably. */
40
+ export const ASSET_INLINE_MAX_BYTES = 3 * 1024 * 1024;
41
+ /** A plugin id as the serving route accepts it: lower-case, digits, dashes. */
42
+ export const PLUGIN_ID_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
43
+ const OBJECT_RE = /^([a-f0-9]{64})\.([a-z0-9]{1,8})$/;
44
+ const NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$/;
45
+ /** The extension of an asset name, lower-case, or null when the name is not an asset name. */
46
+ export function assetExt(name) {
47
+ if (!NAME_RE.test(name))
48
+ return null;
49
+ const i = name.lastIndexOf(".");
50
+ if (i <= 0)
51
+ return null;
52
+ const ext = name.slice(i + 1).toLowerCase();
53
+ return ext in ASSET_TYPES ? ext : null;
54
+ }
55
+ /** The object an asset is stored and served as: `<sha256>.<ext>`. */
56
+ export function assetObject(sha256, ext) {
57
+ return `${sha256}.${ext}`;
58
+ }
59
+ /** `<sha256>.<ext>` → its parts, or null for anything else (the serving route's only door). */
60
+ export function parseAssetObject(object) {
61
+ const m = OBJECT_RE.exec(object);
62
+ if (!m)
63
+ return null;
64
+ const type = ASSET_TYPES[m[2]];
65
+ return type ? { sha256: m[1], ext: m[2], type } : null;
66
+ }
67
+ /** The public, immutable, same-origin address of an object. */
68
+ export function assetPath(pluginId, sha256, ext) {
69
+ return `/pa/${pluginId}/${assetObject(sha256, ext)}`;
70
+ }
71
+ /** Why a name has no asset, in words an author can act on. */
72
+ export function missingAssetMessage(assets, name) {
73
+ const known = Object.keys(assets?.files ?? {});
74
+ return `asset "${name}" is not in assets.json${known.length ? ` (known: ${known.slice(0, 12).join(", ")}${known.length > 12 ? ", …" : ""})` : " (no assets have been put yet — put_app_asset / forge_put_asset)"}`;
75
+ }
76
+ const warned = new Set();
77
+ /**
78
+ * The URL an app renders for one of its assets. NEVER throws (2026-09-24): an unknown name used to
79
+ * throw "a missing asset is a bug", and the homepage went down whole when a visitor opened an app
80
+ * whose film had not been recorded yet — a render-time throw takes the page with it. Now an unknown
81
+ * name logs once (the author sees it in the console and the Forge's journal) and returns an address
82
+ * that answers 404, so an `<img>` is simply empty and its `onError` fires. For an asset that may
83
+ * legitimately be absent, use `assetUrlOrNull` and render a fallback.
84
+ */
85
+ export function assetUrl(assets, name) {
86
+ const e = assets?.files?.[name];
87
+ if (!e) {
88
+ const key = `${assets?.pluginId}:${name}`;
89
+ if (!warned.has(key)) {
90
+ warned.add(key);
91
+ try {
92
+ console.error(`[esoul-sdk] ${missingAssetMessage(assets, name)}`);
93
+ }
94
+ catch { /* no console */ }
95
+ }
96
+ return `/pa/${assets?.pluginId || "unknown"}/missing`;
97
+ }
98
+ const ext = assetExt(name) ?? "bin";
99
+ return assetPath(assets.pluginId, e.sha256, ext);
100
+ }
101
+ /** Like `assetUrl` for an OPTIONAL asset: null instead of a throw. */
102
+ export function assetUrlOrNull(assets, name) {
103
+ return assets?.files?.[name] ? assetUrl(assets, name) : null;
104
+ }
105
+ /** The bytes an app's assets add up to — what the per-app cap is measured against. */
106
+ export function assetsTotalBytes(assets) {
107
+ return Object.values(assets?.files ?? {}).reduce((n, e) => n + (e?.bytes ?? 0), 0);
108
+ }
109
+ /** A manifest with one entry added or replaced. Pure. */
110
+ export function withAsset(assets, pluginId, name, entry) {
111
+ const files = { ...(assets?.files ?? {}) };
112
+ files[name] = entry;
113
+ // Code-point order, not locale order: the manifest must serialise identically on every machine.
114
+ return { pluginId, files: Object.fromEntries(Object.entries(files).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) };
115
+ }
116
+ /** A manifest with one entry removed (the bytes stay; they may be shared). Pure. */
117
+ export function withoutAsset(assets, pluginId, name) {
118
+ const files = { ...(assets?.files ?? {}) };
119
+ delete files[name];
120
+ return { pluginId, files };
121
+ }
122
+ /** Parse `assets.json` text leniently: a missing or broken file is an empty manifest. */
123
+ export function parseAssetsManifest(text, pluginId) {
124
+ if (!text)
125
+ return { pluginId, files: {} };
126
+ try {
127
+ const j = JSON.parse(text);
128
+ const files = {};
129
+ for (const [name, e] of Object.entries(j?.files ?? {})) {
130
+ if (e && typeof e === "object" && typeof e.sha256 === "string" && /^[a-f0-9]{64}$/.test(e.sha256)) {
131
+ files[name] = { sha256: e.sha256, bytes: Number(e.bytes) || 0, type: String(e.type ?? ""), ...(typeof e.at === "number" ? { at: e.at } : {}) };
132
+ }
133
+ }
134
+ return { pluginId: typeof j?.pluginId === "string" && j.pluginId ? j.pluginId : pluginId, files };
135
+ }
136
+ catch {
137
+ return { pluginId, files: {} };
138
+ }
139
+ }
@@ -52,6 +52,7 @@ export type NotifyTarget = {
52
52
  } | {
53
53
  role: string;
54
54
  } | "apps";
55
+ /** A publish aimed at viewers the topic's audience does not allow — refused with code `forbidden`. */
55
56
  export declare class AudienceError extends Error {
56
57
  readonly code: "forbidden";
57
58
  constructor(message: string);
@@ -63,6 +64,7 @@ export interface AudienceViewer {
63
64
  viewerIds: string[];
64
65
  role: string;
65
66
  }
67
+ /** The audience a realtime topic declares — `"viewer"`, `"role:<name>"`, or `"all"` when it declares none. */
66
68
  export declare function audienceOf(decl: TopicDecl | undefined): TopicAudience;
67
69
  /**
68
70
  * The id a person's own channel is keyed on. A signed-in account first, so
package/dist/audience.js CHANGED
@@ -26,6 +26,7 @@
26
26
  * server's `notify` calls `decideDestination`, and the workbench calls both,
27
27
  * so a box shows an author exactly what an installed app will do.
28
28
  */
29
+ /** A publish aimed at viewers the topic's audience does not allow — refused with code `forbidden`. */
29
30
  export class AudienceError extends Error {
30
31
  code = "forbidden";
31
32
  constructor(message) {
@@ -33,6 +34,7 @@ export class AudienceError extends Error {
33
34
  this.name = "AudienceError";
34
35
  }
35
36
  }
37
+ /** The audience a realtime topic declares — `"viewer"`, `"role:<name>"`, or `"all"` when it declares none. */
36
38
  export function audienceOf(decl) {
37
39
  const a = decl?.audience;
38
40
  if (a === "viewer")
@@ -67,7 +67,9 @@ export interface ProviderFacts {
67
67
  /** The `provides` block from its manifest. */
68
68
  provides: Record<string, ProvidesDecl>;
69
69
  }
70
+ /** `"stock/v1"` → `{name: "stock", version: 1}`; anything else → null. */
70
71
  export declare function parseContractId(raw: string): ContractId | null;
72
+ /** `{name: "stock", version: 1}` → `"stock/v1"`. */
71
73
  export declare function formatContractId(c: ContractId): string;
72
74
  export type BindCheck = {
73
75
  ok: true;
@@ -133,6 +135,7 @@ export declare function unfilledRequiredSlots(uses: Record<string, UsesDecl>, bi
133
135
  export interface BindingHolder {
134
136
  _bindings?: BindingMap;
135
137
  }
138
+ /** The event a consumer app records a binding on (`<applicationType>_binding_set`) — put it in your `events` when you declare `uses`. */
136
139
  export declare function bindingEventName(applicationType: string): string;
137
140
  /**
138
141
  * The event definition for one app's slots. `knownSlots` comes from the
package/dist/bindings.js CHANGED
@@ -27,6 +27,7 @@
27
27
  * Pure: no platform, no transport. The bind-time check, the workbench picker
28
28
  * and the author's own tests all read this.
29
29
  */
30
+ /** `"stock/v1"` → `{name: "stock", version: 1}`; anything else → null. */
30
31
  export function parseContractId(raw) {
31
32
  const m = /^([a-z][a-z0-9-]*)\/v(\d+)$/.exec(raw ?? "");
32
33
  if (!m)
@@ -34,6 +35,7 @@ export function parseContractId(raw) {
34
35
  const version = Number(m[2]);
35
36
  return Number.isSafeInteger(version) && version > 0 ? { name: m[1], version } : null;
36
37
  }
38
+ /** `{name: "stock", version: 1}` → `"stock/v1"`. */
37
39
  export function formatContractId(c) {
38
40
  return `${c.name}/v${c.version}`;
39
41
  }
@@ -113,6 +115,7 @@ export function reduceBinding(current, event, knownSlots) {
113
115
  export function unfilledRequiredSlots(uses, bindings) {
114
116
  return Object.keys(uses ?? {}).filter((slot) => !uses[slot].optional && !bindings[slot]);
115
117
  }
118
+ /** The event a consumer app records a binding on (`<applicationType>_binding_set`) — put it in your `events` when you declare `uses`. */
116
119
  export function bindingEventName(applicationType) {
117
120
  return `${applicationType}_binding_set`;
118
121
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * GLYPHS AS PATHS, so a chart's words render the same everywhere.
3
+ *
4
+ * A chart rasterised on a serverless function (`sharp`/librsvg) has no fonts
5
+ * installed: `<text>` comes out as nothing, or as boxes. The platform's LaTeX
6
+ * renderer met the same wall and ships its glyphs as `<path>` data; this does
7
+ * the same for plain text. Outlines are DejaVu Sans (Bitstream Vera licence,
8
+ * with DejaVu changes in the public domain — free to embed and modify), in
9
+ * thousandths of an em with the baseline at y = 0. Generated once; do not edit
10
+ * by hand. Printable ASCII, Czech and German letters, and the few symbols a
11
+ * measurement needs (° − × → … ± µ ² ³).
12
+ */
13
+ export declare const GLYPH_METRICS: {
14
+ readonly ascent: 760;
15
+ readonly descent: 240;
16
+ readonly capHeight: 729;
17
+ };
18
+ /** char → [advance, path] */
19
+ export declare const GLYPHS: Record<string, [number, string]>;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * GLYPHS AS PATHS, so a chart's words render the same everywhere.
3
+ *
4
+ * A chart rasterised on a serverless function (`sharp`/librsvg) has no fonts
5
+ * installed: `<text>` comes out as nothing, or as boxes. The platform's LaTeX
6
+ * renderer met the same wall and ships its glyphs as `<path>` data; this does
7
+ * the same for plain text. Outlines are DejaVu Sans (Bitstream Vera licence,
8
+ * with DejaVu changes in the public domain — free to embed and modify), in
9
+ * thousandths of an em with the baseline at y = 0. Generated once; do not edit
10
+ * by hand. Printable ASCII, Czech and German letters, and the few symbols a
11
+ * measurement needs (° − × → … ± µ ² ³).
12
+ */
13
+ export const GLYPH_METRICS = { "ascent": 760, "descent": 240, "capHeight": 729 };
14
+ /** char → [advance, path] */
15
+ export const GLYPHS = { " ": [318, ""], "!": [401, "M151 -124H250V0H151ZM151 -729H250V-409L240 -235H161L151 -409Z"], "\"": [460, "M179 -729V-458H96V-729ZM364 -729V-458H281V-729Z"], "#": [838, "M511 -440H369L328 -277H471ZM438 -718 387 -515H530L581 -718H659L609 -515H761V-440H590L550 -277H705V-202H531L480 0H402L452 -202H309L259 0H180L231 -202H77V-277H249L290 -440H133V-515H309L359 -718Z"], "$": [636, "M338 147H289L289 0Q237 -1 186 -12Q135 -23 83 -45V-133Q133 -102 184 -86Q235 -70 289 -69V-292Q181 -310 132 -352Q83 -394 83 -467Q83 -546 136 -592Q189 -638 289 -645V-760H338V-646Q383 -645 426 -637Q468 -629 509 -616V-531Q468 -551 426 -562Q383 -574 338 -576V-367Q449 -350 501 -306Q553 -262 553 -186Q553 -104 498 -56Q442 -8 338 -1ZM289 -376V-576Q232 -570 203 -544Q173 -518 173 -475Q173 -433 200 -410Q228 -386 289 -376ZM338 -282V-71Q400 -79 431 -106Q463 -133 463 -177Q463 -220 433 -245Q403 -271 338 -282Z"], "%": [950, "M727 -321Q685 -321 660 -285Q636 -249 636 -184Q636 -121 660 -84Q685 -48 727 -48Q769 -48 793 -84Q817 -121 817 -184Q817 -248 793 -284Q769 -321 727 -321ZM727 -383Q804 -383 850 -329Q895 -275 895 -184Q895 -93 849 -39Q804 14 727 14Q649 14 604 -39Q558 -93 558 -184Q558 -276 604 -329Q649 -383 727 -383ZM223 -680Q181 -680 157 -644Q133 -607 133 -544Q133 -479 157 -443Q181 -407 223 -407Q266 -407 290 -443Q314 -479 314 -544Q314 -607 290 -644Q265 -680 223 -680ZM664 -742H742L286 14H208ZM223 -742Q300 -742 346 -689Q392 -635 392 -544Q392 -452 346 -398Q301 -345 223 -345Q146 -345 100 -399Q55 -452 55 -544Q55 -635 101 -688Q146 -742 223 -742Z"], "&": [780, "M243 -392Q199 -353 178 -313Q157 -274 157 -231Q157 -160 209 -112Q261 -65 339 -65Q385 -65 426 -80Q466 -96 502 -127ZM312 -447 560 -193Q589 -236 605 -286Q621 -335 624 -391H715Q709 -327 684 -264Q658 -201 613 -139L749 0H626L556 -72Q505 -28 450 -7Q394 14 330 14Q212 14 138 -53Q63 -120 63 -225Q63 -288 96 -343Q128 -397 194 -446Q170 -477 158 -507Q146 -538 146 -567Q146 -646 200 -694Q254 -742 344 -742Q385 -742 425 -733Q465 -725 507 -707V-618Q464 -641 426 -653Q387 -665 354 -665Q303 -665 271 -638Q239 -611 239 -568Q239 -543 253 -518Q268 -493 312 -447Z"], "'": [275, "M179 -729V-458H96V-729Z"], "(": [390, "M310 -759Q245 -646 213 -537Q181 -427 181 -314Q181 -201 213 -91Q245 20 310 132H232Q159 17 122 -94Q86 -205 86 -314Q86 -423 122 -533Q158 -644 232 -759Z"], ")": [390, "M80 -759H158Q231 -644 268 -533Q304 -423 304 -314Q304 -205 268 -94Q231 17 158 132H80Q145 20 177 -91Q209 -201 209 -314Q209 -427 177 -537Q145 -646 80 -759Z"], "*": [500, "M470 -609 295 -514 470 -419 442 -371 278 -470V-286H222V-470L58 -371L30 -419L205 -514L30 -609L58 -657L222 -558V-742H278V-558L442 -657Z"], "+": [838, "M460 -627V-355H732V-272H460V0H378V-272H106V-355H378V-627Z"], ",": [318, "M117 -124H220V-40L140 116H77L117 -40Z"], "-": [361, "M49 -314H312V-234H49Z"], ".": [318, "M107 -124H210V0H107Z"], "/": [337, "M254 -729H337L83 93H0Z"], "0": [636, "M318 -664Q242 -664 203 -589Q165 -514 165 -364Q165 -214 203 -139Q242 -64 318 -64Q395 -64 433 -139Q471 -214 471 -364Q471 -514 433 -589Q395 -664 318 -664ZM318 -742Q440 -742 505 -645Q570 -548 570 -364Q570 -180 505 -83Q440 14 318 14Q195 14 131 -83Q66 -180 66 -364Q66 -548 131 -645Q195 -742 318 -742Z"], "1": [636, "M124 -83H285V-639L110 -604V-694L284 -729H383V-83H544V0H124Z"], "2": [636, "M192 -83H536V0H73V-83Q129 -141 226 -239Q323 -337 348 -365Q396 -418 414 -455Q433 -492 433 -528Q433 -586 392 -623Q352 -659 286 -659Q240 -659 188 -643Q137 -627 78 -594V-694Q138 -718 189 -730Q241 -742 284 -742Q397 -742 465 -686Q532 -629 532 -534Q532 -489 515 -449Q499 -409 454 -354Q442 -340 376 -272Q311 -205 192 -83Z"], "3": [636, "M406 -393Q477 -378 516 -330Q556 -282 556 -212Q556 -104 482 -45Q408 14 271 14Q225 14 177 5Q128 -4 76 -22V-117Q117 -93 166 -81Q215 -69 268 -69Q361 -69 409 -105Q458 -142 458 -212Q458 -276 413 -313Q368 -349 287 -349H202V-430H291Q364 -430 402 -459Q441 -488 441 -543Q441 -599 401 -629Q361 -659 287 -659Q247 -659 200 -650Q154 -642 98 -623V-711Q154 -727 203 -734Q252 -742 296 -742Q408 -742 474 -691Q539 -640 539 -553Q539 -493 504 -451Q470 -409 406 -393Z"], "4": [636, "M378 -643 129 -254H378ZM352 -729H476V-254H580V-172H476V0H378V-172H49V-267Z"], "5": [636, "M108 -729H495V-646H198V-467Q220 -475 241 -478Q263 -482 284 -482Q406 -482 478 -415Q549 -348 549 -234Q549 -116 476 -51Q402 14 269 14Q223 14 176 6Q128 -1 77 -17V-116Q121 -92 168 -81Q215 -69 267 -69Q352 -69 401 -113Q450 -158 450 -234Q450 -310 401 -354Q352 -399 267 -399Q228 -399 188 -390Q149 -381 108 -363Z"], "6": [636, "M330 -404Q264 -404 225 -358Q186 -313 186 -234Q186 -155 225 -110Q264 -64 330 -64Q396 -64 435 -110Q474 -155 474 -234Q474 -313 435 -358Q396 -404 330 -404ZM526 -713V-623Q489 -641 451 -650Q413 -659 376 -659Q278 -659 227 -593Q175 -527 168 -394Q197 -437 240 -459Q284 -482 336 -482Q446 -482 510 -415Q573 -349 573 -234Q573 -122 507 -54Q440 14 330 14Q204 14 137 -83Q70 -180 70 -364Q70 -537 152 -639Q234 -742 372 -742Q409 -742 447 -735Q485 -728 526 -713Z"], "7": [636, "M82 -729H551V-687L286 0H183L432 -646H82Z"], "8": [636, "M318 -346Q248 -346 207 -309Q167 -271 167 -205Q167 -139 207 -102Q248 -64 318 -64Q388 -64 429 -102Q469 -140 469 -205Q469 -271 429 -309Q389 -346 318 -346ZM219 -388Q156 -404 120 -447Q85 -491 85 -553Q85 -641 147 -691Q209 -742 318 -742Q427 -742 489 -691Q551 -641 551 -553Q551 -491 515 -447Q480 -404 417 -388Q488 -372 528 -323Q568 -275 568 -205Q568 -99 503 -42Q438 14 318 14Q197 14 133 -42Q68 -99 68 -205Q68 -275 108 -323Q148 -372 219 -388ZM183 -544Q183 -487 219 -456Q254 -424 318 -424Q381 -424 417 -456Q453 -487 453 -544Q453 -601 417 -632Q381 -664 318 -664Q254 -664 219 -632Q183 -601 183 -544Z"], "9": [636, "M110 -15V-105Q147 -87 185 -78Q223 -69 260 -69Q357 -69 409 -135Q460 -200 468 -334Q439 -292 396 -270Q353 -247 300 -247Q190 -247 127 -313Q63 -379 63 -494Q63 -606 129 -674Q196 -742 306 -742Q433 -742 499 -645Q566 -548 566 -364Q566 -191 484 -89Q402 14 264 14Q227 14 189 7Q151 0 110 -15ZM306 -324Q373 -324 411 -370Q450 -415 450 -494Q450 -573 411 -618Q373 -664 306 -664Q240 -664 201 -618Q162 -573 162 -494Q162 -415 201 -370Q240 -324 306 -324Z"], ":": [337, "M117 -124H220V0H117ZM117 -517H220V-393H117Z"], ";": [337, "M117 -517H220V-393H117ZM117 -124H220V-40L140 116H77L117 -40Z"], "<": [838, "M732 -492 228 -313 732 -135V-46L106 -273V-354L732 -581Z"], "=": [838, "M106 -454H732V-372H106ZM106 -255H732V-172H106Z"], ">": [838, "M106 -492V-581L732 -354V-273L106 -46V-135L609 -313Z"], "?": [531, "M191 -124H290V0H191ZM287 -196H194V-271Q194 -320 208 -352Q221 -384 265 -426L309 -469Q337 -495 349 -518Q362 -541 362 -565Q362 -608 330 -635Q298 -662 245 -662Q207 -662 163 -645Q119 -628 72 -595V-687Q118 -715 165 -729Q212 -742 262 -742Q352 -742 406 -695Q461 -647 461 -570Q461 -533 443 -499Q426 -466 382 -424L339 -382Q316 -359 306 -346Q297 -333 293 -321Q290 -311 289 -296Q287 -281 287 -256Z"], "@": [1000, "M372 -262Q372 -192 407 -153Q441 -113 502 -113Q562 -113 596 -153Q631 -193 631 -262Q631 -331 596 -371Q561 -411 501 -411Q442 -411 407 -371Q372 -331 372 -262ZM638 -116Q609 -79 571 -61Q533 -43 483 -43Q399 -43 346 -104Q294 -165 294 -262Q294 -360 347 -421Q399 -482 483 -482Q533 -482 571 -464Q609 -445 638 -408V-472H708V-113Q779 -124 820 -178Q860 -232 860 -319Q860 -371 844 -417Q829 -463 798 -502Q747 -566 674 -600Q601 -634 515 -634Q455 -634 400 -618Q345 -602 298 -571Q221 -521 178 -440Q135 -359 135 -265Q135 -188 163 -120Q191 -52 244 0Q295 51 363 77Q430 104 507 104Q570 104 631 83Q691 62 742 22L786 76Q725 124 653 149Q581 174 507 174Q417 174 336 142Q256 110 194 49Q131 -12 99 -93Q66 -173 66 -265Q66 -354 99 -435Q132 -515 194 -576Q257 -638 339 -671Q422 -704 514 -704Q618 -704 706 -662Q795 -619 855 -541Q892 -493 911 -437Q930 -381 930 -321Q930 -192 853 -118Q775 -44 638 -41Z"], "A": [684, "M342 -632 208 -269H476ZM286 -729H398L676 0H573L507 -187H178L112 0H8Z"], "B": [686, "M197 -348V-81H355Q435 -81 473 -114Q511 -147 511 -215Q511 -283 473 -316Q435 -348 355 -348ZM197 -648V-428H343Q415 -428 450 -455Q486 -482 486 -538Q486 -593 450 -621Q415 -648 343 -648ZM98 -729H350Q463 -729 524 -682Q585 -635 585 -549Q585 -482 554 -442Q522 -403 462 -393Q535 -377 575 -328Q615 -278 615 -204Q615 -106 549 -53Q482 0 360 0H98Z"], "C": [698, "M644 -673V-569Q594 -615 538 -638Q481 -661 418 -661Q293 -661 227 -585Q160 -508 160 -364Q160 -220 227 -143Q293 -67 418 -67Q481 -67 538 -90Q594 -113 644 -159V-56Q592 -21 534 -3Q477 14 412 14Q247 14 151 -87Q56 -188 56 -364Q56 -540 151 -641Q247 -742 412 -742Q478 -742 535 -725Q593 -708 644 -673Z"], "D": [770, "M197 -648V-81H316Q467 -81 537 -149Q607 -218 607 -365Q607 -512 537 -580Q467 -648 316 -648ZM98 -729H301Q513 -729 612 -641Q711 -553 711 -365Q711 -177 611 -88Q512 0 301 0H98Z"], "E": [632, "M98 -729H559V-646H197V-430H544V-347H197V-83H568V0H98Z"], "F": [575, "M98 -729H517V-646H197V-431H486V-348H197V0H98Z"], "G": [775, "M595 -104V-300H434V-381H693V-68Q636 -27 567 -7Q498 14 420 14Q249 14 153 -86Q56 -186 56 -364Q56 -542 153 -642Q249 -742 420 -742Q491 -742 555 -725Q620 -707 674 -673V-568Q619 -614 558 -638Q496 -661 428 -661Q294 -661 227 -586Q160 -512 160 -364Q160 -216 227 -142Q294 -67 428 -67Q480 -67 521 -76Q562 -85 595 -104Z"], "H": [752, "M98 -729H197V-430H555V-729H654V0H555V-347H197V0H98Z"], "I": [295, "M98 -729H197V0H98Z"], "J": [295, "M98 -729H197V-51Q197 81 147 141Q97 200 -14 200H-52V117H-21Q44 117 71 81Q98 44 98 -51Z"], "K": [656, "M98 -729H197V-421L524 -729H651L289 -389L677 0H547L197 -351V0H98Z"], "L": [557, "M98 -729H197V-83H552V0H98Z"], "M": [863, "M98 -729H245L431 -233L618 -729H765V0H669V-640L481 -140H382L194 -640V0H98Z"], "N": [748, "M98 -729H231L554 -119V-729H650V0H517L194 -610V0H98Z"], "O": [787, "M394 -662Q287 -662 223 -582Q160 -502 160 -364Q160 -226 223 -146Q287 -66 394 -66Q501 -66 564 -146Q627 -226 627 -364Q627 -502 564 -582Q501 -662 394 -662ZM394 -742Q547 -742 639 -639Q731 -537 731 -364Q731 -191 639 -89Q547 14 394 14Q240 14 148 -88Q56 -191 56 -364Q56 -537 148 -639Q240 -742 394 -742Z"], "P": [603, "M197 -648V-374H321Q390 -374 427 -410Q465 -445 465 -511Q465 -577 427 -612Q390 -648 321 -648ZM98 -729H321Q443 -729 506 -674Q569 -618 569 -511Q569 -403 506 -348Q443 -293 321 -293H197V0H98Z"], "Q": [787, "M394 -662Q287 -662 223 -582Q160 -502 160 -364Q160 -226 223 -146Q287 -66 394 -66Q501 -66 564 -146Q627 -226 627 -364Q627 -502 564 -582Q501 -662 394 -662ZM532 -13 662 129H543L435 12Q419 13 410 14Q402 14 394 14Q240 14 148 -89Q56 -191 56 -364Q56 -537 148 -639Q240 -742 394 -742Q547 -742 639 -639Q731 -537 731 -364Q731 -237 680 -146Q629 -56 532 -13Z"], "R": [695, "M444 -342Q476 -331 506 -296Q536 -261 566 -199L666 0H560L467 -187Q431 -260 397 -284Q363 -308 304 -308H197V0H98V-729H321Q446 -729 507 -677Q569 -625 569 -519Q569 -450 537 -405Q505 -359 444 -342ZM197 -648V-389H321Q392 -389 428 -422Q465 -455 465 -519Q465 -583 428 -615Q392 -648 321 -648Z"], "S": [635, "M535 -705V-609Q479 -636 429 -649Q379 -662 333 -662Q252 -662 209 -631Q165 -600 165 -542Q165 -494 194 -469Q223 -444 304 -429L364 -417Q474 -396 527 -343Q579 -290 579 -201Q579 -95 508 -41Q437 14 300 14Q248 14 190 2Q131 -9 69 -32V-134Q129 -100 187 -83Q244 -66 300 -66Q384 -66 430 -99Q476 -132 476 -194Q476 -248 443 -278Q410 -308 335 -323L275 -335Q165 -357 115 -404Q66 -451 66 -534Q66 -631 134 -687Q202 -742 322 -742Q373 -742 426 -733Q479 -724 535 -705Z"], "T": [611, "M-3 -729H614V-646H355V0H256V-646H-3Z"], "U": [732, "M87 -729H186V-286Q186 -169 229 -117Q271 -66 366 -66Q461 -66 503 -117Q546 -169 546 -286V-729H645V-274Q645 -131 574 -59Q504 14 366 14Q228 14 157 -59Q87 -131 87 -274Z"], "V": [684, "M286 0 8 -729H111L342 -115L573 -729H676L398 0Z"], "W": [989, "M33 -729H133L286 -113L439 -729H550L703 -113L856 -729H956L773 0H649L495 -633L340 0H216Z"], "X": [685, "M63 -729H169L350 -458L532 -729H638L404 -379L654 0H548L343 -310L136 0H30L290 -389Z"], "Y": [611, "M-2 -729H104L306 -429L507 -729H613L355 -347V0H256V-347Z"], "Z": [685, "M56 -729H629V-654L168 -83H640V0H45V-75L506 -646H56Z"], "[": [390, "M86 -760H293V-690H176V62H293V132H86Z"], "\\": [337, "M83 -729 337 93H254L0 -729Z"], "]": [390, "M304 -760V132H97V62H214V-690H97V-760Z"], "^": [838, "M467 -729 732 -457H634L419 -650L204 -457H106L371 -729Z"], "_": [500, "M510 166V236H-10V166Z"], "`": [500, "M179 -800 317 -617H242L83 -800Z"], "a": [613, "M343 -275Q234 -275 192 -250Q150 -225 150 -165Q150 -117 181 -89Q213 -61 267 -61Q342 -61 387 -114Q432 -167 432 -255V-275ZM522 -312V0H432V-83Q401 -33 355 -10Q310 14 243 14Q159 14 110 -33Q60 -80 60 -159Q60 -251 122 -298Q184 -345 306 -345H432V-354Q432 -416 391 -450Q351 -484 277 -484Q230 -484 186 -473Q141 -461 100 -439V-522Q149 -541 196 -551Q242 -560 286 -560Q405 -560 463 -499Q522 -437 522 -312Z"], "b": [635, "M487 -273Q487 -372 446 -428Q405 -485 334 -485Q263 -485 222 -428Q181 -372 181 -273Q181 -174 222 -117Q263 -61 334 -61Q405 -61 446 -117Q487 -174 487 -273ZM181 -464Q209 -513 253 -536Q296 -560 356 -560Q456 -560 518 -481Q580 -402 580 -273Q580 -144 518 -65Q456 14 356 14Q296 14 253 -10Q209 -33 181 -82V0H91V-760H181Z"], "c": [550, "M488 -526V-442Q450 -463 411 -473Q373 -484 334 -484Q247 -484 198 -428Q150 -373 150 -273Q150 -173 198 -117Q247 -62 334 -62Q373 -62 411 -73Q450 -83 488 -104V-21Q450 -3 410 5Q370 14 324 14Q201 14 128 -63Q55 -141 55 -273Q55 -407 129 -483Q202 -560 330 -560Q372 -560 411 -552Q451 -543 488 -526Z"], "d": [635, "M454 -464V-760H544V0H454V-82Q426 -33 383 -10Q339 14 279 14Q180 14 117 -65Q55 -144 55 -273Q55 -402 117 -481Q180 -560 279 -560Q339 -560 383 -536Q426 -513 454 -464ZM148 -273Q148 -174 189 -117Q229 -61 301 -61Q372 -61 413 -117Q454 -174 454 -273Q454 -372 413 -428Q372 -485 301 -485Q229 -485 189 -428Q148 -372 148 -273Z"], "e": [615, "M562 -296V-252H149Q155 -159 205 -111Q255 -62 344 -62Q396 -62 445 -75Q493 -87 541 -113V-28Q493 -7 442 3Q391 14 339 14Q208 14 132 -62Q55 -138 55 -268Q55 -402 128 -481Q200 -560 323 -560Q434 -560 498 -489Q562 -418 562 -296ZM472 -322Q471 -396 431 -440Q391 -484 324 -484Q249 -484 204 -441Q159 -399 152 -322Z"], "f": [352, "M371 -760V-685H285Q237 -685 218 -666Q199 -646 199 -595V-547H347V-477H199V0H109V-477H23V-547H109V-585Q109 -676 151 -718Q194 -760 286 -760Z"], "g": [635, "M454 -280Q454 -377 414 -431Q374 -485 301 -485Q229 -485 188 -431Q148 -377 148 -280Q148 -183 188 -129Q229 -75 301 -75Q374 -75 414 -129Q454 -183 454 -280ZM544 -68Q544 72 482 140Q420 208 292 208Q245 208 203 201Q161 194 121 179V92Q161 113 199 124Q238 134 278 134Q366 134 410 88Q454 42 454 -52V-96Q426 -48 383 -24Q339 0 279 0Q178 0 117 -77Q55 -153 55 -280Q55 -407 117 -483Q178 -560 279 -560Q339 -560 383 -536Q426 -512 454 -464V-547H544Z"], "h": [634, "M549 -330V0H459V-327Q459 -405 429 -443Q398 -482 338 -482Q265 -482 223 -436Q181 -389 181 -309V0H91V-760H181V-462Q213 -511 257 -536Q301 -560 358 -560Q452 -560 500 -502Q549 -443 549 -330Z"], "i": [278, "M94 -547H184V0H94ZM94 -760H184V-646H94Z"], "j": [278, "M94 -547H184V10Q184 114 144 161Q104 208 16 208H-18V132H6Q57 132 76 108Q94 84 94 10ZM94 -760H184V-646H94Z"], "k": [579, "M91 -760H181V-311L449 -547H564L274 -291L576 0H459L181 -267V0H91Z"], "l": [278, "M94 -760H184V0H94Z"], "m": [974, "M520 -442Q554 -502 601 -531Q647 -560 711 -560Q796 -560 843 -500Q889 -440 889 -330V0H799V-327Q799 -406 771 -444Q743 -482 686 -482Q616 -482 576 -436Q535 -389 535 -309V0H445V-327Q445 -406 417 -444Q389 -482 331 -482Q262 -482 222 -435Q181 -389 181 -309V0H91V-547H181V-462Q212 -512 255 -536Q298 -560 357 -560Q417 -560 458 -530Q500 -500 520 -442Z"], "n": [634, "M549 -330V0H459V-327Q459 -405 429 -443Q398 -482 338 -482Q265 -482 223 -436Q181 -389 181 -309V0H91V-547H181V-462Q213 -511 257 -536Q301 -560 358 -560Q452 -560 500 -502Q549 -443 549 -330Z"], "o": [612, "M306 -484Q234 -484 192 -427Q150 -371 150 -273Q150 -175 192 -118Q233 -62 306 -62Q378 -62 420 -119Q462 -175 462 -273Q462 -370 420 -427Q378 -484 306 -484ZM306 -560Q423 -560 490 -484Q557 -408 557 -273Q557 -139 490 -62Q423 14 306 14Q188 14 122 -62Q55 -139 55 -273Q55 -408 122 -484Q188 -560 306 -560Z"], "p": [635, "M181 -82V208H91V-547H181V-464Q209 -513 253 -536Q296 -560 356 -560Q456 -560 518 -481Q580 -402 580 -273Q580 -144 518 -65Q456 14 356 14Q296 14 253 -10Q209 -33 181 -82ZM487 -273Q487 -372 446 -428Q405 -485 334 -485Q263 -485 222 -428Q181 -372 181 -273Q181 -174 222 -117Q263 -61 334 -61Q405 -61 446 -117Q487 -174 487 -273Z"], "q": [635, "M148 -273Q148 -174 189 -117Q229 -61 301 -61Q372 -61 413 -117Q454 -174 454 -273Q454 -372 413 -428Q372 -485 301 -485Q229 -485 189 -428Q148 -372 148 -273ZM454 -82Q426 -33 383 -10Q339 14 279 14Q180 14 117 -65Q55 -144 55 -273Q55 -402 117 -481Q180 -560 279 -560Q339 -560 383 -536Q426 -513 454 -464V-547H544V208H454Z"], "r": [411, "M411 -463Q396 -472 378 -476Q360 -480 339 -480Q263 -480 222 -430Q181 -381 181 -288V0H91V-547H181V-462Q209 -512 255 -536Q300 -560 365 -560Q375 -560 386 -559Q397 -558 411 -555Z"], "s": [521, "M443 -531V-446Q405 -465 364 -475Q323 -485 279 -485Q212 -485 178 -464Q145 -444 145 -403Q145 -372 169 -354Q193 -336 265 -320L296 -313Q392 -292 432 -255Q472 -218 472 -151Q472 -75 412 -30Q352 14 246 14Q202 14 155 6Q107 -3 54 -20V-113Q104 -87 152 -74Q201 -61 248 -61Q312 -61 346 -83Q380 -104 380 -144Q380 -181 355 -200Q331 -220 247 -238L216 -245Q132 -263 95 -299Q58 -335 58 -399Q58 -476 113 -518Q167 -560 268 -560Q318 -560 362 -553Q406 -545 443 -531Z"], "t": [392, "M183 -702V-547H368V-477H183V-180Q183 -113 201 -94Q220 -75 276 -75H368V0H276Q172 0 132 -39Q93 -78 93 -180V-477H27V-547H93V-702Z"], "u": [634, "M85 -216V-547H175V-219Q175 -142 205 -103Q235 -64 296 -64Q369 -64 411 -110Q453 -157 453 -237V-547H543V0H453V-84Q420 -34 377 -10Q334 14 277 14Q183 14 134 -44Q85 -103 85 -216ZM311 -560Z"], "v": [592, "M30 -547H125L296 -88L467 -547H562L357 0H235Z"], "w": [818, "M42 -547H132L244 -120L356 -547H462L574 -120L686 -547H776L633 0H527L409 -448L291 0H185Z"], "x": [592, "M549 -547 351 -281 559 0H453L294 -215L135 0H29L241 -286L47 -547H153L298 -352L443 -547Z"], "y": [592, "M322 51Q284 148 248 178Q211 208 151 208H79V133H132Q169 133 189 115Q210 98 235 32L251 -9L30 -547H125L296 -119L467 -547H562Z"], "z": [525, "M55 -547H482V-465L144 -72H482V0H43V-82L381 -475H55Z"], "{": [636, "M511 93V163H481Q359 163 318 127Q277 91 277 -17V-134Q277 -208 250 -236Q224 -264 155 -264H125V-334H155Q225 -334 251 -362Q277 -390 277 -463V-580Q277 -688 318 -724Q359 -760 481 -760H511V-690H478Q409 -690 388 -668Q367 -647 367 -578V-457Q367 -380 345 -346Q323 -311 269 -299Q323 -286 345 -251Q367 -216 367 -140V-19Q367 50 388 71Q409 93 478 93Z"], "|": [337, "M210 -764V236H127V-764Z"], "}": [636, "M125 93H159Q228 93 248 72Q269 51 269 -19V-140Q269 -216 291 -251Q313 -286 367 -299Q313 -311 291 -346Q269 -380 269 -457V-578Q269 -647 248 -669Q228 -690 159 -690H125V-760H156Q277 -760 318 -724Q359 -688 359 -580V-463Q359 -390 385 -362Q412 -334 481 -334H511V-264H481Q412 -264 385 -236Q359 -208 359 -134V-17Q359 91 318 127Q277 163 156 163H125Z"], "~": [838, "M732 -399V-312Q681 -273 637 -257Q593 -240 546 -240Q492 -240 421 -269Q416 -271 413 -272Q410 -273 402 -276Q327 -306 281 -306Q238 -306 196 -287Q154 -269 106 -228V-315Q157 -354 201 -370Q245 -387 292 -387Q346 -387 417 -358Q422 -356 425 -355Q429 -354 436 -351Q511 -321 557 -321Q599 -321 640 -339Q682 -358 732 -399Z"], "°": [500, "M250 -679Q211 -679 184 -652Q157 -625 157 -586Q157 -547 184 -521Q211 -494 250 -494Q289 -494 316 -521Q343 -547 343 -586Q343 -625 316 -652Q289 -679 250 -679ZM250 -742Q281 -742 310 -730Q339 -718 360 -696Q382 -674 394 -646Q405 -618 405 -586Q405 -521 360 -477Q314 -432 249 -432Q183 -432 139 -476Q95 -520 95 -586Q95 -651 140 -697Q185 -742 250 -742Z"], "−": [838, "M106 -355H732V-272H106Z"], "×": [838, "M701 -537 478 -313 701 -90 643 -31 419 -255 195 -31 137 -90 360 -313 137 -537 195 -596 419 -372 643 -596Z"], "→": [838, "M789 -335V-292L597 -100L539 -158L652 -272H57V-355H652L539 -469L597 -527Z"], "←": [838, "M49 -292V-335L241 -527L299 -469L186 -355H781V-272H186L299 -158L241 -100Z"], "…": [1000, "M448 -124H552V0H448ZM781 -124H885V0H781ZM115 -124H219V0H115Z"], "–": [500, "M49 -309H451V-239H49Z"], "—": [1000, "M49 -309H951V-239H49Z"], "·": [318, "M107 -409H210V-285H107Z"], "µ": [636, "M85 208V-547H175V-207Q175 -136 208 -100Q242 -64 308 -64Q380 -64 417 -105Q453 -146 453 -228V-547H543V-126Q543 -97 552 -83Q560 -69 578 -69Q583 -69 590 -72Q598 -74 612 -80V-8Q592 3 574 9Q556 14 539 14Q505 14 485 -5Q465 -24 458 -63Q434 -24 398 -5Q363 14 315 14Q265 14 230 -5Q195 -24 175 -62V208Z"], "±": [838, "M460 -627V-438H732V-355H460V-166H378V-355H106V-438H378V-627ZM106 -83H732V0H106Z"], "²": [401, "M131 -382H338V-326H46V-380Q62 -395 93 -422Q261 -571 261 -617Q261 -649 236 -669Q210 -689 169 -689Q144 -689 114 -680Q84 -672 49 -655V-715Q86 -729 119 -735Q151 -742 179 -742Q250 -742 292 -710Q335 -678 335 -625Q335 -557 173 -418Q146 -395 131 -382Z"], "³": [401, "M256 -547Q301 -538 325 -511Q350 -485 350 -445Q350 -384 304 -352Q257 -319 171 -319Q143 -319 113 -324Q82 -329 48 -339V-398Q73 -385 102 -378Q131 -372 164 -372Q217 -372 247 -391Q276 -411 276 -445Q276 -481 249 -500Q222 -518 169 -518H127V-571H173Q219 -571 242 -586Q266 -602 266 -631Q266 -659 242 -674Q217 -689 171 -689Q151 -689 126 -685Q102 -680 62 -669V-725Q98 -733 129 -738Q160 -742 187 -742Q257 -742 299 -713Q340 -685 340 -636Q340 -603 318 -579Q296 -556 256 -547Z"], "á": [613, "M343 -275Q234 -275 192 -250Q150 -225 150 -165Q150 -117 181 -89Q213 -61 267 -61Q342 -61 387 -114Q432 -167 432 -255V-275ZM522 -312V0H432V-83Q401 -33 355 -10Q310 14 243 14Q159 14 110 -33Q60 -80 60 -159Q60 -251 122 -298Q184 -345 306 -345H432V-354Q432 -416 391 -450Q351 -484 277 -484Q230 -484 186 -473Q141 -461 100 -439V-522Q149 -541 196 -551Q242 -560 286 -560Q405 -560 463 -499Q522 -437 522 -312ZM358 -800H455L296 -616H221Z"], "č": [550, "M488 -526V-442Q450 -463 411 -473Q373 -484 334 -484Q247 -484 198 -428Q150 -373 150 -273Q150 -173 198 -117Q247 -62 334 -62Q373 -62 411 -73Q450 -83 488 -104V-21Q450 -3 410 5Q370 14 324 14Q201 14 128 -63Q55 -141 55 -273Q55 -407 129 -483Q202 -560 330 -560Q372 -560 411 -552Q451 -543 488 -526ZM281 -616 161 -800H229L317 -680L405 -800H473L353 -616Z"], "ď": [635, "M454 -464V-760H544V0H454V-82Q426 -33 383 -10Q339 14 279 14Q180 14 117 -65Q55 -144 55 -273Q55 -402 117 -481Q180 -560 279 -560Q339 -560 383 -536Q426 -513 454 -464ZM148 -273Q148 -174 189 -117Q229 -61 301 -61Q372 -61 413 -117Q454 -174 454 -273Q454 -372 413 -428Q372 -485 301 -485Q229 -485 189 -428Q148 -372 148 -273ZM635 -759H732L675 -575H600Z"], "é": [615, "M562 -296V-252H149Q155 -159 205 -111Q255 -62 344 -62Q396 -62 445 -75Q493 -87 541 -113V-28Q493 -7 442 3Q391 14 339 14Q208 14 132 -62Q55 -138 55 -268Q55 -402 128 -481Q200 -560 323 -560Q434 -560 498 -489Q562 -418 562 -296ZM472 -322Q471 -396 431 -440Q391 -484 324 -484Q249 -484 204 -441Q159 -399 152 -322ZM386 -800H483L324 -616H249Z"], "ě": [615, "M562 -296V-252H149Q155 -159 205 -111Q255 -62 344 -62Q396 -62 445 -75Q493 -87 541 -113V-28Q493 -7 442 3Q391 14 339 14Q208 14 132 -62Q55 -138 55 -268Q55 -402 128 -481Q200 -560 323 -560Q434 -560 498 -489Q562 -418 562 -296ZM472 -322Q471 -396 431 -440Q391 -484 324 -484Q249 -484 204 -441Q159 -399 152 -322ZM286 -614 167 -797H234L322 -678L410 -797H478L358 -614Z"], "í": [278, "M207 -800H304L145 -616H70ZM94 -547H184V0H94ZM139 -560Z"], "ň": [634, "M549 -330V0H459V-327Q459 -405 429 -443Q398 -482 338 -482Q265 -482 223 -436Q181 -389 181 -309V0H91V-547H181V-462Q213 -511 257 -536Q301 -560 358 -560Q452 -560 500 -502Q549 -443 549 -330ZM283 -616 163 -800H231L319 -680L407 -800H475L355 -616Z"], "ó": [612, "M306 -484Q234 -484 192 -427Q150 -371 150 -273Q150 -175 192 -118Q233 -62 306 -62Q378 -62 420 -119Q462 -175 462 -273Q462 -370 420 -427Q378 -484 306 -484ZM306 -560Q423 -560 490 -484Q557 -408 557 -273Q557 -139 490 -62Q423 14 306 14Q188 14 122 -62Q55 -139 55 -273Q55 -408 122 -484Q188 -560 306 -560ZM374 -800H471L312 -616H237Z"], "ř": [411, "M411 -463Q396 -472 378 -476Q360 -480 339 -480Q263 -480 222 -430Q181 -381 181 -288V0H91V-547H181V-462Q209 -512 255 -536Q300 -560 365 -560Q375 -560 386 -559Q397 -558 411 -555ZM227 -616 107 -800H175L263 -680L351 -800H419L299 -616Z"], "š": [521, "M443 -531V-446Q405 -465 364 -475Q323 -485 279 -485Q212 -485 178 -464Q145 -444 145 -403Q145 -372 169 -354Q193 -336 265 -320L296 -313Q392 -292 432 -255Q472 -218 472 -151Q472 -75 412 -30Q352 14 246 14Q202 14 155 6Q107 -3 54 -20V-113Q104 -87 152 -74Q201 -61 248 -61Q312 -61 346 -83Q380 -104 380 -144Q380 -181 355 -200Q331 -220 247 -238L216 -245Q132 -263 95 -299Q58 -335 58 -399Q58 -476 113 -518Q167 -560 268 -560Q318 -560 362 -553Q406 -545 443 -531ZM235 -616 115 -800H183L271 -680L359 -800H427L307 -616ZM269 -560Z"], "ť": [392, "M183 -702V-547H368V-477H183V-180Q183 -113 201 -94Q220 -75 276 -75H368V0H276Q172 0 132 -39Q93 -78 93 -180V-477H27V-547H93V-702ZM277 -813H374L317 -630H242Z"], "ú": [634, "M85 -216V-547H175V-219Q175 -142 205 -103Q235 -64 296 -64Q369 -64 411 -110Q453 -157 453 -237V-547H543V0H453V-84Q420 -34 377 -10Q334 14 277 14Q183 14 134 -44Q85 -103 85 -216ZM311 -560ZM378 -800H475L316 -616H241Z"], "ů": [634, "M85 -216V-547H175V-219Q175 -142 205 -103Q235 -64 296 -64Q369 -64 411 -110Q453 -157 453 -237V-547H543V0H453V-84Q420 -34 377 -10Q334 14 277 14Q183 14 134 -44Q85 -103 85 -216ZM311 -560ZM385 -715Q385 -746 363 -767Q342 -789 311 -789Q279 -789 258 -767Q236 -746 236 -715Q236 -683 258 -662Q279 -641 311 -641Q342 -641 363 -662Q385 -684 385 -715ZM444 -715Q444 -659 406 -620Q367 -581 311 -581Q254 -581 216 -620Q177 -659 177 -715Q177 -771 216 -810Q254 -849 311 -849Q367 -849 406 -810Q444 -771 444 -715Z"], "ý": [592, "M322 51Q284 148 248 178Q211 208 151 208H79V133H132Q169 133 189 115Q210 98 235 32L251 -9L30 -547H125L296 -119L467 -547H562ZM364 -800H461L302 -616H227Z"], "ž": [525, "M55 -547H482V-465L144 -72H482V0H43V-82L381 -475H55ZM227 -616 107 -800H175L263 -680L351 -800H419L299 -616Z"], "Á": [684, "M342 -632 208 -269H476ZM286 -729H398L676 0H573L507 -187H178L112 0H8ZM369 -927H459L348 -798H273Z"], "Č": [698, "M644 -673V-569Q594 -615 538 -638Q481 -661 418 -661Q293 -661 227 -585Q160 -508 160 -364Q160 -220 227 -143Q293 -67 418 -67Q481 -67 538 -90Q594 -113 644 -159V-56Q592 -21 534 -3Q477 14 412 14Q247 14 151 -87Q56 -188 56 -364Q56 -540 151 -641Q247 -742 412 -742Q478 -742 535 -725Q593 -708 644 -673ZM351 -798 248 -928H316L397 -841L478 -928H546L443 -798Z"], "Ď": [770, "M319 -798 216 -928H284L365 -841L446 -928H514L411 -798ZM197 -648V-81H316Q467 -81 537 -149Q607 -218 607 -365Q607 -512 537 -580Q467 -648 316 -648ZM98 -729H301Q513 -729 612 -641Q711 -553 711 -365Q711 -177 611 -88Q512 0 301 0H98Z"], "É": [632, "M98 -729H559V-646H197V-430H544V-347H197V-83H568V0H98ZM354 -927H444L333 -798H258Z"], "Ě": [632, "M98 -729H559V-646H197V-430H544V-347H197V-83H568V0H98ZM285 -795 182 -925H250L331 -838L412 -925H480L377 -795Z"], "Í": [295, "M98 -729H197V0H98ZM175 -927H265L154 -798H79Z"], "Ň": [748, "M98 -729H231L554 -119V-729H650V0H517L194 -610V0H98ZM324 -792 221 -921H289L370 -834L451 -921H519L416 -792Z"], "Ó": [787, "M394 -662Q287 -662 223 -582Q160 -502 160 -364Q160 -226 223 -146Q287 -66 394 -66Q501 -66 564 -146Q627 -226 627 -364Q627 -502 564 -582Q501 -662 394 -662ZM394 -742Q547 -742 639 -639Q731 -537 731 -364Q731 -191 639 -89Q547 14 394 14Q240 14 148 -88Q56 -191 56 -364Q56 -537 148 -639Q240 -742 394 -742ZM421 -927H511L400 -798H325Z"], "Ř": [695, "M444 -342Q476 -331 506 -296Q536 -261 566 -199L666 0H560L467 -187Q431 -260 397 -284Q363 -308 304 -308H197V0H98V-729H321Q446 -729 507 -677Q569 -625 569 -519Q569 -450 537 -405Q505 -359 444 -342ZM197 -648V-389H321Q392 -389 428 -422Q465 -455 465 -519Q465 -583 428 -615Q392 -648 321 -648ZM265 -792 162 -921H230L311 -834L392 -921H460L357 -792Z"], "Š": [635, "M535 -705V-609Q479 -636 429 -649Q379 -662 333 -662Q252 -662 209 -631Q165 -600 165 -542Q165 -494 194 -469Q223 -444 304 -429L364 -417Q474 -396 527 -343Q579 -290 579 -201Q579 -95 508 -41Q437 14 300 14Q248 14 190 2Q131 -9 69 -32V-134Q129 -100 187 -83Q244 -66 300 -66Q384 -66 430 -99Q476 -132 476 -194Q476 -248 443 -278Q410 -308 335 -323L275 -335Q165 -357 115 -404Q66 -451 66 -534Q66 -631 134 -687Q202 -742 322 -742Q373 -742 426 -733Q479 -724 535 -705ZM272 -798 169 -928H237L318 -841L399 -928H467L364 -798Z"], "Ť": [611, "M-3 -729H614V-646H355V0H256V-646H-3ZM260 -792 157 -921H225L306 -834L387 -921H455L352 -792Z"], "Ú": [732, "M87 -729H186V-286Q186 -169 229 -117Q271 -66 366 -66Q461 -66 503 -117Q546 -169 546 -286V-729H645V-274Q645 -131 574 -59Q504 14 366 14Q228 14 157 -59Q87 -131 87 -274ZM393 -927H483L372 -798H297Z"], "Ů": [732, "M87 -729H186V-286Q186 -169 229 -117Q271 -66 366 -66Q461 -66 503 -117Q546 -169 546 -286V-729H645V-274Q645 -131 574 -59Q504 14 366 14Q228 14 157 -59Q87 -131 87 -274ZM441 -795Q441 -826 420 -848Q398 -869 367 -869Q335 -869 314 -848Q293 -827 293 -795Q293 -764 314 -742Q335 -721 367 -721Q398 -721 420 -743Q441 -764 441 -795ZM501 -795Q501 -739 462 -700Q423 -661 367 -661Q311 -661 272 -700Q233 -739 233 -795Q233 -852 272 -890Q311 -929 367 -929Q423 -929 462 -890Q501 -852 501 -795Z"], "Ý": [611, "M-2 -729H104L306 -429L507 -729H613L355 -347V0H256V-347ZM333 -927H423L312 -798H237Z"], "Ž": [685, "M56 -729H629V-654L168 -83H640V0H45V-75L506 -646H56ZM297 -798 194 -928H262L343 -841L424 -928H492L389 -798Z"], "ä": [613, "M343 -275Q234 -275 192 -250Q150 -225 150 -165Q150 -117 181 -89Q213 -61 267 -61Q342 -61 387 -114Q432 -167 432 -255V-275ZM522 -312V0H432V-83Q401 -33 355 -10Q310 14 243 14Q159 14 110 -33Q60 -80 60 -159Q60 -251 122 -298Q184 -345 306 -345H432V-354Q432 -416 391 -450Q351 -484 277 -484Q230 -484 186 -473Q141 -461 100 -439V-522Q149 -541 196 -551Q242 -560 286 -560Q405 -560 463 -499Q522 -437 522 -312ZM336 -758H435V-659H336ZM145 -758H244V-659H145Z"], "ö": [612, "M306 -484Q234 -484 192 -427Q150 -371 150 -273Q150 -175 192 -118Q233 -62 306 -62Q378 -62 420 -119Q462 -175 462 -273Q462 -370 420 -427Q378 -484 306 -484ZM306 -560Q423 -560 490 -484Q557 -408 557 -273Q557 -139 490 -62Q423 14 306 14Q188 14 122 -62Q55 -139 55 -273Q55 -408 122 -484Q188 -560 306 -560ZM352 -758H451V-659H352ZM161 -758H260V-659H161Z"], "ü": [634, "M85 -216V-547H175V-219Q175 -142 205 -103Q235 -64 296 -64Q369 -64 411 -110Q453 -157 453 -237V-547H543V0H453V-84Q420 -34 377 -10Q334 14 277 14Q183 14 134 -44Q85 -103 85 -216ZM311 -560ZM356 -758H455V-659H356ZM165 -758H264V-659H165Z"], "ß": [630, "M91 -555Q91 -653 149 -706Q208 -760 314 -760Q416 -760 469 -703Q522 -646 524 -537Q450 -533 409 -505Q368 -477 368 -430Q368 -407 382 -387Q396 -368 428 -347L456 -329Q537 -277 561 -243Q584 -208 584 -159Q584 -75 529 -31Q474 14 371 14Q340 14 307 8Q273 2 238 -10V-90Q277 -75 311 -68Q345 -61 377 -61Q434 -61 463 -84Q492 -107 492 -152Q492 -183 478 -203Q463 -224 414 -254L369 -281Q322 -310 301 -343Q280 -375 280 -420Q280 -482 321 -524Q361 -566 435 -580Q431 -630 399 -658Q367 -685 312 -685Q249 -685 215 -651Q182 -617 182 -553V0H91Z"], "▲": [769, "M3 123 384 -643 766 123Z"], "▼": [769, "M3 -643H766L384 123Z"], "●": [873, "M55 -259Q55 -361 106 -450Q157 -538 246 -589Q334 -641 437 -641Q539 -641 627 -589Q716 -538 767 -450Q818 -361 818 -259Q818 -157 767 -68Q716 21 627 72Q539 123 437 123Q334 123 246 72Q157 21 106 -68Q55 -157 55 -259Z"] };
@@ -0,0 +1,83 @@
1
+ export type ChartTone = "page" | "escalate" | "warn" | "note" | "info" | "ok";
2
+ export interface ChartPanel {
3
+ label: string;
4
+ unit?: string;
5
+ /** `line` joins the points; `step` holds each value until the next (on/off signals). */
6
+ kind?: "line" | "step";
7
+ /** [x, y] in the same x units as `xStart`/`xEnd`, ascending. */
8
+ points: [number, number][];
9
+ /** Draw a faint band for what normal looks like (a probe's physical range, a setpoint ± tolerance). */
10
+ band?: {
11
+ min: number;
12
+ max: number;
13
+ label?: string;
14
+ };
15
+ /** For a step panel: the words for 0 and 1 (default off/on). */
16
+ levels?: [string, string];
17
+ /**
18
+ * Values no sensor can honestly read (a probe's −999.9 sentinel, a 2³² counter).
19
+ * They are drawn on a red rail at the panel's edge with a count, and the scale is
20
+ * fitted to the rest — so the fault is visible AND the real signal is readable.
21
+ */
22
+ impossible?: {
23
+ below?: number;
24
+ above?: number;
25
+ label?: string;
26
+ };
27
+ }
28
+ export interface ChartMarker {
29
+ x: number;
30
+ label?: string;
31
+ tone?: ChartTone;
32
+ }
33
+ export interface ChartSpec {
34
+ title?: string;
35
+ subtitle?: string;
36
+ /** Pixel width (default 960). Height follows from the panels. */
37
+ width?: number;
38
+ /** Plot height of one panel (default 96). */
39
+ panelHeight?: number;
40
+ xStart: number;
41
+ xEnd: number;
42
+ /** Tick labels along the bottom, e.g. stream times. */
43
+ xTicks?: {
44
+ x: number;
45
+ label: string;
46
+ }[];
47
+ panels: ChartPanel[];
48
+ markers?: ChartMarker[];
49
+ /** A vertical "now" edge (the stream clock). */
50
+ now?: number;
51
+ /** Break a line where consecutive points are further apart than this (x units); default: 5 % of the window. */
52
+ gap?: number;
53
+ theme?: "light" | "dark";
54
+ }
55
+ /** The width of a string at a font size, in pixels. */
56
+ export declare function textWidth(text: string, size: number): number;
57
+ /** A string as filled glyph outlines. `y` is the baseline. */
58
+ export declare function textPath(text: string, x: number, y: number, size: number, opts?: {
59
+ fill: string;
60
+ anchor?: "start" | "middle" | "end";
61
+ maxWidth?: number;
62
+ }): string;
63
+ /** A number the way a person reads a measurement: few digits, no noise. */
64
+ export declare function formatValue(v: number): string;
65
+ /**
66
+ * A chart as one SVG string from a spec (panels of series, markers, tones): the same picture for the
67
+ * app's screen (`dangerouslySetInnerHTML`) and, rendered with `renderChartImage` on the server, for
68
+ * a tool's answer. Text is drawn as glyph outlines, so it needs no fonts where it is rasterised.
69
+ */
70
+ export declare function chartSvg(spec: ChartSpec): string;
71
+ /**
72
+ * Naive local timestamps ("2026-03-31T20:58:20" or with a space) as a number for an
73
+ * x axis — minutes since the epoch, WITHOUT a timezone. Stream times are wall-clock
74
+ * strings from a device; `new Date(s)` would shift them by the viewer's offset.
75
+ */
76
+ export declare function naiveMinutes(ts: string): number;
77
+ /** A naive-minutes value back to "MM-DD HH:MM" for a tick. */
78
+ export declare function naiveLabel(minutes: number, withDate?: boolean): string;
79
+ /** Evenly spaced ticks across a naive-minutes window, labelled for the span. */
80
+ export declare function naiveTicks(start: number, end: number, count?: number): {
81
+ x: number;
82
+ label: string;
83
+ }[];