@hpcc-js/observablehq-compiler 1.4.0 → 3.2.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 (64) hide show
  1. package/bin/ojscc.mjs +13 -19
  2. package/dist/index.css +2 -1
  3. package/dist/index.css.map +7 -0
  4. package/dist/index.js +24 -7999
  5. package/dist/index.js.map +7 -1
  6. package/package.json +42 -52
  7. package/src/__package__.ts +2 -2
  8. package/src/compiler.ts +34 -22
  9. package/src/cst.ts +27 -23
  10. package/src/index.ts +4 -3
  11. package/src/observable-shim.ts +2 -0
  12. package/src/parse.ts +136 -0
  13. package/src/types.ts +180 -0
  14. package/src/util.ts +6 -3
  15. package/src/writer.ts +9 -6
  16. package/types/compiler.d.ts +7 -8
  17. package/types/cst.d.ts +0 -1
  18. package/types/index.d.ts +4 -4
  19. package/types/observable-shim.d.ts +2 -0
  20. package/types/parse.d.ts +26 -0
  21. package/types/types.d.ts +165 -0
  22. package/types/util.d.ts +2 -3
  23. package/types/writer.d.ts +2 -3
  24. package/dist/index.esm.css +0 -1
  25. package/dist/index.esm.js +0 -7999
  26. package/dist/index.esm.js.map +0 -1
  27. package/dist/index.esm.min.js +0 -4
  28. package/dist/index.esm.min.js.map +0 -1
  29. package/dist/index.min.js +0 -4
  30. package/dist/index.min.js.map +0 -1
  31. package/src/__tests__/File Attachments.ts +0 -895
  32. package/src/__tests__/Introduction to Imports.ts +0 -749
  33. package/src/__tests__/Observable TimeChart.ts +0 -772
  34. package/src/__tests__/index.ts +0 -13
  35. package/src/__tests__/m1.mjs +0 -3
  36. package/src/__tests__/node.ts +0 -199
  37. package/types/__package__.d.ts +0 -4
  38. package/types/__package__.d.ts.map +0 -1
  39. package/types/__tests__/File Attachments.d.ts +0 -110
  40. package/types/__tests__/File Attachments.d.ts.map +0 -1
  41. package/types/__tests__/Introduction to Imports.d.ts +0 -120
  42. package/types/__tests__/Introduction to Imports.d.ts.map +0 -1
  43. package/types/__tests__/Observable TimeChart.d.ts +0 -111
  44. package/types/__tests__/Observable TimeChart.d.ts.map +0 -1
  45. package/types/__tests__/index.d.ts +0 -2
  46. package/types/__tests__/index.d.ts.map +0 -1
  47. package/types/__tests__/node.d.ts +0 -2
  48. package/types/__tests__/node.d.ts.map +0 -1
  49. package/types/compiler.d.ts.map +0 -1
  50. package/types/cst.d.ts.map +0 -1
  51. package/types/index.d.ts.map +0 -1
  52. package/types/util.d.ts.map +0 -1
  53. package/types/writer.d.ts.map +0 -1
  54. package/types-3.4/__package__.d.ts +0 -4
  55. package/types-3.4/__tests__/File Attachments.d.ts +0 -110
  56. package/types-3.4/__tests__/Introduction to Imports.d.ts +0 -120
  57. package/types-3.4/__tests__/Observable TimeChart.d.ts +0 -111
  58. package/types-3.4/__tests__/index.d.ts +0 -2
  59. package/types-3.4/__tests__/node.d.ts +0 -2
  60. package/types-3.4/compiler.d.ts +0 -112
  61. package/types-3.4/cst.d.ts +0 -42
  62. package/types-3.4/index.d.ts +0 -5
  63. package/types-3.4/util.d.ts +0 -30
  64. package/types-3.4/writer.d.ts +0 -19
package/src/types.ts ADDED
@@ -0,0 +1,180 @@
1
+ export namespace ohq {
2
+
3
+ // ObservableHQ Notebook Format ---
4
+ export interface Owner {
5
+ id?: string;
6
+ github_login?: string;
7
+ avatar_url?: string;
8
+ login?: string;
9
+ name?: string;
10
+ bio?: string;
11
+ home_url?: string;
12
+ type?: string;
13
+ tier?: string;
14
+ }
15
+
16
+ export interface Creator {
17
+ id?: string;
18
+ github_login?: string;
19
+ avatar_url?: string;
20
+ login?: string;
21
+ name?: string;
22
+ bio?: string;
23
+ home_url?: string;
24
+ tier?: string;
25
+ }
26
+
27
+ export interface Author {
28
+ id?: string;
29
+ avatar_url?: string;
30
+ name?: string;
31
+ login?: string;
32
+ bio?: string;
33
+ home_url?: string;
34
+ github_login?: string;
35
+ tier?: string;
36
+ approved?: boolean;
37
+ description?: string;
38
+ }
39
+
40
+ export interface Owner2 {
41
+ id?: string;
42
+ github_login?: string;
43
+ avatar_url?: string;
44
+ login?: string;
45
+ name?: string;
46
+ bio?: string;
47
+ home_url?: string;
48
+ type?: string;
49
+ tier?: string;
50
+ }
51
+
52
+ export interface Collection {
53
+ id?: string;
54
+ type?: string;
55
+ slug?: string;
56
+ title?: string;
57
+ description?: string;
58
+ update_time?: Date;
59
+ pinned?: boolean;
60
+ ordered?: boolean;
61
+ custom_thumbnail?: any;
62
+ default_thumbnail?: string;
63
+ thumbnail?: string;
64
+ listing_count?: number;
65
+ parent_collection_count?: number;
66
+ owner?: Owner2;
67
+ }
68
+
69
+ export interface File {
70
+ id?: string;
71
+ url: string;
72
+ download_url?: string;
73
+ name: string;
74
+ create_time?: Date;
75
+ status?: string;
76
+ size?: number;
77
+ mime_type?: string;
78
+ content_encoding?: string;
79
+ }
80
+
81
+ export interface User {
82
+ id?: string;
83
+ github_login?: string;
84
+ avatar_url?: string;
85
+ login?: string;
86
+ name?: string;
87
+ bio?: string;
88
+ home_url?: string;
89
+ tier?: string;
90
+ }
91
+
92
+ export interface Comment {
93
+ id?: string;
94
+ content?: string;
95
+ node_id?: number;
96
+ create_time?: Date;
97
+ update_time?: any;
98
+ resolved?: boolean;
99
+ user?: User;
100
+ }
101
+
102
+ export interface Node {
103
+ id: string | number;
104
+ mode: string;
105
+ value: string;
106
+ pinned?: boolean; // Show source code?
107
+ data?: any;
108
+ name?: string;
109
+ // NodeEx ---
110
+ start?: number;
111
+ end?: number;
112
+ private?: boolean;
113
+ outputs?: string[];
114
+ }
115
+
116
+ export interface Notebook {
117
+ id?: string;
118
+ slug?: any;
119
+ trashed?: boolean;
120
+ description?: string;
121
+ likes?: number;
122
+ publish_level?: string;
123
+ forks?: number;
124
+ fork_of?: any;
125
+ update_time?: Date;
126
+ publish_time?: Date;
127
+ publish_version?: number;
128
+ latest_version?: number;
129
+ thumbnail?: string;
130
+ default_thumbnail?: string;
131
+ roles?: any[];
132
+ sharing?: any;
133
+ owner?: Owner;
134
+ creator?: Creator;
135
+ authors?: Author[];
136
+ collections?: Collection[];
137
+ files: File[];
138
+ comments?: Comment[];
139
+ commenting_lock?: any;
140
+ suggestion_from?: any;
141
+ suggestions_to?: any[];
142
+ version?: number;
143
+ title?: string;
144
+ license?: string;
145
+ copyright?: string;
146
+ nodes: Node[];
147
+ resolutions?: any[];
148
+ }
149
+
150
+ // @observablehq/runtime API ---
151
+ export type InspectorFactory = (name?: string) => Inspector;
152
+
153
+ export interface Inspector {
154
+ _node?: HTMLDivElement;
155
+ pending();
156
+ fulfilled(value);
157
+ rejected(error);
158
+ }
159
+
160
+ export interface Runtime {
161
+ fileAttachments(func: (name: string) => ohq.File): any;
162
+ module(define?, inspector?: InspectorFactory): Module;
163
+ dispose(): void;
164
+ }
165
+
166
+ export interface Module {
167
+ derive(specifiers: string[] | { name: string, alias: string }[], source: any);
168
+ import(name: string, alias: string | undefined, mod: Module): Variable;
169
+ builtin(name: string, _: any);
170
+ variable(inspector?: Inspector): Variable;
171
+ value(name: string): Promise<any>;
172
+ }
173
+
174
+ export interface Variable {
175
+ delete();
176
+ define(name?: string, inputs?: string[], definition?: any);
177
+ import(name: string, otherModule: ohq.Module);
178
+ import(name: string, alias: string, otherModule: ohq.Module);
179
+ }
180
+ }
package/src/util.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { ohq } from "@hpcc-js/observable-shim";
2
- import { parseCell, splitModule } from "@hpcc-js/observable-shim";
1
+ import type { ohq } from "./observable-shim.ts";
2
+ import { parseCell, splitModule } from "./observable-shim.ts";
3
3
 
4
4
  const FuncTypes = {
5
5
  functionType: Object.getPrototypeOf(function () { }).constructor,
@@ -41,7 +41,7 @@ export function createFunction(refs: Refs, async = false, generator = false, blo
41
41
  `return (\n${body}\n);`);
42
42
  }
43
43
 
44
- function join(baseURL, relativeURL) {
44
+ function join(baseURL: string, relativeURL: string) {
45
45
  return relativeURL
46
46
  ? baseURL.replace(/\/+$/, "") + "/" + relativeURL.replace(/^\/+/, "")
47
47
  : baseURL;
@@ -159,6 +159,9 @@ export function omd2notebook(omd: string): ohq.Notebook {
159
159
 
160
160
  export function fetchEx(url: string, proxyPrefix = "https://api.codetabs.com/v1/proxy/?quest=", proxyPostfix = "") {
161
161
  const matches = url.match(/^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img);
162
+ if (!matches || matches.length === 0) {
163
+ throw new Error(`Invalid URL: ${url}`);
164
+ }
162
165
  return fetch(url, { headers: { origin: matches[0], referer: url } }).then(response => {
163
166
  if (response.ok) return response;
164
167
  throw new Error("CORS?");
package/src/writer.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { ohq } from "@hpcc-js/observable-shim";
2
- import { ParsedImportCell, ParsedVariable } from "./cst";
1
+ import { ohq } from "./observable-shim.ts";
2
+ import { ParsedImportCell, ParsedVariable } from "./cst.ts";
3
3
 
4
4
  export class Writer {
5
5
 
@@ -43,14 +43,16 @@ export default function define(runtime, observer) {
43
43
  }
44
44
 
45
45
  importDefine(imp: Partial<ParsedImportCell>) {
46
- const injections = imp.injections.map(inj => {
46
+ const impInjections = imp.injections ?? [];
47
+ const injections = impInjections.map(inj => {
47
48
  return inj.name === inj.alias ?
48
49
  `"${inj.name}"` :
49
50
  `{name: "${inj.name}", alias: "${inj.alias}"}`;
50
51
  });
51
- const derive = imp.injections.length ? `.derive([${injections.join(", ")}], main)` : "";
52
+ const derive = impInjections.length ? `.derive([${injections.join(", ")}], main)` : "";
52
53
  this._defines.push(`const child${this._defineUid} = runtime.module(define${this._defineUid})${derive};`);
53
- imp.specifiers.forEach(s => {
54
+ const impSpecifiers = imp.specifiers ?? [];
55
+ impSpecifiers.forEach(s => {
54
56
  this._defines.push(`main.import("${s.name}"${s.alias && s.alias !== s.name ? `, "${s.alias}"` : ""}, child${this._defineUid}); `);
55
57
  });
56
58
  }
@@ -67,7 +69,8 @@ export default function define(runtime, observer) {
67
69
  funcId = funcId ?? variable.id;
68
70
  const observe = observable ? `.variable(observer(${variable.id ? JSON.stringify(variable.id) : ""}))` : "";
69
71
  const id = variable.id ? `${JSON.stringify(variable.id)}, ` : "";
70
- const inputs = variable.inputs.length ? `[${variable.inputs.map(i => JSON.stringify(i)).join(", ")}], ` : "";
72
+ const variableInputs = variable.inputs ?? [];
73
+ const inputs = variableInputs.length ? `[${variableInputs.map(i => JSON.stringify(i)).join(", ")}], ` : "";
71
74
  const func = inlineFunc ?
72
75
  variable.func?.toString() :
73
76
  funcId;
@@ -1,11 +1,11 @@
1
- import { ohq } from "@hpcc-js/observable-shim";
2
- import { Writer } from "./writer";
1
+ import { ohq } from "./observable-shim.ts";
2
+ import { Writer } from "./writer.ts";
3
3
  export type InspectorFactoryEx = (name: string | undefined, id: string | number) => Inspector;
4
4
  export interface Inspector {
5
5
  _node?: HTMLDivElement;
6
- pending(): any;
7
- fulfilled(value: any): any;
8
- rejected(error: any): any;
6
+ pending(): void;
7
+ fulfilled(value: any): void;
8
+ rejected(error: Error): void;
9
9
  }
10
10
  declare function createCell(node: ohq.Node, options: CompileOptions): Promise<{
11
11
  (runtime: ohq.Runtime, main: ohq.Module, inspector?: InspectorFactoryEx): void;
@@ -66,7 +66,7 @@ export declare function notebook(_files?: ohq.File[], _cells?: CellFunc[], { bas
66
66
  write(w: Writer): void;
67
67
  }>;
68
68
  set(n: ohq.Node): Promise<CellFunc>;
69
- get(id: string | number): CellFunc;
69
+ get(id: string | number): CellFunc | undefined;
70
70
  delete(id: string | number): boolean;
71
71
  clear(): void;
72
72
  write(w: Writer): void;
@@ -101,7 +101,7 @@ export declare function compile(notebookOrOjs: ohq.Notebook | string, { baseUrl,
101
101
  write(w: Writer): void;
102
102
  }>;
103
103
  set(n: ohq.Node): Promise<CellFunc>;
104
- get(id: string | number): CellFunc;
104
+ get(id: string | number): CellFunc | undefined;
105
105
  delete(id: string | number): boolean;
106
106
  clear(): void;
107
107
  write(w: Writer): void;
@@ -109,4 +109,3 @@ export declare function compile(notebookOrOjs: ohq.Notebook | string, { baseUrl,
109
109
  }>;
110
110
  export type compileFunc = Awaited<ReturnType<typeof compile>>;
111
111
  export {};
112
- //# sourceMappingURL=compiler.d.ts.map
package/types/cst.d.ts CHANGED
@@ -39,4 +39,3 @@ interface ParsedVariableCell extends ParsedCell {
39
39
  }
40
40
  export declare function parseCell(cellStr: string, baseUrl: string): ParsedImportCell | ParsedViewCell | ParsedMutableCell | ParsedVariableCell;
41
41
  export {};
42
- //# sourceMappingURL=cst.d.ts.map
package/types/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export type { ohq } from "@hpcc-js/observable-shim";
2
- export * from "./compiler";
3
- export { ojs2notebook, omd2notebook, download } from "./util";
1
+ export type { ohq } from "./observable-shim.ts";
2
+ export * from "./compiler.ts";
3
+ export { ojs2notebook, omd2notebook, download } from "./util.ts";
4
+ export * from "./writer.ts";
4
5
  import "../src/index.css";
5
- //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ export type { ohq } from "./types.ts";
2
+ export * from "./parse.ts";
@@ -0,0 +1,26 @@
1
+ import { Statement, ModuleDeclaration, Expression as ExpressionBase, Node } from "acorn";
2
+ import { ancestor, RecursiveVisitors, AncestorVisitors } from "acorn-walk";
3
+ export interface MutableExpression extends Node {
4
+ type: "MutableExpression";
5
+ }
6
+ export interface ViewExpression extends Node {
7
+ type: "ViewExpression";
8
+ }
9
+ export type Expression = ExpressionBase | MutableExpression | ViewExpression;
10
+ export declare function parseModule(input: any, { globals }?: {
11
+ globals: any;
12
+ }): any;
13
+ export interface Cell extends Node {
14
+ type: "Cell";
15
+ id: Expression;
16
+ text: string;
17
+ body?: Statement | ModuleDeclaration | Expression;
18
+ references: unknown[];
19
+ async: boolean;
20
+ generator: boolean;
21
+ strict: boolean;
22
+ }
23
+ export declare function splitModule(input: string): Cell[];
24
+ export { Node, ancestor, AncestorVisitors };
25
+ export declare function parseCell(input: string): Cell;
26
+ export declare const walk: RecursiveVisitors<any>;
@@ -0,0 +1,165 @@
1
+ export declare namespace ohq {
2
+ interface Owner {
3
+ id?: string;
4
+ github_login?: string;
5
+ avatar_url?: string;
6
+ login?: string;
7
+ name?: string;
8
+ bio?: string;
9
+ home_url?: string;
10
+ type?: string;
11
+ tier?: string;
12
+ }
13
+ interface Creator {
14
+ id?: string;
15
+ github_login?: string;
16
+ avatar_url?: string;
17
+ login?: string;
18
+ name?: string;
19
+ bio?: string;
20
+ home_url?: string;
21
+ tier?: string;
22
+ }
23
+ interface Author {
24
+ id?: string;
25
+ avatar_url?: string;
26
+ name?: string;
27
+ login?: string;
28
+ bio?: string;
29
+ home_url?: string;
30
+ github_login?: string;
31
+ tier?: string;
32
+ approved?: boolean;
33
+ description?: string;
34
+ }
35
+ interface Owner2 {
36
+ id?: string;
37
+ github_login?: string;
38
+ avatar_url?: string;
39
+ login?: string;
40
+ name?: string;
41
+ bio?: string;
42
+ home_url?: string;
43
+ type?: string;
44
+ tier?: string;
45
+ }
46
+ interface Collection {
47
+ id?: string;
48
+ type?: string;
49
+ slug?: string;
50
+ title?: string;
51
+ description?: string;
52
+ update_time?: Date;
53
+ pinned?: boolean;
54
+ ordered?: boolean;
55
+ custom_thumbnail?: any;
56
+ default_thumbnail?: string;
57
+ thumbnail?: string;
58
+ listing_count?: number;
59
+ parent_collection_count?: number;
60
+ owner?: Owner2;
61
+ }
62
+ interface File {
63
+ id?: string;
64
+ url: string;
65
+ download_url?: string;
66
+ name: string;
67
+ create_time?: Date;
68
+ status?: string;
69
+ size?: number;
70
+ mime_type?: string;
71
+ content_encoding?: string;
72
+ }
73
+ interface User {
74
+ id?: string;
75
+ github_login?: string;
76
+ avatar_url?: string;
77
+ login?: string;
78
+ name?: string;
79
+ bio?: string;
80
+ home_url?: string;
81
+ tier?: string;
82
+ }
83
+ interface Comment {
84
+ id?: string;
85
+ content?: string;
86
+ node_id?: number;
87
+ create_time?: Date;
88
+ update_time?: any;
89
+ resolved?: boolean;
90
+ user?: User;
91
+ }
92
+ interface Node {
93
+ id: string | number;
94
+ mode: string;
95
+ value: string;
96
+ pinned?: boolean;
97
+ data?: any;
98
+ name?: string;
99
+ start?: number;
100
+ end?: number;
101
+ private?: boolean;
102
+ outputs?: string[];
103
+ }
104
+ interface Notebook {
105
+ id?: string;
106
+ slug?: any;
107
+ trashed?: boolean;
108
+ description?: string;
109
+ likes?: number;
110
+ publish_level?: string;
111
+ forks?: number;
112
+ fork_of?: any;
113
+ update_time?: Date;
114
+ publish_time?: Date;
115
+ publish_version?: number;
116
+ latest_version?: number;
117
+ thumbnail?: string;
118
+ default_thumbnail?: string;
119
+ roles?: any[];
120
+ sharing?: any;
121
+ owner?: Owner;
122
+ creator?: Creator;
123
+ authors?: Author[];
124
+ collections?: Collection[];
125
+ files: File[];
126
+ comments?: Comment[];
127
+ commenting_lock?: any;
128
+ suggestion_from?: any;
129
+ suggestions_to?: any[];
130
+ version?: number;
131
+ title?: string;
132
+ license?: string;
133
+ copyright?: string;
134
+ nodes: Node[];
135
+ resolutions?: any[];
136
+ }
137
+ type InspectorFactory = (name?: string) => Inspector;
138
+ interface Inspector {
139
+ _node?: HTMLDivElement;
140
+ pending(): any;
141
+ fulfilled(value: any): any;
142
+ rejected(error: any): any;
143
+ }
144
+ interface Runtime {
145
+ fileAttachments(func: (name: string) => ohq.File): any;
146
+ module(define?: any, inspector?: InspectorFactory): Module;
147
+ dispose(): void;
148
+ }
149
+ interface Module {
150
+ derive(specifiers: string[] | {
151
+ name: string;
152
+ alias: string;
153
+ }[], source: any): any;
154
+ import(name: string, alias: string | undefined, mod: Module): Variable;
155
+ builtin(name: string, _: any): any;
156
+ variable(inspector?: Inspector): Variable;
157
+ value(name: string): Promise<any>;
158
+ }
159
+ interface Variable {
160
+ delete(): any;
161
+ define(name?: string, inputs?: string[], definition?: any): any;
162
+ import(name: string, otherModule: ohq.Module): any;
163
+ import(name: string, alias: string, otherModule: ohq.Module): any;
164
+ }
165
+ }
package/types/util.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ohq } from "@hpcc-js/observable-shim";
1
+ import type { ohq } from "./observable-shim.ts";
2
2
  interface Ref {
3
3
  start: number;
4
4
  end: number;
@@ -11,7 +11,7 @@ export interface Refs {
11
11
  }
12
12
  export declare function createFunction(refs: Refs, async?: boolean, generator?: boolean, blockStatement?: boolean, body?: string): any;
13
13
  export declare const isRelativePath: (path: string) => boolean;
14
- export declare const fixRelativeUrl: (path: string, basePath: string) => any;
14
+ export declare const fixRelativeUrl: (path: string, basePath: string) => string;
15
15
  export declare function obfuscatedImport(url: string): Promise<any>;
16
16
  interface ParsedOJS {
17
17
  ojs: string;
@@ -27,4 +27,3 @@ export declare function omd2notebook(omd: string): ohq.Notebook;
27
27
  export declare function fetchEx(url: string, proxyPrefix?: string, proxyPostfix?: string): Promise<Response>;
28
28
  export declare function download(impUrl: string, proxyPrefix?: string, proxyPostfix?: string): Promise<ohq.Notebook>;
29
29
  export {};
30
- //# sourceMappingURL=util.d.ts.map
package/types/writer.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { ohq } from "@hpcc-js/observable-shim";
2
- import { ParsedImportCell, ParsedVariable } from "./cst";
1
+ import { ohq } from "./observable-shim.ts";
2
+ import { ParsedImportCell, ParsedVariable } from "./cst.ts";
3
3
  export declare class Writer {
4
4
  protected _files: ohq.File[];
5
5
  protected _imports: string[];
@@ -16,4 +16,3 @@ export declare class Writer {
16
16
  define(variable: Partial<ParsedVariable>, observable?: boolean, inlineFunc?: boolean, funcId?: string): void;
17
17
  error(msg: string): void;
18
18
  }
19
- //# sourceMappingURL=writer.d.ts.map
@@ -1 +0,0 @@
1
- @import url("https://fonts.googleapis.com/css2?family=Source+Serif+Pro:ital,wght@0,400;0,600;0,700;1,400;1,600;1,700&display=swap");:root{--syntax-normal:#1b1e23;--syntax-comment:#828282;--syntax-number:#20a5ba;--syntax-keyword:#c30771;--syntax-atom:#10a778;--syntax-string:#008ec4;--syntax-error:#ffbedc;--syntax-unknown-variable:#838383;--syntax-known-variable:#005f87;--syntax-matchbracket:#20bbfc;--syntax-key:#6636b4;--mono-fonts:82%/1.5 Menlo,Consolas,monospace}.observablehq--collapsed,.observablehq--expanded,.observablehq--function,.observablehq--gray,.observablehq--import,.observablehq--string:after,.observablehq--string:before{color:var(--syntax-normal)}.observablehq--collapsed,.observablehq--expanded.observablehq--inspect a{cursor:pointer}.observablehq--field{margin-left:1em;text-indent:-1em}.observablehq--empty{color:var(--syntax_comment)}.observablehq--blue,.observablehq--keyword,a[href]{color:#3182bd}.hljs-deletion,.hljs-variable,.observablehq--forbidden,.observablehq--pink{color:#e377c2}.observablehq--orange{color:#e6550d}.hljs-literal,.observablehq--boolean,.observablehq--null,.observablehq--undefined{color:var(--syntax-atom)}.hljs-bullet,.hljs-link,.hljs-number,.hljs-regexp,.observablehq--bigint,.observablehq--date,.observablehq--green,.observablehq--number,.observablehq--regexp,.observablehq--symbol{color:var(--syntax-number)}.observablehq--index,.observablehq--key{color:var(--syntax-key)}.observablehq--prototype-key{color:#aaa}.observablehq--empty{font-style:oblique}.hljs-addition,.hljs-meta,.hljs-string,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.observablehq--purple,.observablehq--string{color:var(--syntax-string)}.observablehq--error,.observablehq--red{color:#e7040f}.observablehq--inspect,.observablehq:empty:after,.observablehq>link:only-child,.observablehq>style:only-child{display:block;font:var(--monospace-font);overflow-x:auto;padding:4px 0;white-space:pre}.observablehq--error .observablehq--inspect{white-space:pre-wrap;word-break:break-all}:root{--syntax-diff:#24292e;--syntax-diff-bg:#fff;--hr:rgba(0,0,0,.05);--monospace:Menlo,Consolas,monospace;--monospace-font:14px/1.5 var(--monospace);--serif:"Source Serif Pro","Iowan Old Style","Apple Garamond","Palatino Linotype","Times New Roman","Droid Serif",Times,serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--sans-serif:-apple-system,BlinkMacSystemFont,"avenir next",avenir,helvetica,"helvetica neue",ubuntu,roboto,noto,"segoe ui",arial,sans-serif}html{-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:#1b1e23;font:17px/1.5 var(--serif)}body{margin:0 14px}body.fullscreen{margin:0}h1,h2,h3,h4,h5,h6{color:#333;font-weight:700;line-height:1.15;margin-bottom:.25rem;margin-top:0}h2~p,h2~table,h3~p,h3~table,h4~p,h4~table{margin-top:0}.observablehq:first-of-type h1+h2{font-size:20px;font-style:italic;font-weight:400;margin-bottom:1rem}a[href]{text-decoration:none}a[href]:hover{text-decoration:underline}h1 code,h2 code,h3 code,h4 code,h5 code,h6 code{font-size:90%}code,pre,tt{font-family:var(--monospace);font-size:14px;line-height:1.5}img{max-width:calc(100vw - 28px)}.katex-display,figcaption,figure,h1,h2,h3,h4,h5,h6,p,table{max-width:640px}blockquote,ol,ul{max-width:600px}blockquote{margin:1rem 1.5rem}ol,ul{padding-left:28px}hr{background:no-repeat 50%/100% 1px linear-gradient(to right,var(--hr),var(--hr));border:none;height:1px;margin:1rem 0;padding:1rem 0}pre{padding:2px 0}.observablehq--md-pre{overflow-x:auto}input:not([type]),input[type=email],input[type=number],input[type=password],input[type=range],input[type=search],input[type=tel],input[type=text],input[type=url]{width:240px}button,canvas,input{vertical-align:middle}button,input,textarea{accent-color:#3b5fc0}table{border-collapse:collapse;font:13px/1.2 var(--sans-serif);width:100%}table code,table pre,table tt{font-size:inherit;line-height:inherit}td>pre:only-child,th>pre:only-child{margin:0;padding:0}th{color:#111;text-align:left;vertical-align:bottom}td{color:#444;vertical-align:top}td,th{padding:3px 6.5px 3px 0}td:last-child,th:last-child{padding-right:0}tr:not(:last-child){border-bottom:1px solid #eee}thead tr{border-bottom:1px solid #ccc}figure,table{margin:1rem 0}figure img{max-width:100%}figcaption{color:var(--syntax-unknown-variable);font:small var(--sans-serif)}.observablehq--caret{margin-right:4px;vertical-align:baseline}.observablehq--field{margin-left:1rem;text-indent:-1rem}.hljs-comment,.observablehq--empty,.observablehq--prototype-key{color:var(--syntax-comment)}.hljs-built_in{color:var(--syntax-known-variable)}.observablehq--unknown{color:var(--syntax-unknown-variable)}.hljs-doctag,.hljs-keyword,.hljs-name,.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-selector-tag,.hljs-strong,.hljs-tag,.hljs-type{color:var(--syntax-keyword)}.observablehq{margin:17px 0;min-height:1.5rem;position:relative}.observablehq:before{bottom:1px;content:"";left:-14px;position:absolute;top:0;transition:background-color .25s linear;width:4px}.observablehq--changed:before,.observablehq--running:before{background-color:#a9b0bc;transition:none}.observablehq--error:before{background-color:#e7040f}.observablehq:not(.observablehq--running):empty:after{color:var(--syntax-comment);content:"<detached>";font-style:oblique}.observablehq>link:only-child,.observablehq>style:only-child{color:var(--syntax-keyword);visibility:hidden;white-space:nowrap}.observablehq>link:only-child:before{content:"<link>";pointer-events:none;text-decoration:none;visibility:visible}.observablehq>style:only-child:before{content:"<style>";visibility:visible}.observablehq--inspect.observablehq--import{white-space:normal}.observablehq--inspect::-webkit-scrollbar{display:none}.observablehq--string-expand{background:#eee;border-radius:2px;color:var(--syntax-normal);cursor:pointer;font-size:80%;margin-left:6px;padding:2px 6px;position:sticky;right:0;vertical-align:middle}.observablehq--string-expand:active,.observablehq--string-expand:hover{background:#ddd}