@netnodeag/kraftwerk 0.52.0 → 0.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -192,7 +192,9 @@ run-artifact directory (default `output/`), `knowledge:` the OKF bundle root
192
192
  (default `knowledge/`), and `agents:` the agent-definition root (default
193
193
  `agents/`). `repos:` turns on the [repositories](#repositories) folder.
194
194
  `public:` and `tunnel:` expose the inspector through a
195
- [Cloudflare Tunnel](#inspector-through-a-cloudflare-tunnel).
195
+ [Cloudflare Tunnel](#inspector-through-a-cloudflare-tunnel). `cloud:`
196
+ tunes (or turns off) the registration with the
197
+ [kraftwerk cloud](#inspector-in-the-kraftwerk-cloud), which is on by default.
196
198
 
197
199
  A `.env` next to kraftwerk.yml (`KEY=value` lines, `#` comments, quotes)
198
200
  is loaded into every kraftwerk process at start: `kraftwerk ui` and the
@@ -404,6 +406,39 @@ Quick tunnels (`trycloudflare.com`) are deliberately not supported: Access
404
406
  cannot be attached to them, which would leave the UI open to anyone with
405
407
  the URL.
406
408
 
409
+ ### Inspector in the kraftwerk cloud
410
+
411
+ The kraftwerk cloud is the `~/.kraftwerk` registry made reachable over the
412
+ internet: every `kraftwerk ui` registers there when it starts and sends a
413
+ heartbeat while it runs, so you can see from anywhere which of your
414
+ workspaces are up, on which machine, with which agents — and an admin sees
415
+ every instance at once. **This is on by default.** The record carries the
416
+ workspace name, icon and colour, the machine, the root, the version, the
417
+ public URL if there is one, and the agent and channel roster. Registration
418
+ is best-effort: a cloud that is down never affects the UI.
419
+
420
+ No key goes into kraftwerk.yml. The cloud hands the instance an identity
421
+ (kept under `~/.kraftwerk/cloud/`, so a restart updates the record) and a
422
+ **claim code**, shown under Settings → Cloud in the UI. Sign in at the
423
+ cloud, type the code (or follow the "claim in the cloud" link), and the
424
+ workspace appears under *My instances*; the instance learns about the claim
425
+ with its next heartbeat.
426
+
427
+ ```yaml
428
+ cloud:
429
+ url: https://srv.kraftwerk-cloud.netnode.cloud # default
430
+ interval: 60 # seconds between heartbeats (default 60)
431
+ enabled: false # opt out of the cloud for this workspace
432
+ ```
433
+
434
+ `KRAFTWERK_CLOUD_URL` in the environment wins over the file (`off` turns the
435
+ feature off everywhere — what the test suites set). A server that starts
436
+ unattended and should register under an account without a claim puts an
437
+ account token from the cloud UI into `.env` as `KRAFTWERK_CLOUD_TOKEN`; a
438
+ `token:` key in kraftwerk.yml is refused. `/api/meta` reports the
439
+ connection state and the claim code; `kraftwerk doctor` prints what the
440
+ block will do.
441
+
407
442
  ## Projects
408
443
 
409
444
  Turn on `projects:` in `kraftwerk.yml` (or the checkbox in settings) and
@@ -2,7 +2,7 @@ import { spawnSync } from "node:child_process";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import chalk from "chalk";
5
- import { ignoreEntryFor, isDir, publicHostFor, reposRootFor, resolveProject, tunnelFor } from "../config.js";
5
+ import { cloudFor, ignoreEntryFor, isDir, publicHostFor, reposRootFor, resolveProject, tunnelFor } from "../config.js";
6
6
  import { discoverWorkflows } from "../discover.js";
7
7
  import { missingEnv } from "../yaml.js";
8
8
  import { applyDotenv, DOTENV_FILE } from "../dotenv.js";
@@ -167,6 +167,16 @@ export async function runDoctor(cwd) {
167
167
  else
168
168
  report("warn", "tunnel without access", "the UI has no login of its own — put a Cloudflare Access policy on the hostname and set tunnel.access so a removed policy fails closed");
169
169
  }
170
+ // Cloud manager: registration is best-effort at runtime, so doctor only says what would happen.
171
+ const cloud = cloudFor(project);
172
+ if (cloud) {
173
+ report("ok", `cloud: ${cloud.url}`, cloud.token
174
+ ? `registers under your kraftwerk account (KRAFTWERK_CLOUD_TOKEN), heartbeat every ${cloud.interval}s`
175
+ : `on by default — the UI shows a claim code under Settings → Cloud; opt out with cloud.enabled: false`);
176
+ }
177
+ else {
178
+ report("info", "cloud: off", process.env.KRAFTWERK_CLOUD_URL?.trim().toLowerCase() === "off" ? "KRAFTWERK_CLOUD_URL=off" : "cloud.enabled: false in kraftwerk.yml");
179
+ }
170
180
  const found = project.workflowsRoot ? await discoverWorkflows(cwd) : [];
171
181
  if (!project.workflowsRoot) {
172
182
  report("warn", "no workflows root", "expected src/workflows/ or workflows/ — `kraftwerk init` scaffolds one");
package/dist/config.d.ts CHANGED
@@ -38,6 +38,11 @@
38
38
  * access: # verify the Cloudflare Access login on every request that arrives via `public`
39
39
  * team: acme # Zero Trust team name (https://<team>.cloudflareaccess.com)
40
40
  * aud: 4714c135… # Application Audience tag of the Access application
41
+ * cloud: # kraftwerk cloud manager — ON BY DEFAULT, `enabled: false` opts out
42
+ * url: https://srv.kraftwerk-cloud.netnode.cloud # where the cloud answers (default). KRAFTWERK_CLOUD_URL env wins; "off" disables
43
+ * interval: 60 # seconds between heartbeats. Default: 60
44
+ * # No key here: the cloud hands the instance its identity and a claim code (Settings → Cloud in the UI);
45
+ * # a server that should register under an account unattended puts KRAFTWERK_CLOUD_TOKEN into .env.
41
46
  */
42
47
  /** Stable, versionless URL of the workflow JSON schema (editor validation). */
43
48
  export declare const SCHEMA_URL = "https://raw.githubusercontent.com/NETNODEAG/kraftwerk/main/kraftwerk/schema/workflow.schema.json";
@@ -154,6 +159,36 @@ export interface TunnelConfig {
154
159
  /** Verify the Cloudflare Access token on every request that arrives via `public`. */
155
160
  access?: AccessConfig;
156
161
  }
162
+ /**
163
+ * Cloud manager: the kraftwerk cloud is ~/.kraftwerk made reachable over
164
+ * the internet — a registry of instances across machines. Every inspector
165
+ * registers on start and heartbeats while it runs, so the cloud's global
166
+ * view shows this workspace, where it runs, and whether it is live; the
167
+ * user claims it into their account with the code the UI shows. On by
168
+ * default: an absent block is the same as a bare one, `enabled: false`
169
+ * opts out, and so does KRAFTWERK_CLOUD_URL=off in the environment (what
170
+ * the tests and CI set). No credential lives in kraftwerk.yml — the
171
+ * identity comes from the cloud, and an account token for unattended
172
+ * servers is KRAFTWERK_CLOUD_TOKEN in .env.
173
+ */
174
+ export interface CloudConfig {
175
+ /** false turns the feature off. Default: true. */
176
+ enabled?: boolean;
177
+ /** Origin of the cloud manager. Default: https://srv.kraftwerk-cloud.netnode.cloud */
178
+ url?: string;
179
+ /** Seconds between heartbeats. Default: 60 (the cloud may raise it). */
180
+ interval?: number;
181
+ }
182
+ export declare const CLOUD_DEFAULT_URL = "https://srv.kraftwerk-cloud.netnode.cloud";
183
+ export declare const CLOUD_DEFAULT_INTERVAL = 60;
184
+ export interface CloudSettings {
185
+ url: string;
186
+ interval: number;
187
+ /** KRAFTWERK_CLOUD_TOKEN from the environment (.env), when set. */
188
+ token?: string;
189
+ }
190
+ /** The effective cloud settings when the feature is on; undefined when kraftwerk.yml or the environment turned it off. */
191
+ export declare function cloudFor(project: Project): CloudSettings | undefined;
157
192
  /** The public hostname (lowercase, no port) when `public` is set, undefined otherwise. */
158
193
  export declare function publicHostFor(project: Project): string | undefined;
159
194
  /** The public origin ("https://kw.example.com") when `public` is set, undefined otherwise. */
@@ -212,6 +247,8 @@ export interface ProjectConfig {
212
247
  public?: string;
213
248
  /** Cloudflare Tunnel run alongside the inspector. Absent = off. */
214
249
  tunnel?: TunnelConfig;
250
+ /** kraftwerk cloud manager this instance registers with. Absent = on with defaults; `enabled: false` opts out. */
251
+ cloud?: CloudConfig;
215
252
  }
216
253
  export interface Project {
217
254
  /** Absolute project root the CLI operates on. */
package/dist/config.js CHANGED
@@ -42,6 +42,11 @@ import { parse } from "yaml";
42
42
  * access: # verify the Cloudflare Access login on every request that arrives via `public`
43
43
  * team: acme # Zero Trust team name (https://<team>.cloudflareaccess.com)
44
44
  * aud: 4714c135… # Application Audience tag of the Access application
45
+ * cloud: # kraftwerk cloud manager — ON BY DEFAULT, `enabled: false` opts out
46
+ * url: https://srv.kraftwerk-cloud.netnode.cloud # where the cloud answers (default). KRAFTWERK_CLOUD_URL env wins; "off" disables
47
+ * interval: 60 # seconds between heartbeats. Default: 60
48
+ * # No key here: the cloud hands the instance its identity and a claim code (Settings → Cloud in the UI);
49
+ * # a server that should register under an account unattended puts KRAFTWERK_CLOUD_TOKEN into .env.
45
50
  */
46
51
  /** Stable, versionless URL of the workflow JSON schema (editor validation). */
47
52
  export const SCHEMA_URL = "https://raw.githubusercontent.com/NETNODEAG/kraftwerk/main/kraftwerk/schema/workflow.schema.json";
@@ -95,6 +100,20 @@ export function projectsRootFor(project) {
95
100
  return undefined;
96
101
  return path.resolve(project.root, p.root ?? PROJECTS_DEFAULT_ROOT);
97
102
  }
103
+ export const CLOUD_DEFAULT_URL = "https://srv.kraftwerk-cloud.netnode.cloud";
104
+ export const CLOUD_DEFAULT_INTERVAL = 60;
105
+ /** The effective cloud settings when the feature is on; undefined when kraftwerk.yml or the environment turned it off. */
106
+ export function cloudFor(project) {
107
+ const c = project.config.cloud ?? {};
108
+ const envUrl = process.env.KRAFTWERK_CLOUD_URL?.trim();
109
+ if (c.enabled === false || envUrl?.toLowerCase() === "off")
110
+ return undefined;
111
+ return {
112
+ url: (envUrl || c.url || CLOUD_DEFAULT_URL).replace(/\/+$/, ""),
113
+ interval: c.interval ?? CLOUD_DEFAULT_INTERVAL,
114
+ token: process.env.KRAFTWERK_CLOUD_TOKEN?.trim() || undefined,
115
+ };
116
+ }
98
117
  /** The public hostname (lowercase, no port) when `public` is set, undefined otherwise. */
99
118
  export function publicHostFor(project) {
100
119
  return project.config.public ? parsePublic(project.config.public)?.hostname : undefined;
@@ -198,7 +217,7 @@ export async function resolveProject(cwd) {
198
217
  const root = gitFallback ?? start;
199
218
  return { root, config: {}, outputDir: path.join(root, "output") };
200
219
  }
201
- const KNOWN_KEYS = ["name", "icon", "color", "port", "workflows", "output", "knowledge", "agents", "skills", "switcher", "git", "repos", "vibeables", "projects", "public", "tunnel"];
220
+ const KNOWN_KEYS = ["name", "icon", "color", "port", "workflows", "output", "knowledge", "agents", "skills", "switcher", "git", "repos", "vibeables", "projects", "public", "tunnel", "cloud"];
202
221
  async function loadConfig(configPath) {
203
222
  let raw;
204
223
  try {
@@ -264,6 +283,11 @@ async function loadConfig(configPath) {
264
283
  config[key] = {};
265
284
  validateTunnel(configPath, config[key]);
266
285
  }
286
+ else if (key === "cloud") {
287
+ if (config[key] === null)
288
+ config[key] = {};
289
+ validateCloud(configPath, config[key]);
290
+ }
267
291
  else if (typeof config[key] !== "string") {
268
292
  throw new Error(`${path.basename(configPath)}: ${key} must be a string`);
269
293
  }
@@ -312,6 +336,38 @@ function validateTunnel(configPath, value) {
312
336
  }
313
337
  }
314
338
  }
339
+ /** cloud: { enabled?, url?, interval? } */
340
+ function validateCloud(configPath, value) {
341
+ const file = path.basename(configPath);
342
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
343
+ throw new Error(`${file}: cloud must be a mapping (enabled, url, interval)`);
344
+ }
345
+ const c = value;
346
+ for (const key of Object.keys(c)) {
347
+ if (key === "token") {
348
+ throw new Error(`${file}: cloud.token does not belong in kraftwerk.yml — put KRAFTWERK_CLOUD_TOKEN into .env (and only for unattended servers; a workspace with a UI is claimed with its code)`);
349
+ }
350
+ if (!["enabled", "url", "interval"].includes(key)) {
351
+ throw new Error(`${file}: cloud.${key} is unknown (allowed: enabled, url, interval)`);
352
+ }
353
+ }
354
+ if (c.enabled !== undefined && typeof c.enabled !== "boolean") {
355
+ throw new Error(`${file}: cloud.enabled must be true or false`);
356
+ }
357
+ if (c.url !== undefined) {
358
+ let ok = false;
359
+ try {
360
+ const u = new URL(String(c.url));
361
+ ok = typeof c.url === "string" && /^https?:$/.test(u.protocol) && !u.search && !u.hash && !u.username;
362
+ }
363
+ catch { }
364
+ if (!ok)
365
+ throw new Error(`${file}: cloud.url must be an http(s) origin like "https://kraftwerk.start"`);
366
+ }
367
+ if (c.interval !== undefined && (typeof c.interval !== "number" || !Number.isInteger(c.interval) || c.interval < 1)) {
368
+ throw new Error(`${file}: cloud.interval must be a positive integer (seconds between heartbeats)`);
369
+ }
370
+ }
315
371
  function validateSwitcher(configPath, value) {
316
372
  const file = path.basename(configPath);
317
373
  if (!Array.isArray(value)) {
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The cloud manager client: kraftwerk.yml `cloud:` makes this instance
3
+ * register with the kraftwerk cloud when the inspector starts and heartbeat
4
+ * while it runs — the same record ~/.kraftwerk/instances holds locally,
5
+ * kept on a server so an admin (and, with an account token, the user)
6
+ * sees every instance across machines.
7
+ *
8
+ * Identity: the first registration hands out an id + secret, stored under
9
+ * ~/.kraftwerk/cloud/<hash(url, root)>.json and presented on every later
10
+ * call, so a restart updates the record instead of creating a new one.
11
+ * When the cloud does not recognise the id (data reset) it hands out a
12
+ * fresh one and the file is rewritten.
13
+ *
14
+ * Everything is best-effort: a cloud that is down never affects the UI.
15
+ * The status is reported in /api/meta so the UI can show it.
16
+ */
17
+ export type CloudState = "off" | "connecting" | "connected" | "error";
18
+ export interface CloudStatus {
19
+ url: string;
20
+ state: CloudState;
21
+ /** Last error message while connecting or heartbeating. */
22
+ error?: string;
23
+ /** Instance id in the cloud once registered. */
24
+ id?: string;
25
+ /** Email of the linked kraftwerk account, when a token was presented and accepted. */
26
+ account?: string | null;
27
+ /** Effective seconds between heartbeats (the cloud may raise the configured one). */
28
+ interval?: number;
29
+ lastSeen?: string;
30
+ /** XXXX-XXXX the user types into the cloud UI to claim this instance; null once claimed. */
31
+ claimCode?: string | null;
32
+ /** The cloud page that claims this instance after sign-in. */
33
+ claimUrl?: string | null;
34
+ }
35
+ export declare const cloudStatus: () => CloudStatus;
36
+ /**
37
+ * Start the client once the inspector listens. Resolves after the first
38
+ * registration attempt (success or not); the heartbeat loop runs on its
39
+ * own afterwards.
40
+ */
41
+ export declare function startCloudSync(port: number, version: string): Promise<void>;
42
+ /** Stop the heartbeat loop (server close, tests). */
43
+ export declare function stopCloudSync(): void;
44
+ /**
45
+ * Tell the cloud we are going away, so the record flips to "stopped" now
46
+ * instead of after the grace period. Bounded: an exit handler waits for
47
+ * this, and a slow cloud must not hold the process.
48
+ */
49
+ export declare function cloudGoodbye(): Promise<void>;
@@ -0,0 +1,199 @@
1
+ import { createHash } from "node:crypto";
2
+ import { promises as fs } from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { cloudFor, publicUrlFor, resolveProject } from "../config.js";
6
+ import { getProjectRoot } from "./context.js";
7
+ import { listAgents, toSummary } from "./agents.js";
8
+ import { listChannels, toChannelSummary } from "./channels.js";
9
+ import { tildify } from "./instances.js";
10
+ const claimUrlFor = (url, code) => (code ? `${url}/claim/${encodeURIComponent(code)}` : null);
11
+ const REQUEST_TIMEOUT_MS = 8_000;
12
+ const GOODBYE_TIMEOUT_MS = 800;
13
+ let status = { url: "", state: "off" };
14
+ let identity = null;
15
+ let timer = null;
16
+ let stopped = false;
17
+ let lastRoster = "";
18
+ let selfPort = 0;
19
+ let selfVersion = "";
20
+ const startedAt = new Date().toISOString();
21
+ export const cloudStatus = () => status;
22
+ const cloudDir = () => path.join(os.homedir(), ".kraftwerk", "cloud");
23
+ const identityFile = (url, root) => path.join(cloudDir(), `${createHash("sha1").update(`${url}\n${root}`).digest("hex").slice(0, 16)}.json`);
24
+ async function readIdentity(file) {
25
+ try {
26
+ const rec = JSON.parse(await fs.readFile(file, "utf8"));
27
+ return typeof rec.id === "string" && typeof rec.secret === "string" ? { id: rec.id, secret: rec.secret } : null;
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ async function writeIdentity(file, url, root, id) {
34
+ try {
35
+ await fs.mkdir(cloudDir(), { recursive: true });
36
+ await fs.writeFile(file, JSON.stringify({ ...id, url, root, updatedAt: new Date().toISOString() }), { mode: 0o600 });
37
+ }
38
+ catch { } // best-effort — the next start registers again
39
+ }
40
+ /** The agents and channels of this workspace, as the cloud lists them. */
41
+ async function roster() {
42
+ const [agents, channels] = await Promise.all([
43
+ listAgents().then((l) => l.map(toSummary)).catch(() => []),
44
+ listChannels().then((l) => l.map(toChannelSummary)).catch(() => []),
45
+ ]);
46
+ return { agents, channels };
47
+ }
48
+ async function post(url, body, timeout = REQUEST_TIMEOUT_MS) {
49
+ const r = await fetch(url, {
50
+ method: "POST",
51
+ headers: { "content-type": "application/json", "user-agent": `kraftwerk/${selfVersion}` },
52
+ body: JSON.stringify(body),
53
+ signal: AbortSignal.timeout(timeout),
54
+ });
55
+ const text = await r.text();
56
+ let data;
57
+ try {
58
+ data = text ? JSON.parse(text) : {};
59
+ }
60
+ catch {
61
+ throw new Error(`${r.status} from ${url}: not JSON`);
62
+ }
63
+ if (!r.ok)
64
+ throw new Error(data.error ?? `${r.status} from ${url}`);
65
+ return data;
66
+ }
67
+ /** Register (or re-register) this instance. Returns false when the cloud refused or is unreachable. */
68
+ async function register() {
69
+ const project = await resolveProject(getProjectRoot()).catch(() => null);
70
+ const cloud = project ? cloudFor(project) : undefined;
71
+ if (!project || !cloud)
72
+ return false;
73
+ const file = identityFile(cloud.url, project.root);
74
+ identity ??= await readIdentity(file);
75
+ const { agents, channels } = await roster();
76
+ lastRoster = JSON.stringify({ agents, channels });
77
+ const body = {
78
+ ...(identity ?? {}),
79
+ name: project.config.name ?? path.basename(project.root),
80
+ icon: project.config.icon ?? "",
81
+ color: project.config.color ?? "",
82
+ root: project.root,
83
+ rootLabel: tildify(project.root),
84
+ hostname: os.hostname(),
85
+ platform: `${process.platform}-${process.arch}`,
86
+ version: selfVersion,
87
+ url: `http://localhost:${selfPort}`,
88
+ publicUrl: publicUrlFor(project) ?? "",
89
+ agents,
90
+ channels,
91
+ interval: cloud.interval,
92
+ startedAt,
93
+ ...(cloud.token ? { accountToken: cloud.token } : {}),
94
+ };
95
+ try {
96
+ const r = await post(`${cloud.url}/api/instances/register`, body);
97
+ if (!identity || identity.id !== r.id || identity.secret !== r.secret) {
98
+ identity = { id: r.id, secret: r.secret };
99
+ await writeIdentity(file, cloud.url, project.root, identity);
100
+ }
101
+ status = {
102
+ url: cloud.url, state: "connected", id: r.id, account: r.account, interval: r.interval, lastSeen: new Date().toISOString(),
103
+ claimCode: r.claimCode ?? null, claimUrl: claimUrlFor(cloud.url, r.claimCode),
104
+ };
105
+ return true;
106
+ }
107
+ catch (err) {
108
+ status = { url: cloud.url, state: "error", error: err.message, ...(identity ? { id: identity.id } : {}) };
109
+ return false;
110
+ }
111
+ }
112
+ async function heartbeat() {
113
+ if (!identity || status.state === "off")
114
+ return;
115
+ const { agents, channels } = await roster();
116
+ const rosterNow = JSON.stringify({ agents, channels });
117
+ const body = {
118
+ ...identity,
119
+ version: selfVersion,
120
+ ...(rosterNow !== lastRoster ? { agents, channels } : {}),
121
+ };
122
+ try {
123
+ const r = await post(`${status.url}/api/instances/heartbeat`, body);
124
+ lastRoster = rosterNow;
125
+ status = {
126
+ ...status, state: "connected", error: undefined, interval: r.interval, lastSeen: new Date().toISOString(),
127
+ ...(r.account !== undefined ? { account: r.account } : {}),
128
+ ...(r.claimCode !== undefined ? { claimCode: r.claimCode, claimUrl: claimUrlFor(status.url, r.claimCode) } : {}),
129
+ };
130
+ }
131
+ catch (err) {
132
+ const message = err.message;
133
+ status = { ...status, state: "error", error: message };
134
+ // An unknown identity (the cloud lost it) is fixed by registering again, which hands out a new one.
135
+ if (/unknown instance|wrong instance secret|id and secret required/.test(message)) {
136
+ identity = null;
137
+ await register();
138
+ }
139
+ }
140
+ }
141
+ /** Schedule the next tick after the effective interval; a failed cloud is retried at the same cadence. */
142
+ function schedule() {
143
+ if (stopped)
144
+ return;
145
+ const seconds = status.interval && status.interval > 0 ? status.interval : 60;
146
+ timer = setTimeout(async () => {
147
+ if (status.state === "connected" || status.state === "error") {
148
+ if (identity)
149
+ await heartbeat();
150
+ else
151
+ await register();
152
+ }
153
+ schedule();
154
+ }, seconds * 1000);
155
+ timer.unref();
156
+ }
157
+ /**
158
+ * Start the client once the inspector listens. Resolves after the first
159
+ * registration attempt (success or not); the heartbeat loop runs on its
160
+ * own afterwards.
161
+ */
162
+ export async function startCloudSync(port, version) {
163
+ selfPort = port;
164
+ selfVersion = version;
165
+ stopped = false;
166
+ const project = await resolveProject(getProjectRoot()).catch(() => null);
167
+ const cloud = project ? cloudFor(project) : undefined;
168
+ if (!cloud) {
169
+ status = { url: "", state: "off" };
170
+ return;
171
+ }
172
+ status = { url: cloud.url, state: "connecting", interval: cloud.interval };
173
+ await register();
174
+ // Until the cloud answers, retry at the configured cadence; once it does, at what it asked for.
175
+ if (status.state !== "connected")
176
+ status.interval = cloud.interval;
177
+ schedule();
178
+ }
179
+ /** Stop the heartbeat loop (server close, tests). */
180
+ export function stopCloudSync() {
181
+ stopped = true;
182
+ if (timer)
183
+ clearTimeout(timer);
184
+ timer = null;
185
+ }
186
+ /**
187
+ * Tell the cloud we are going away, so the record flips to "stopped" now
188
+ * instead of after the grace period. Bounded: an exit handler waits for
189
+ * this, and a slow cloud must not hold the process.
190
+ */
191
+ export async function cloudGoodbye() {
192
+ stopCloudSync();
193
+ if (!identity || status.state === "off" || !status.url)
194
+ return;
195
+ try {
196
+ await post(`${status.url}/api/instances/goodbye`, identity, GOODBYE_TIMEOUT_MS);
197
+ }
198
+ catch { }
199
+ }
@@ -5,6 +5,7 @@ import { attachmentPath, readMeta, saveAttachment } from "./chat/store.js";
5
5
  import { setOutputDir, setProjectRoot, getOutputDir, getProjectRoot } from "./context.js";
6
6
  import { publicHostFor, publicUrlFor, resolveProject, tunnelFor } from "../config.js";
7
7
  import { ACCESS_HEADER, verifyAccessToken } from "./access.js";
8
+ import { cloudGoodbye, cloudStatus, startCloudSync, stopCloudSync } from "./cloud.js";
8
9
  import { listRuns, getRun, readRunFile, deleteRun, safeRunDir } from "./runs.js";
9
10
  import { decide } from "./decisions.js";
10
11
  import { canSelfUpdate, startUpdate, updateStatus } from "./update.js";
@@ -396,6 +397,7 @@ async function handleApi(req, res, url) {
396
397
  vibeables: (project?.config.vibeables && project.config.vibeables.enabled !== false) === true,
397
398
  projects: (project?.config.projects && project.config.projects.enabled !== false) === true,
398
399
  publicUrl: (project && publicUrlFor(project)) ?? "",
400
+ cloud: cloudStatus(),
399
401
  switcher,
400
402
  });
401
403
  }
@@ -1380,7 +1382,8 @@ export async function startInspector(opts) {
1380
1382
  disposeAllDevs();
1381
1383
  unregisterInstance();
1382
1384
  markWorkspaceStopped();
1383
- process.exit(sig === "SIGINT" ? 130 : 143);
1385
+ // The cloud goodbye is bounded (cloudGoodbye) and a no-op without cloud:, so the exit stays prompt.
1386
+ void cloudGoodbye().finally(() => process.exit(sig === "SIGINT" ? 130 : 143));
1384
1387
  });
1385
1388
  }
1386
1389
  process.once("exit", (code) => {
@@ -1419,11 +1422,13 @@ export async function startInspector(opts) {
1419
1422
  });
1420
1423
  return new Promise((resolve, reject) => {
1421
1424
  server.once("error", reject);
1425
+ server.once("close", stopCloudSync);
1422
1426
  server.listen(opts.port, INSPECTOR_HOST, () => {
1423
1427
  const addr = server.address();
1424
1428
  const port = typeof addr === "object" && addr ? addr.port : opts.port;
1425
1429
  void registerInstance(port, getProjectRoot());
1426
1430
  void registerWorkspace(getProjectRoot());
1431
+ void getPkgVersion().then((v) => startCloudSync(port, v));
1427
1432
  resolve(server);
1428
1433
  });
1429
1434
  });
@@ -1 +1 @@
1
- import{C as e,D as t,F as n,L as r,R as i,Ut as a,V as o,i as s,n as c,r as l,s as u,u as d,v as f,vt as p}from"./dist-H3rerbMg.js";import{n as m}from"./dist-B8oWIJzY.js";var h=1,g=2,_=3,v=155,y=4,b=156;function x(e){return e>=65&&e<=90||e>=97&&e<=122}var S=new c(e=>{let t=e.pos;for(;;){let{next:n}=e;if(n<0)break;if(n==123){let n=e.peek(1);if(n==123){if(e.pos>t)break;e.acceptToken(h,2);return}if(n==35){if(e.pos>t)break;e.acceptToken(g,2);return}if(n==37){if(e.pos>t)break;let n=2,r=2;for(;;){let t=e.peek(n);if(t==32||t==10)++n;else if(t==35)for(++n;;){let t=e.peek(n);if(t<0||t==10)break;n++}else if(t==45&&r==2)r=++n;else{e.acceptToken(_,r);return}}}}if(e.advance(),n==10)break}e.pos>t&&e.acceptToken(v)});function C(e,t,n){return new c(r=>{let i=r.pos;for(;;){let{next:t}=r;if(t==123&&r.peek(1)==37){let t=2;for(;;t++){let e=r.peek(t);if(e!=32&&e!=10)break}let a=``;for(;;t++){let e=r.peek(t);if(!x(e))break;a+=String.fromCharCode(e)}if(a==e){if(r.pos>i)break;r.acceptToken(n,2);break}}else if(t<0)break;if(r.advance(),t==10)break}r.pos>i&&r.acceptToken(t)})}var w=C(`endraw`,b,y),T={__proto__:null,in:38,is:40,and:46,or:48,not:52,if:78,else:80,true:98,false:98,self:100,super:102,loop:104,recursive:136,scoped:160,required:162,as:256,import:260,ignore:268,missing:270,with:272,without:274,context:276},E={__proto__:null,if:112,elif:118,else:122,endif:126,for:132,endfor:140,raw:146,endraw:152,block:158,endblock:166,macro:172,endmacro:182,call:188,endcall:192,filter:198,endfilter:202,set:208,endset:212,trans:218,pluralize:222,endtrans:226,with:232,endwith:236,autoescape:242,endautoescape:246,import:254,from:258,include:266},D=l.deserialize({version:14,states:"!*dQVOPOOOOOP'#F`'#F`OeOTO'#CbOvQSO'#CdO!kOPO'#DcO!yOPO'#DnO#XOQO'#DuO#^OPO'#D{O#lOPO'#ESO#zOPO'#E[O$YOPO'#EaO$hOPO'#EfO$vOPO'#EkO%UOPO'#ErO%dOPO'#EwOOOP'#F|'#F|O%rQWO'#E|O&sO#tO'#F]OOOP'#Fq'#FqOOOP'#F_'#F_QVOPOOOOOP-E9^-E9^OOQO'#Ce'#CeO'sQSO,59OO'zQSO'#DWO(RQSO'#DXO(YQ`O'#DZOOQO'#Fr'#FrOvQSO'#CuO(aOPO'#CbOOOP'#Fd'#FdO!kOPO,59}OOOP,59},59}O(oOPO,59}O(}QWO'#E|OOOP,5:Y,5:YO)[OPO,5:YO!yOPO,5:YO)jQWO'#E|OOOQ'#Ff'#FfO)tOQO'#DxO)|OQO,5:aOOOP,5:g,5:gO#^OPO,5:gO*RQWO'#E|OOOP,5:n,5:nO#lOPO,5:nO*YQWO'#E|OOOP,5:v,5:vO#zOPO,5:vO*aQWO'#E|OOOP,5:{,5:{O$YOPO,5:{O*hQWO'#E|OOOP,5;Q,5;QO$hOPO,5;QO*oQWO'#E|OOOP,5;V,5;VO*vOPO,5;VO$vOPO,5;VO+UQWO'#E|OOOP,5;^,5;^O%UOPO,5;^O+`QWO'#E|OOOP,5;c,5;cO%dOPO,5;cO+gQWO'#E|O+nQSO,5;hOvQSO,5:OO+uQSO,5:ZO+zQSO,5:bO+uQSO,5:hO+uQSO,5:oO,PQSO,5:wO,XQpO,5:|O+uQSO,5;RO,^QSO,5;WO,fQSO,5;_OvQSO,5;dOvQSO,5;jOvQSO,5;jOvQSO,5;pOOOO'#Fk'#FkO,nO#tO,5;wOOOP-E9]-E9]O,vQ!bO,59QOvQSO,59TOvQSO,59UOvQSO,59UOvQSO,59UOvQSO,59UO,{QSO'#C}O,XQpO,59cOOQO,59q,59qOOOP1G.j1G.jOvQSO,59UO-SQSO,59UOvQSO,59UOvQSO,59UOvQSO,59nO-wQSO'#FxO.RQSO,59rO.WQSO,59tOOQO,59s,59sO.bQSO'#D[O.iQWO'#F{O.qQWO,59uO0WQSO,59aOOOP-E9b-E9bOOOP1G/i1G/iO(oOPO1G/iO(oOPO1G/iO)TQWO'#E|OvQSO,5:SO0nQSO,5:UO0sQSO,5:WOOOP1G/t1G/tO)[OPO1G/tO)mQWO'#E|O)[OPO1G/tO0xQSO,5:_OOOQ-E9d-E9dOOOP1G/{1G/{O0}QWO'#DyOOOP1G0R1G0RO1SQSO,5:lOOOP1G0Y1G0YO1[QSO,5:tOOOP1G0b1G0bO1aQSO,5:yOOOP1G0g1G0gO1fQSO,5;OOOOP1G0l1G0lO1kQSO,5;TOOOP1G0q1G0qO*vOPO1G0qO+XQWO'#E|O*vOPO1G0qOvQSO,5;YO1pQSO,5;[OOOP1G0x1G0xO1uQSO,5;aOOOP1G0}1G0}O1zQSO,5;fO2PQSO1G1SOOOP1G1S1G1SO2WQSO1G/jOOQO'#Dq'#DqO2_QSO1G/uOOOQ1G/|1G/|O2gQSO1G0SO2rQSO1G0ZO2zQSO'#EVO3SQSO1G0cO,SQSO1G0cO4fQSO'#FvOOQO'#Fv'#FvO5]QSO1G0hO5bQSO1G0mOOOP1G0r1G0rO5mQSO1G0rO5rQSO'#GOO5zQSO1G0yO6PQSO1G1OO6WQSO1G1UO6_QSO1G1UO6fQSO1G1[OOOO-E9i-E9iOOOP1G1c1G1cOOQO1G.l1G.lO6vQSO1G.oO8wQSO1G.pO:oQSO1G.pO:vQSO1G.pO<nQSO1G.pO<uQSO'#FwO>QQSO'#FrO>XQSO'#FwO>aQSO,59iOOQO1G.}1G.}O>fQSO1G.pO@aQSO1G.pOB_QSO1G.pOBfQSO1G.pOD^QSO1G/YOvQSO'#FbODeQSO,5<dOOQO1G/^1G/^ODmQSO1G/_OOQO1G/`1G/`ODuQSO,59vOvQSO'#FcOEjQWO,5<gOOQO1G/a1G/aPErQWO'#E|OOOP7+%T7+%TO(oOPO7+%TOEyQSO1G/nOOOP1G/p1G/pOOOP1G/r1G/rOOOP7+%`7+%`O)[OPO7+%`OOOP1G/y1G/yOFQQSO,5:eOOOP1G0W1G0WOFVQSO1G0WOOOP1G0`1G0`OOOP1G0e1G0eOOOP1G0j1G0jOOOP1G0o1G0oOOOP7+&]7+&]O*vOPO7+&]OF[QSO1G0tOOOP1G0v1G0vOOOP1G0{1G0{OOOP1G1Q1G1QOOOP7+&n7+&nOOOP7+%U7+%UO+uQSO'#FeOFcQSO7+%aOvQSO7+%aOOOP7+%n7+%nOFkQSO7+%nOFpQSO7+%nOOOP7+%u7+%uOFxQSO7+%uOF}QSO'#F}OGQQSO'#F}OGYQSO,5:qOOOP7+%}7+%}OG_QSO7+%}OGdQSO7+%}OOQO,59f,59fOOOP7+&S7+&SOGlQSO7+&oOOOP7+&X7+&XOvQSO7+&oOvQSO7+&^OGtQSO,5<jOvQSO,5<jOOOP7+&e7+&eOOOP7+&j7+&jO+uQSO7+&pOG|QSO7+&pOOOP7+&v7+&vOHRQSO7+&vOHWQSO7+&vOOQO7+$Z7+$ZOvQSO'#FaOH]QSO,5<cOvQSO,59jOOQO1G/T1G/TOOQO7+$[7+$[OvQSO7+$tOHeQSO,5;|OOQO-E9`-E9`OOQO7+$y7+$yOImQ`O1G/bOIwQSO'#D^OOQO,5;},5;}OOQO-E9a-E9aOOOP<<Ho<<HoOOOP7+%Y7+%YOOOP<<Hz<<HzOOOP1G0P1G0POOOP7+%r7+%rOOOP<<Iw<<IwOOOP7+&`7+&`OOQO,5<P,5<POOQO-E9c-E9cOvQSO<<H{OJOQSO<<H{OOOP<<IY<<IYOJYQSO<<IYOOOP<<Ia<<IaOvQSO,5:rO+uQSO'#FgOJ_QSO,5<iOOQO1G0]1G0]OOOP<<Ii<<IiOJgQSO<<IiOvQSO<<JZOJlQSO<<JZOJsQSO<<IxOvQSO1G2UOJ}QSO1G2UOKXQSO<<J[OK^QSO'#CeOOQO'#FT'#FTOKiQSO'#FTOKnQSO<<J[OKvQSO<<JbOK{QSO<<JbOLWQSO,5;{OLbQSO'#FrOOQO,5;{,5;{OOQO-E9_-E9_OLiQSO1G/UOM}QSO<<H`O! ]Q`O,59aODuQSO,59xO! sQSOAN>gOOOPAN>gAN>gO! }QSOAN>gOOOPAN>tAN>tO!!SQSO1G0^O!!^QSO,5<ROOQO,5<R,5<ROOQO-E9e-E9eOOOPAN?TAN?TO!!iQSOAN?uOOOPAN?uAN?uO+uQSO'#FhO!!pQSOAN?dOOOPAN?dAN?dO!!xQSO7+'pO+uQSO'#FiO!#SQSO7+'pOOOPAN?vAN?vO+uQSO,5;oOG|QSO'#FjO!#[QSOAN?vOOOPAN?|AN?|O!#dQSOAN?|OvQSO,59mO!$sQ`O1G.pO!%{Q`O1G.pO!&SQ`O1G.pO!'[Q`O1G.pO!'cQ`O'#FvO!'jQ`O1G.pO!(uQ`O1G.pO!*TQ`O1G.pO!*[Q`O1G.pO!+dQ`O1G/YO!+kQ`O1G/dOOOPG24RG24RO!+uQSOG24ROvQSO,5:sOOOPG25aG25aO!+zQSO,5<SOOQO-E9f-E9fOOOPG25OG25OO!,PQSO<<K[O!,XQSO,5<TOOQO-E9g-E9gOOQO1G1Z1G1ZOOQO,5<U,5<UOOQO-E9h-E9hOOOPG25bG25bO!,aQSOG25hO!,fQSO1G/XOOOPLD)mLD)mO!,pQSO1G0_OvQSO1G1nO!,zQSO1G1oOvQSO1G1oOOOPLD+SLD+SO!-wQ`O<<H`O!.[QSO7+'YOvQSO7+'ZO!.fQSO7+'ZO!.pQSO<<JuODuQSO'#CuODuQSO,59UODuQSO,59UODuQSO,59UODuQSO,59UO!.zQpO,59cODuQSO,59UO!/PQSO,59UODuQSO,59UODuQSO,59UODuQSO,59nO!/tQSO1G.pP!0RQSO1G/YODuQSO7+$tO!0YQ`O1G.pP!0gQ`O1G/YO-SQSO,59UPvQSO,59nO!0nQSO,59aP!3XQSO1G.pP!3`QSO1G.pP!5aQSO1G/YP!5hQSO<<H`O!/PQSO,59UPDuQSO,59nP!6_QSO1G/YP!7pQ`O1G/YO-SQSO'#CuO-SQSO,59UO-SQSO,59UO-SQSO,59UO-SQSO,59UO-SQSO,59UP-SQSO,59UP-SQSO,59UP-SQSO,59nO!7wQSO1G.pO!9xQSO1G.pO!:PQSO1G.pO!;UQSO1G.pP-SQSO7+$tO!<XQ`O,59aP!>SQ`O1G.pP!>ZQ`O1G.pP!>bQ`O1G/YP!?QQ`O<<H`O!/PQSO'#CuO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UP!/PQSO,59UP!/PQSO,59UP!/PQSO,59nP!/PQSO7+$tP-SQSO,59nP!/PQSO,59nO!?zQ`O1G.pO!@RQ`O1G.pO!@fQ`O1G.pO!@yQ`O1G.p",stateData:"!Ac~O$dOS~OPROQaOR`O$aPO~O$aPOPUXQUXRUX$`UX~OekOfkOjlOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~OPROQaORrO$aPO~OPROQaORvO$aPO~O$bwO~OPROQaOR|O$aPO~OPROQaOR!PO$aPO~OPROQaOR!SO$aPO~OPROQaOR!VO$aPO~OPROQaOR!YO$aPO~OPROQaOR!^O$aPO~OPROQaOR!aO$aPO~OPROQaOR!dO$aPO~O!X!eO!Y!fO!d!gO!k!hO!q!iO!x!jO#Q!kO#V!lO#[!mO#a!nO#h!oO#m!pO#s!qO#u!rO#y!sO~O$s!tO~OZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UOl#OOp!}Ow#VO$i!xO~OV#QO~P&xO$h$lP~PvOo#ZO~PvO$m$oP~PvO$aPOPUXQUXRUX~OPROQaOR#dO$aPO~O!]#eO!_#fO!a#gO~P%rOPROQaOR#jO$aPO~O!_#fO!h#lO~P%rO$bwOS!lX~OS#oO~O!u#qO~P%rO!}#sO~P%rO#S#uO~P%rO#X#wO~P%rO#^#yO~P%rOPROQaOR#|O$aPO~O#c$OO#e$PO~P%rO#j$RO~P%rO#o$TO~P%rO!Z$VO~PvO$g$XO~O!Z$ZO~Op$^O$gfO~Om$aO~O!Z$eO$g$XO~O$g$XO!Z$rP~O$Q$nO$s!tO~O[$oO~Oo$kP~PvOekOfkOj)fOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Ot%PO$h$lX~P&xO$h%RO~Oo%TOt%PO~P&xO!P%UO~P&xOt%VO$m$oX~O$m%XO~OZ!wOp!}O$i!xOViagiahialiawiatia$hiaoia!Pia!Zia#tia#via#zia#|ia#}iaxia!fia~O_!yO`!zOa!{Ob!|Oc#ROd#SO~P.vO!Z%^O~O!Z%_O~O!Z%bO~O!n%cO~O!Z%dO$g$XO~O!Z%fO~O!Z%gO~O!Z%hO~O!Z%iO~O!Z%mO~O!Z%nO~O!Z%oO~O!Z%pO~P&xO!Z%qO~P&xOc%tOt%rO~O!Z%uO!r%wO!s%vO~Op$^O!Z%xO~O$g$XOo$qP~Op!}O!Z%}O~Op!}OZ$jX_$jX`$jXa$jXb$jXc$jXd$jXg$jXh$jXl$jXw$jX$i$jXt$jXe$jXf$jX$g$jXx$jX~O!Z$jXV$jX$h$jXo$jX!P$jX#t$jX#v$jX#z$jX#|$jX#}$jX!f$jX~P3[O!Z&RO~Os&UOt%rO!Z&TO~Os&VO~Os&XOt%rO~O!Z&YO~O!Z&ZO~P&xO#t&[O~P&xO#v&]O~P&xO!Z&^O#z&`O#|&_O#}&_O~P&xO$h&aO~P&xOZ!wOp!}O$i!xOV^i`^ia^ib^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ie^if^i$g^ix^i!f^i~O_^i~P6}OZ!wO_!yOp!}O$i!xOV^ia^ib^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~O`^i~P9OO`!zO~P9OOZ!wO_!yO`!zOa!{Op!}O$i!xOV^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Ob^i~P:}Ot&bOo$kX~P&xOZ$fX_$fX`$fXa$fXb$fXc$fXd$fXg$fXh$fXl$fXo$fXp$fXt$fXw$fX$i$fX~Os&dO~P=POt&bOo$kX~Oo&eO~Ob!|O~P:}OZ!wO_)gO`)hOa)iOb)jOc)kOp!}O$i!xOV^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Oe&fOf&fO$gfO~P>mOZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOp!}O$i!xOV^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Og^i~P@nOg#TO~P@nOZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UOp!}O$i!xOVvilviwvitvi$hviovi!Pvi!Zvi#tvi#vvi#zvi#|vi#}vi!fvi~Ox&gO~PBmOt%PO$h$la~Oo&jOt%PO~OekOfkOj(yOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Ot%VO$m$oa~O!]#eO~P%rO!Z&pO~P&xO!Z&rO~O!Z&sO~O!Z&uO~P&xOc&xOt%rO~O!Z&zO~O!Z&zO!s&{O~O!Z&|O~Os&}Ot'OOo$qX~Oo'QO~O!Z'RO~Op!}O!Z'RO~Os'TOt%rO~Os'WOt%rO~O$g'ZO~O$O'_O~O#{'`O~Ot&bOo$ka~Ot$Ua$h$Uao$Ua~P&xOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOl)OOp!}Ow)TO$i!xO~Ot!Oi$m!Oi~PHrO!P'hO~P&xO!Z'jO!f'kO~P&xO!Z'lO~Ot'OOo$qa~O!Z'qO~O!Z'sO~P&xOt'tO!Z'vO~P&xOt'xO!Z$ri~P&xO!Z'zO~Ot!eX!Z!eX#tXX~O#t'{O~Ot'|O!Z'zO~O!Z(OO~O!Z(OO#|(PO#}(PO~Oo$Tat$Ta~P&xOs(QO~P=POoritri~P&xOZ!wOp!}O$i!xOVvylvywvytvy$hvyovy!Pvy!Zvy#tvy#vvy#zvy#|vy#}vyxvy!fvy~O_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UO~PLsOZ!wOp!}O$i!xOgiahialiatiawia$miaxia~O_(zO`({Oa(|Ob(}Oc)POd)QO~PNkO!Z(^O!f(_O~P&xO!Z(^O~Oo!zit!zi~P&xOs(`Oo$Zat$Za~O!Z(aO~P&xOt'tO!Z(dO~Ot'xO!Z$rq~P&xOt'xO!Z$rq~Ot'|O!Z(kO~O$O(lO~OZ!wOp!}O$i!xO`^ia^ib^ic^id^ig^ih^il^it^iw^i$m^ie^if^i$g^ix^i~O_^i~P!#iOZ!wO_(zOp!}O$i!xOa^ib^ic^id^ig^ih^il^it^iw^i$m^ix^i~O`^i~P!$zO`({O~P!$zOZ!wO_(zO`({Oa(|Op!}O$i!xOc^id^ig^ih^il^it^iw^i$m^ix^i~Ob^i~P!&ZO$m$jX~P3[Ob(}O~P!&ZOZ!wO_)zO`){Oa)|Ob)}Oc*OOp!}O$i!xOd^ig^ih^il^it^iw^i$m^ix^i~Oe&fOf&fO$gfO~P!'qOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOp!}O$i!xOh^il^it^iw^i$m^ix^i~Og^i~P!)SOg)RO~P!)SOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOp!}O$i!xOlvitviwvi$mvi~Ox)WO~P!*cOt!Qi$m!Qi~PHrO!Z(nO~Os(pO~Ot'xO!Z$ry~Os(rOt%rO~O!Z(sO~Oouitui~P&xOo!{it!{i~P&xOs(vOt%rO~OZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOp!}O$i!xO~Olvytvywvy$mvyxvy~P!-SOt$[q!Z$[q~P&xOt$]q!Z$]q~P&xOt$]y!Z$]y~P&xOm(VO~OekOfkOj)yOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Oe^if^i$g^i~P>mOxvi~PBmOe^if^i$g^i~P!'qOxvi~P!*cO_)gO`)hOa)iOb)jOc)kOd)ZOeiafia$gia~P.vOZ!wO_)gO`)hOa)iOb)jOc)kOd)ZOp!}O$i!xOV^ie^if^ih^il^iw^i$g^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Og^i~P!1_Og)lO~P!1_OZ!wO_)gO`)hOa)iOb)jOc)kOd)ZOg)lOh)mOp!}O$i!xOVvievifvilviwvi$gvitvi$hviovi!Pvi!Zvi#tvi#vvi#zvi#|vi#}vi!fvi~Ox)sO~P!3gO_)gO`)hOa)iOb)jOc)kOd)ZOg)lOh)mOevyfvy$gvy~PLsOxvi~P!3gOZ!wO_)zO`){Oa)|Ob)}Oc*OOd)bOg*POh*QOp!}O$i!xOevifvilvitviwvi$gvi$mvi~Oxvi~P!6fO_)gO~P6}OZ!wO_)gO`)hOp!}O$i!xOV^ib^ic^id^ie^if^ig^ih^il^iw^i$g^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Oa^i~P!8OOa)iO~P!8OOZ!wOp!}O$i!xOc^id^ie^if^ig^ih^il^iw^i$g^it^ix^i~O_)gO`)hOa)iOb)jOV^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^i!f^i~P!:WO_)zO`){Oa)|Ob)}Oc*OOd)bOeiafia$gia~PNkOZ!wO_)zO`){Oa)|Ob)}Oc*OOd)bOp!}O$i!xOe^if^ih^il^it^iw^i$g^i$m^ix^i~Og^i~P!<xOg*PO~P!<xOx*SO~P!6fOZ!wO_)zO`){Oa)|Ob)}Op!}O$i!xO~Oc*OOd)bOg*POh*QOevyfvylvytvywvy$gvy$mvyxvy~P!>iO_)zO~P!#iO_)zO`){Oa^ib^i$m^i~P!:WO_)zO`){Oa)|Ob^i$m^i~P!:WO_)zO`){Oa)|Ob)}O$m^i~P!:WOfaZa~",goto:"Cy$sPPPPPP$tP$t%j'sPP's'sPPPPPPPPPP'sP'sPP)jPP)o+nPP+q'sPP's's's's's+tP+wPPPP+z,pPPP-fP-jP-vP+z.UP.zP/zP+z0YP1O1RP+z1UPPP1zP+z2QP2v2|3P3SP+z3YP4OP+z4UP4zP+z5QP5vP+z5|P6rP6xP+z7WP7|P+z8SP8xP$t$t$tPPPP9O$tPPPPPP$tP9U:j;f;m;w;}<T<g<m<t<z=U=[PPPPP=b>YPPPCcCjCmPPCp$tCsCv!gbOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%k$dkRhijl!e!f!p!q!r!s!x!y!z!{!|#R#S#T#U#V#e$O%P%U%V%t&U&V&X&d&g&x&}'T'W'h(Q(`(p(r(v(y(z({(|(})P)Q)R)S)T)W)Z)[)b)c)f)g)h)i)j)k)l)m)n)s)y)z){)|)}*O*P*Q*R*S*T*UQ$_!kQ$v!}Q&P$`S&f${(XS']&]'|R'b&b$ikRhijl!e!f!p!q!r!s!x!y!z!{!|!}#R#S#T#U#V#e$O%P%U%V%t&U&V&X&b&d&g&x&}'T'W'h(Q(`(p(r(v(y(z({(|(})P)Q)R)S)T)W)Z)[)b)c)f)g)h)i)j)k)l)m)n)s)y)z){)|)}*O*P*Q*R*S*T*UV$b!l#O)O$d#Pg#W#Y#[#_$U$W$i$j$k$l$p$q$r$s$t$u$z${$|$}%O%]%l&h&k&l&y'U'V'X'a'e'f'g'i'm'r'w(R(S(T(U(W(X(Y(Z([(](m(o(t(u(w(x)U)V)X)Y)])^)_)`)a)d)e)o)p)q)r)t)u)v)w)x*V*W*X*YQ&O$_S&Q$a(VR'S&PR$w!}R'c&bR#]jR&m%V!g_OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%k!gSOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kTnSoQqSQtTQ#boR#kuQpSS#aoqS%Z#b#cR&o%[!gTOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ$Y!gQ$[!iQ$]!jQ$d!mQ$f!nQ$g!oQ%e#qQ%z$^Q&v%rQ'Y&[S'[&]'|Q'n'OQ(b'tQ(f'xR(h'{QsTS#htuS%`#i#kR&q%a!gUOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kRyUR#ny!gVOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQzVR#p{!gWOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ$`!kR%y$]R%{$^R'o'OQ}WR#r!O!gXOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!QXR#t!R!gYOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!TYR#v!U!gZOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!WZR#x!X!g[OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ![[R#}!]Q!Z[S#z![!]S%j#{#}R&t%k!g]OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!_]R$Q!`!g^OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!b^R$S!cQ'^&]R(i'|QdOQuTQ{VQ!OWQ!RXQ!UYQ!XZQ!][Q!`]Q!c^p!vdu{!O!R!U!X!]!`!c#c#i#{%[%a%kQ#cqQ#itQ#{![Q%[#bQ%a#kR%k#}SQOdSeQm!cmSTVWXYZ[]^oqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kS&c$u$wR'd&cQ%Q#WQ%S#YT&i%Q%SQ%W#]R&n%WQoSR#`oQ%s$YQ&S$dQ&W$gW&w%s&S&W(qR(q(fQxUR#mxS'P%z%{R'p'PQ'u'VR(c'uQ'y'XQ(e'wT(g'y(eQ'}'^R(j'}Q!uaR$m!u!bcOTVWXYZ[]^dqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kTnSoQgRQ#WhQ#YiQ#[jQ#_lQ$U!eQ$W!fQ$i!pQ$j!qQ$k!rQ$l!sQ$p!xS$q!y)gQ$r!zQ$s!{Q$t!|Q$u!}Q$z#RQ${#SQ$|#TQ$}#UQ%O#VQ%]#eQ%l$OQ&h%PQ&k%UQ&l%VQ&y%tQ'U&UQ'V&VQ'X&XQ'a&bQ'e&dQ'f&gQ'g(yQ'i&xQ'm&}Q'r'TQ'w'WS(R(z)zQ(S({Q(T(|Q(U(}Q(W)PQ(X)QQ(Y)RQ(Z)SQ([)TQ(]'hQ(m(QQ(o(`Q(t)WQ(u(pQ(w(rQ(x(vQ)U)ZQ)V)[Q)X)bQ)Y)cQ)])fQ)^)lQ)_)mQ)`)nQ)a)sQ)d*TQ)e*UQ)o)hQ)p)iQ)q)jQ)r)kQ)t)yQ)u*PQ)v*QQ)w*RQ)x*SQ*V){Q*W)|Q*X)}R*Y*OQ$c!lT$y#O)OR$x!}R#XhR#^jR%|$^R$h!o",nodeNames:`⚠ {{ {# {% {% Template Text }} Interpolation VariableName MemberExpression . PropertyName SubscriptExpression BinaryExpression ConcatOp ArithOp ArithOp CompareOp in is StringLiteral NumberLiteral and or NotExpression not FilterExpression FilterOp FilterName FilterCall ) ( ArgumentList NamedArgument AssignOp , NamedArgument ConditionalExpression if else CallExpression ArrayExpression TupleExpression ParenthesizedExpression DictExpression Entry : Entry BooleanLiteral self super loop IfStatement Tag TagName if %} Tag elif Tag else EndTag endif ForStatement Tag for Definition recursive EndTag endfor RawStatement Tag raw RawText EndTag endraw BlockStatement Tag block scoped required EndTag endblock MacroStatement Tag macro ParamList OptionalParameter OptionalParameter EndTag endmacro CallStatement Tag call EndTag endcall FilterStatement Tag filter EndTag endfilter SetStatement Tag set EndTag endset TransStatement Tag trans Tag pluralize EndTag endtrans WithStatement Tag with EndTag endwith AutoescapeStatement Tag autoescape EndTag endautoescape Tag Tag Tag import as from import ImportItem Tag include ignore missing with without context Comment #}`,maxTerm:173,nodeProps:[[`closedBy`,1,`}}`,2,`#}`,-2,3,4,`%}`,32,`)`],[`openedBy`,7,`{{`,31,`(`,57,`{%`,140,`{#`],[`group`,-18,9,10,13,14,21,22,25,27,38,41,42,43,44,45,49,50,51,52,`Expression`,-11,53,64,71,77,84,92,97,102,107,114,119,`Statement`]],skippedNodes:[0],repeatNodeCount:13,tokenData:".|~RqXY#YYZ#Y]^#Ypq#Yqr#krs#vuv&nwx&{xy)nyz)sz{)x{|*V|}+|}!O,R!O!P,g!P!Q,o!Q![+h![!],w!^!_,|!_!`-U!`!a,|!c!}-^!}#O.U#P#Q.Z#R#S-^#T#o-^#o#p.`#p#q.e#q#r.j#r#s.w%W;'S-^;'S;:j.O<%lO-^~#_S$d~XY#YYZ#Y]^#Ypq#Y~#nP!_!`#q~#vOb~~#yWOY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x<%lO#v~$hOe~~$kYOY#vYZ#vZr#vrs%Zs#O#v#O#P$h#P;'S#v;'S;=`&O;=`<%l#v<%lO#v~%`We~OY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x<%lO#v~%{P;=`<%l#v~&RXOY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x;=`<%l#v<%lO#v~&sP`~#q#r&v~&{O!Z~~'OWOY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x<%lO&{~'kYOY&{YZ&{Zw&{wx(Zx#O&{#O#P'h#P;'S&{;'S;=`)O;=`<%l&{<%lO&{~(`We~OY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x<%lO&{~({P;=`<%l&{~)RXOY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x;=`<%l&{<%lO&{~)sOp~~)xOo~~)}P`~z{*Q~*VO`~~*[Qa~!O!P*b!Q![+h~*eP!Q![*h~*mSf~!Q![*h!g!h*y#R#S*h#X#Y*y~*|R{|+V}!O+V!Q![+]~+YP!Q![+]~+bQf~!Q![+]#R#S+]~+mTf~!O!P*b!Q![+h!g!h*y#R#S+h#X#Y*y~,ROt~~,WRa~uv,a!O!P*b!Q![+h~,dP#q#r&v~,lPZ~!Q![*h~,tP`~!P!Q*Q~,|O!P~~-RPb~!_!`#q~-ZPs~!_!`#q!`-iVm`[p!XS$gY!Q![-^!c!}-^#R#S-^#T#o-^%W;'S-^;'S;:j.O<%lO-^!`.RP;=`<%l-^~.ZO$i~~.`O$h~~.eO$n~~.jOl~^.oP$m[#q#r.rQ.wOVQ~.|O_~",tokenizers:[S,w,1,2,3,4,5,new s(`b~RPstU~XP#q#r[~aO$Q~~`,17,173)],topRules:{Template:[0,5]},specialized:[{term:161,get:e=>T[e]||-1},{term:55,get:e=>E[e]||-1}],tokenPrec:3602});function O(e,t){return e.split(` `).map(e=>({label:e,type:t}))}var k=O(`abs attr batch capitalize center default dictsort escape filesizeformat first float forceescape format groupby indent int items join last length list lower map max min pprint random reject rejectattr replace reverse round safe select selectattr slice sort string striptags sum title tojson trim truncate unique upper urlencode urlize wordcount wordwrap xmlattr`,`function`),A=O(`boolean callable defined divisibleby eq escaped even filter float ge gt in integer iterable le lower lt mapping ne none number odd sameas sequence string test undefined upper range lipsum dict joiner namespace`,`function`),j=O(`loop super self true false varargs kwargs caller name arguments catch_kwargs catch_varargs caller`,`keyword`),M=A.concat(j),N=O(`raw endraw filter endfilter trans pluralize endtrans with endwith autoescape endautoescape if elif else endif for endfor call endcall block endblock set endset macro endmacro import include break continue debug do extends`,`keyword`);function P(e){let{state:t,pos:r}=e,i=n(t).resolveInner(r,-1).enterUnfinishedNodesBefore(r),a=i.childBefore(r)?.name||i.name;if(i.name==`FilterName`)return{type:`filter`,node:i};if(e.explicit&&(a==`FilterOp`||a==`filter`))return{type:`filter`};if(i.name==`TagName`)return{type:`tag`,node:i};if(e.explicit&&a==`{%`)return{type:`tag`};if(i.name==`PropertyName`&&i.parent.name==`MemberExpression`)return{type:`prop`,node:i,target:i.parent};if(i.name==`.`&&i.parent.name==`MemberExpression`)return{type:`prop`,target:i.parent};if(i.name==`MemberExpression`&&a==`.`)return{type:`prop`,target:i};if(i.name==`VariableName`)return{type:`expr`,from:i.from};if(i.name==`Comment`||i.name==`StringLiteral`||i.name==`NumberLiteral`)return null;let o=e.matchBefore(/[\w\u00c0-\uffff]+$/);return o?{type:`expr`,from:o.from}:e.explicit?{type:`expr`}:null}function F(e,t,n,r){let i=[];for(;;){let n=t.getChild(`Expression`);if(!n)return[];if(n.name==`VariableName`){i.unshift(e.sliceDoc(n.from,n.to));break}if(n.name==`MemberExpression`){let r=n.getChild(`PropertyName`);r&&i.unshift(e.sliceDoc(r.from,r.to)),t=n}else return[]}return r(i,e,n)}function I(e={}){let t=e.tags?e.tags.concat(N):N,n=e.variables?e.variables.concat(M):M,{properties:r}=e;return e=>{let i=P(e);if(!i)return null;let a=i.from??(i.node?i.node.from:e.pos),o;return o=i.type==`filter`?k:i.type==`tag`?t:i.type==`expr`?n:r?F(e.state,i.target,e,r):[],o.length?{options:o,from:a,validFor:/^[\w\u00c0-\uffff]*$/}:null}}var L=o.inputHandler.of((e,t,n,r)=>r!=`%`||t!=n||e.state.doc.sliceString(t-1,n+1)!=`{}`?!1:(e.dispatch(e.state.changeByRange(e=>({changes:{from:e.from,to:e.to,insert:`%%`},range:p.cursor(e.from+1)})),{scrollIntoView:!0,userEvent:`input.type`}),!0));function R(e){return t=>{let n=e.test(t.textAfter);return t.lineIndent(t.node.from)+(n?0:t.unit)}}var z=u.define({name:`jinja`,parser:D.configure({props:[r({"TagName raw endraw filter endfilter as trans pluralize endtrans with endwith autoescape endautoescape":i.keyword,"required scoped recursive with without context ignore missing":i.modifier,self:i.self,"loop super":i.standard(i.variableName),"if elif else endif for endfor call endcall":i.controlKeyword,"block endblock set endset macro endmacro import from include":i.definitionKeyword,"Comment/...":i.blockComment,VariableName:i.variableName,Definition:i.definition(i.variableName),PropertyName:i.propertyName,FilterName:i.special(i.variableName),ArithOp:i.arithmeticOperator,AssignOp:i.definitionOperator,"not and or":i.logicOperator,CompareOp:i.compareOperator,"in is":i.operatorKeyword,"FilterOp ConcatOp":i.operator,StringLiteral:i.string,NumberLiteral:i.number,BooleanLiteral:i.bool,"{% %} {# #} {{ }} { }":i.brace,"( )":i.paren,".":i.derefOperator,": , .":i.punctuation}),t.add({Tag:f({closing:`%}`}),"IfStatement ForStatement":R(/^\s*(\{%-?\s*)?(endif|endfor|else|elif)\b/),Statement:R(/^\s*(\{%-?\s*)?end\w/)}),e.add({"Statement Comment"(e){let t=e.firstChild,n=e.lastChild;return!t||t.name!=`Tag`&&t.name!=`{#`?null:{from:t.to,to:n.name==`EndTag`||n.name==`#}`?n.from:e.to}}})]}),languageData:{indentOnInput:/^\s*{%-?\s*(?:end|elif|else)$/}}),B=m();function V(e){return z.configure({wrap:a(t=>t.type.isTop?{parser:e.parser,overlay:e=>e.name==`Text`||e.name==`RawText`}:null)},`jinja`)}var H=V(B.language);function U(e={}){let t=e.base||B,n=t.language==B.language?H:V(t.language);return new d(n,[t.support,n.data.of({autocomplete:I(e)}),t.language.data.of({closeBrackets:{brackets:[`{`]}}),L])}export{U as jinja};
1
+ import{C as e,D as t,F as n,L as r,R as i,Ut as a,V as o,i as s,n as c,r as l,s as u,u as d,v as f,vt as p}from"./dist-H3rerbMg.js";import{n as m}from"./dist-Bx7GKFmy.js";var h=1,g=2,_=3,v=155,y=4,b=156;function x(e){return e>=65&&e<=90||e>=97&&e<=122}var S=new c(e=>{let t=e.pos;for(;;){let{next:n}=e;if(n<0)break;if(n==123){let n=e.peek(1);if(n==123){if(e.pos>t)break;e.acceptToken(h,2);return}if(n==35){if(e.pos>t)break;e.acceptToken(g,2);return}if(n==37){if(e.pos>t)break;let n=2,r=2;for(;;){let t=e.peek(n);if(t==32||t==10)++n;else if(t==35)for(++n;;){let t=e.peek(n);if(t<0||t==10)break;n++}else if(t==45&&r==2)r=++n;else{e.acceptToken(_,r);return}}}}if(e.advance(),n==10)break}e.pos>t&&e.acceptToken(v)});function C(e,t,n){return new c(r=>{let i=r.pos;for(;;){let{next:t}=r;if(t==123&&r.peek(1)==37){let t=2;for(;;t++){let e=r.peek(t);if(e!=32&&e!=10)break}let a=``;for(;;t++){let e=r.peek(t);if(!x(e))break;a+=String.fromCharCode(e)}if(a==e){if(r.pos>i)break;r.acceptToken(n,2);break}}else if(t<0)break;if(r.advance(),t==10)break}r.pos>i&&r.acceptToken(t)})}var w=C(`endraw`,b,y),T={__proto__:null,in:38,is:40,and:46,or:48,not:52,if:78,else:80,true:98,false:98,self:100,super:102,loop:104,recursive:136,scoped:160,required:162,as:256,import:260,ignore:268,missing:270,with:272,without:274,context:276},E={__proto__:null,if:112,elif:118,else:122,endif:126,for:132,endfor:140,raw:146,endraw:152,block:158,endblock:166,macro:172,endmacro:182,call:188,endcall:192,filter:198,endfilter:202,set:208,endset:212,trans:218,pluralize:222,endtrans:226,with:232,endwith:236,autoescape:242,endautoescape:246,import:254,from:258,include:266},D=l.deserialize({version:14,states:"!*dQVOPOOOOOP'#F`'#F`OeOTO'#CbOvQSO'#CdO!kOPO'#DcO!yOPO'#DnO#XOQO'#DuO#^OPO'#D{O#lOPO'#ESO#zOPO'#E[O$YOPO'#EaO$hOPO'#EfO$vOPO'#EkO%UOPO'#ErO%dOPO'#EwOOOP'#F|'#F|O%rQWO'#E|O&sO#tO'#F]OOOP'#Fq'#FqOOOP'#F_'#F_QVOPOOOOOP-E9^-E9^OOQO'#Ce'#CeO'sQSO,59OO'zQSO'#DWO(RQSO'#DXO(YQ`O'#DZOOQO'#Fr'#FrOvQSO'#CuO(aOPO'#CbOOOP'#Fd'#FdO!kOPO,59}OOOP,59},59}O(oOPO,59}O(}QWO'#E|OOOP,5:Y,5:YO)[OPO,5:YO!yOPO,5:YO)jQWO'#E|OOOQ'#Ff'#FfO)tOQO'#DxO)|OQO,5:aOOOP,5:g,5:gO#^OPO,5:gO*RQWO'#E|OOOP,5:n,5:nO#lOPO,5:nO*YQWO'#E|OOOP,5:v,5:vO#zOPO,5:vO*aQWO'#E|OOOP,5:{,5:{O$YOPO,5:{O*hQWO'#E|OOOP,5;Q,5;QO$hOPO,5;QO*oQWO'#E|OOOP,5;V,5;VO*vOPO,5;VO$vOPO,5;VO+UQWO'#E|OOOP,5;^,5;^O%UOPO,5;^O+`QWO'#E|OOOP,5;c,5;cO%dOPO,5;cO+gQWO'#E|O+nQSO,5;hOvQSO,5:OO+uQSO,5:ZO+zQSO,5:bO+uQSO,5:hO+uQSO,5:oO,PQSO,5:wO,XQpO,5:|O+uQSO,5;RO,^QSO,5;WO,fQSO,5;_OvQSO,5;dOvQSO,5;jOvQSO,5;jOvQSO,5;pOOOO'#Fk'#FkO,nO#tO,5;wOOOP-E9]-E9]O,vQ!bO,59QOvQSO,59TOvQSO,59UOvQSO,59UOvQSO,59UOvQSO,59UO,{QSO'#C}O,XQpO,59cOOQO,59q,59qOOOP1G.j1G.jOvQSO,59UO-SQSO,59UOvQSO,59UOvQSO,59UOvQSO,59nO-wQSO'#FxO.RQSO,59rO.WQSO,59tOOQO,59s,59sO.bQSO'#D[O.iQWO'#F{O.qQWO,59uO0WQSO,59aOOOP-E9b-E9bOOOP1G/i1G/iO(oOPO1G/iO(oOPO1G/iO)TQWO'#E|OvQSO,5:SO0nQSO,5:UO0sQSO,5:WOOOP1G/t1G/tO)[OPO1G/tO)mQWO'#E|O)[OPO1G/tO0xQSO,5:_OOOQ-E9d-E9dOOOP1G/{1G/{O0}QWO'#DyOOOP1G0R1G0RO1SQSO,5:lOOOP1G0Y1G0YO1[QSO,5:tOOOP1G0b1G0bO1aQSO,5:yOOOP1G0g1G0gO1fQSO,5;OOOOP1G0l1G0lO1kQSO,5;TOOOP1G0q1G0qO*vOPO1G0qO+XQWO'#E|O*vOPO1G0qOvQSO,5;YO1pQSO,5;[OOOP1G0x1G0xO1uQSO,5;aOOOP1G0}1G0}O1zQSO,5;fO2PQSO1G1SOOOP1G1S1G1SO2WQSO1G/jOOQO'#Dq'#DqO2_QSO1G/uOOOQ1G/|1G/|O2gQSO1G0SO2rQSO1G0ZO2zQSO'#EVO3SQSO1G0cO,SQSO1G0cO4fQSO'#FvOOQO'#Fv'#FvO5]QSO1G0hO5bQSO1G0mOOOP1G0r1G0rO5mQSO1G0rO5rQSO'#GOO5zQSO1G0yO6PQSO1G1OO6WQSO1G1UO6_QSO1G1UO6fQSO1G1[OOOO-E9i-E9iOOOP1G1c1G1cOOQO1G.l1G.lO6vQSO1G.oO8wQSO1G.pO:oQSO1G.pO:vQSO1G.pO<nQSO1G.pO<uQSO'#FwO>QQSO'#FrO>XQSO'#FwO>aQSO,59iOOQO1G.}1G.}O>fQSO1G.pO@aQSO1G.pOB_QSO1G.pOBfQSO1G.pOD^QSO1G/YOvQSO'#FbODeQSO,5<dOOQO1G/^1G/^ODmQSO1G/_OOQO1G/`1G/`ODuQSO,59vOvQSO'#FcOEjQWO,5<gOOQO1G/a1G/aPErQWO'#E|OOOP7+%T7+%TO(oOPO7+%TOEyQSO1G/nOOOP1G/p1G/pOOOP1G/r1G/rOOOP7+%`7+%`O)[OPO7+%`OOOP1G/y1G/yOFQQSO,5:eOOOP1G0W1G0WOFVQSO1G0WOOOP1G0`1G0`OOOP1G0e1G0eOOOP1G0j1G0jOOOP1G0o1G0oOOOP7+&]7+&]O*vOPO7+&]OF[QSO1G0tOOOP1G0v1G0vOOOP1G0{1G0{OOOP1G1Q1G1QOOOP7+&n7+&nOOOP7+%U7+%UO+uQSO'#FeOFcQSO7+%aOvQSO7+%aOOOP7+%n7+%nOFkQSO7+%nOFpQSO7+%nOOOP7+%u7+%uOFxQSO7+%uOF}QSO'#F}OGQQSO'#F}OGYQSO,5:qOOOP7+%}7+%}OG_QSO7+%}OGdQSO7+%}OOQO,59f,59fOOOP7+&S7+&SOGlQSO7+&oOOOP7+&X7+&XOvQSO7+&oOvQSO7+&^OGtQSO,5<jOvQSO,5<jOOOP7+&e7+&eOOOP7+&j7+&jO+uQSO7+&pOG|QSO7+&pOOOP7+&v7+&vOHRQSO7+&vOHWQSO7+&vOOQO7+$Z7+$ZOvQSO'#FaOH]QSO,5<cOvQSO,59jOOQO1G/T1G/TOOQO7+$[7+$[OvQSO7+$tOHeQSO,5;|OOQO-E9`-E9`OOQO7+$y7+$yOImQ`O1G/bOIwQSO'#D^OOQO,5;},5;}OOQO-E9a-E9aOOOP<<Ho<<HoOOOP7+%Y7+%YOOOP<<Hz<<HzOOOP1G0P1G0POOOP7+%r7+%rOOOP<<Iw<<IwOOOP7+&`7+&`OOQO,5<P,5<POOQO-E9c-E9cOvQSO<<H{OJOQSO<<H{OOOP<<IY<<IYOJYQSO<<IYOOOP<<Ia<<IaOvQSO,5:rO+uQSO'#FgOJ_QSO,5<iOOQO1G0]1G0]OOOP<<Ii<<IiOJgQSO<<IiOvQSO<<JZOJlQSO<<JZOJsQSO<<IxOvQSO1G2UOJ}QSO1G2UOKXQSO<<J[OK^QSO'#CeOOQO'#FT'#FTOKiQSO'#FTOKnQSO<<J[OKvQSO<<JbOK{QSO<<JbOLWQSO,5;{OLbQSO'#FrOOQO,5;{,5;{OOQO-E9_-E9_OLiQSO1G/UOM}QSO<<H`O! ]Q`O,59aODuQSO,59xO! sQSOAN>gOOOPAN>gAN>gO! }QSOAN>gOOOPAN>tAN>tO!!SQSO1G0^O!!^QSO,5<ROOQO,5<R,5<ROOQO-E9e-E9eOOOPAN?TAN?TO!!iQSOAN?uOOOPAN?uAN?uO+uQSO'#FhO!!pQSOAN?dOOOPAN?dAN?dO!!xQSO7+'pO+uQSO'#FiO!#SQSO7+'pOOOPAN?vAN?vO+uQSO,5;oOG|QSO'#FjO!#[QSOAN?vOOOPAN?|AN?|O!#dQSOAN?|OvQSO,59mO!$sQ`O1G.pO!%{Q`O1G.pO!&SQ`O1G.pO!'[Q`O1G.pO!'cQ`O'#FvO!'jQ`O1G.pO!(uQ`O1G.pO!*TQ`O1G.pO!*[Q`O1G.pO!+dQ`O1G/YO!+kQ`O1G/dOOOPG24RG24RO!+uQSOG24ROvQSO,5:sOOOPG25aG25aO!+zQSO,5<SOOQO-E9f-E9fOOOPG25OG25OO!,PQSO<<K[O!,XQSO,5<TOOQO-E9g-E9gOOQO1G1Z1G1ZOOQO,5<U,5<UOOQO-E9h-E9hOOOPG25bG25bO!,aQSOG25hO!,fQSO1G/XOOOPLD)mLD)mO!,pQSO1G0_OvQSO1G1nO!,zQSO1G1oOvQSO1G1oOOOPLD+SLD+SO!-wQ`O<<H`O!.[QSO7+'YOvQSO7+'ZO!.fQSO7+'ZO!.pQSO<<JuODuQSO'#CuODuQSO,59UODuQSO,59UODuQSO,59UODuQSO,59UO!.zQpO,59cODuQSO,59UO!/PQSO,59UODuQSO,59UODuQSO,59UODuQSO,59nO!/tQSO1G.pP!0RQSO1G/YODuQSO7+$tO!0YQ`O1G.pP!0gQ`O1G/YO-SQSO,59UPvQSO,59nO!0nQSO,59aP!3XQSO1G.pP!3`QSO1G.pP!5aQSO1G/YP!5hQSO<<H`O!/PQSO,59UPDuQSO,59nP!6_QSO1G/YP!7pQ`O1G/YO-SQSO'#CuO-SQSO,59UO-SQSO,59UO-SQSO,59UO-SQSO,59UO-SQSO,59UP-SQSO,59UP-SQSO,59UP-SQSO,59nO!7wQSO1G.pO!9xQSO1G.pO!:PQSO1G.pO!;UQSO1G.pP-SQSO7+$tO!<XQ`O,59aP!>SQ`O1G.pP!>ZQ`O1G.pP!>bQ`O1G/YP!?QQ`O<<H`O!/PQSO'#CuO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UO!/PQSO,59UP!/PQSO,59UP!/PQSO,59UP!/PQSO,59nP!/PQSO7+$tP-SQSO,59nP!/PQSO,59nO!?zQ`O1G.pO!@RQ`O1G.pO!@fQ`O1G.pO!@yQ`O1G.p",stateData:"!Ac~O$dOS~OPROQaOR`O$aPO~O$aPOPUXQUXRUX$`UX~OekOfkOjlOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~OPROQaORrO$aPO~OPROQaORvO$aPO~O$bwO~OPROQaOR|O$aPO~OPROQaOR!PO$aPO~OPROQaOR!SO$aPO~OPROQaOR!VO$aPO~OPROQaOR!YO$aPO~OPROQaOR!^O$aPO~OPROQaOR!aO$aPO~OPROQaOR!dO$aPO~O!X!eO!Y!fO!d!gO!k!hO!q!iO!x!jO#Q!kO#V!lO#[!mO#a!nO#h!oO#m!pO#s!qO#u!rO#y!sO~O$s!tO~OZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UOl#OOp!}Ow#VO$i!xO~OV#QO~P&xO$h$lP~PvOo#ZO~PvO$m$oP~PvO$aPOPUXQUXRUX~OPROQaOR#dO$aPO~O!]#eO!_#fO!a#gO~P%rOPROQaOR#jO$aPO~O!_#fO!h#lO~P%rO$bwOS!lX~OS#oO~O!u#qO~P%rO!}#sO~P%rO#S#uO~P%rO#X#wO~P%rO#^#yO~P%rOPROQaOR#|O$aPO~O#c$OO#e$PO~P%rO#j$RO~P%rO#o$TO~P%rO!Z$VO~PvO$g$XO~O!Z$ZO~Op$^O$gfO~Om$aO~O!Z$eO$g$XO~O$g$XO!Z$rP~O$Q$nO$s!tO~O[$oO~Oo$kP~PvOekOfkOj)fOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Ot%PO$h$lX~P&xO$h%RO~Oo%TOt%PO~P&xO!P%UO~P&xOt%VO$m$oX~O$m%XO~OZ!wOp!}O$i!xOViagiahialiawiatia$hiaoia!Pia!Zia#tia#via#zia#|ia#}iaxia!fia~O_!yO`!zOa!{Ob!|Oc#ROd#SO~P.vO!Z%^O~O!Z%_O~O!Z%bO~O!n%cO~O!Z%dO$g$XO~O!Z%fO~O!Z%gO~O!Z%hO~O!Z%iO~O!Z%mO~O!Z%nO~O!Z%oO~O!Z%pO~P&xO!Z%qO~P&xOc%tOt%rO~O!Z%uO!r%wO!s%vO~Op$^O!Z%xO~O$g$XOo$qP~Op!}O!Z%}O~Op!}OZ$jX_$jX`$jXa$jXb$jXc$jXd$jXg$jXh$jXl$jXw$jX$i$jXt$jXe$jXf$jX$g$jXx$jX~O!Z$jXV$jX$h$jXo$jX!P$jX#t$jX#v$jX#z$jX#|$jX#}$jX!f$jX~P3[O!Z&RO~Os&UOt%rO!Z&TO~Os&VO~Os&XOt%rO~O!Z&YO~O!Z&ZO~P&xO#t&[O~P&xO#v&]O~P&xO!Z&^O#z&`O#|&_O#}&_O~P&xO$h&aO~P&xOZ!wOp!}O$i!xOV^i`^ia^ib^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ie^if^i$g^ix^i!f^i~O_^i~P6}OZ!wO_!yOp!}O$i!xOV^ia^ib^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~O`^i~P9OO`!zO~P9OOZ!wO_!yO`!zOa!{Op!}O$i!xOV^ic^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Ob^i~P:}Ot&bOo$kX~P&xOZ$fX_$fX`$fXa$fXb$fXc$fXd$fXg$fXh$fXl$fXo$fXp$fXt$fXw$fX$i$fX~Os&dO~P=POt&bOo$kX~Oo&eO~Ob!|O~P:}OZ!wO_)gO`)hOa)iOb)jOc)kOp!}O$i!xOV^id^ig^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Oe&fOf&fO$gfO~P>mOZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOp!}O$i!xOV^ih^il^iw^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Og^i~P@nOg#TO~P@nOZ!wO_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UOp!}O$i!xOVvilviwvitvi$hviovi!Pvi!Zvi#tvi#vvi#zvi#|vi#}vi!fvi~Ox&gO~PBmOt%PO$h$la~Oo&jOt%PO~OekOfkOj(yOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Ot%VO$m$oa~O!]#eO~P%rO!Z&pO~P&xO!Z&rO~O!Z&sO~O!Z&uO~P&xOc&xOt%rO~O!Z&zO~O!Z&zO!s&{O~O!Z&|O~Os&}Ot'OOo$qX~Oo'QO~O!Z'RO~Op!}O!Z'RO~Os'TOt%rO~Os'WOt%rO~O$g'ZO~O$O'_O~O#{'`O~Ot&bOo$ka~Ot$Ua$h$Uao$Ua~P&xOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOl)OOp!}Ow)TO$i!xO~Ot!Oi$m!Oi~PHrO!P'hO~P&xO!Z'jO!f'kO~P&xO!Z'lO~Ot'OOo$qa~O!Z'qO~O!Z'sO~P&xOt'tO!Z'vO~P&xOt'xO!Z$ri~P&xO!Z'zO~Ot!eX!Z!eX#tXX~O#t'{O~Ot'|O!Z'zO~O!Z(OO~O!Z(OO#|(PO#}(PO~Oo$Tat$Ta~P&xOs(QO~P=POoritri~P&xOZ!wOp!}O$i!xOVvylvywvytvy$hvyovy!Pvy!Zvy#tvy#vvy#zvy#|vy#}vyxvy!fvy~O_!yO`!zOa!{Ob!|Oc#ROd#SOg#TOh#UO~PLsOZ!wOp!}O$i!xOgiahialiatiawia$miaxia~O_(zO`({Oa(|Ob(}Oc)POd)QO~PNkO!Z(^O!f(_O~P&xO!Z(^O~Oo!zit!zi~P&xOs(`Oo$Zat$Za~O!Z(aO~P&xOt'tO!Z(dO~Ot'xO!Z$rq~P&xOt'xO!Z$rq~Ot'|O!Z(kO~O$O(lO~OZ!wOp!}O$i!xO`^ia^ib^ic^id^ig^ih^il^it^iw^i$m^ie^if^i$g^ix^i~O_^i~P!#iOZ!wO_(zOp!}O$i!xOa^ib^ic^id^ig^ih^il^it^iw^i$m^ix^i~O`^i~P!$zO`({O~P!$zOZ!wO_(zO`({Oa(|Op!}O$i!xOc^id^ig^ih^il^it^iw^i$m^ix^i~Ob^i~P!&ZO$m$jX~P3[Ob(}O~P!&ZOZ!wO_)zO`){Oa)|Ob)}Oc*OOp!}O$i!xOd^ig^ih^il^it^iw^i$m^ix^i~Oe&fOf&fO$gfO~P!'qOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOp!}O$i!xOh^il^it^iw^i$m^ix^i~Og^i~P!)SOg)RO~P!)SOZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOp!}O$i!xOlvitviwvi$mvi~Ox)WO~P!*cOt!Qi$m!Qi~PHrO!Z(nO~Os(pO~Ot'xO!Z$ry~Os(rOt%rO~O!Z(sO~Oouitui~P&xOo!{it!{i~P&xOs(vOt%rO~OZ!wO_(zO`({Oa(|Ob(}Oc)POd)QOg)ROh)SOp!}O$i!xO~Olvytvywvy$mvyxvy~P!-SOt$[q!Z$[q~P&xOt$]q!Z$]q~P&xOt$]y!Z$]y~P&xOm(VO~OekOfkOj)yOpiO!RkO!SkO!TkO!UkO$gfO$ihO$njO~Oe^if^i$g^i~P>mOxvi~PBmOe^if^i$g^i~P!'qOxvi~P!*cO_)gO`)hOa)iOb)jOc)kOd)ZOeiafia$gia~P.vOZ!wO_)gO`)hOa)iOb)jOc)kOd)ZOp!}O$i!xOV^ie^if^ih^il^iw^i$g^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Og^i~P!1_Og)lO~P!1_OZ!wO_)gO`)hOa)iOb)jOc)kOd)ZOg)lOh)mOp!}O$i!xOVvievifvilviwvi$gvitvi$hviovi!Pvi!Zvi#tvi#vvi#zvi#|vi#}vi!fvi~Ox)sO~P!3gO_)gO`)hOa)iOb)jOc)kOd)ZOg)lOh)mOevyfvy$gvy~PLsOxvi~P!3gOZ!wO_)zO`){Oa)|Ob)}Oc*OOd)bOg*POh*QOp!}O$i!xOevifvilvitviwvi$gvi$mvi~Oxvi~P!6fO_)gO~P6}OZ!wO_)gO`)hOp!}O$i!xOV^ib^ic^id^ie^if^ig^ih^il^iw^i$g^it^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^ix^i!f^i~Oa^i~P!8OOa)iO~P!8OOZ!wOp!}O$i!xOc^id^ie^if^ig^ih^il^iw^i$g^it^ix^i~O_)gO`)hOa)iOb)jOV^i$h^io^i!P^i!Z^i#t^i#v^i#z^i#|^i#}^i!f^i~P!:WO_)zO`){Oa)|Ob)}Oc*OOd)bOeiafia$gia~PNkOZ!wO_)zO`){Oa)|Ob)}Oc*OOd)bOp!}O$i!xOe^if^ih^il^it^iw^i$g^i$m^ix^i~Og^i~P!<xOg*PO~P!<xOx*SO~P!6fOZ!wO_)zO`){Oa)|Ob)}Op!}O$i!xO~Oc*OOd)bOg*POh*QOevyfvylvytvywvy$gvy$mvyxvy~P!>iO_)zO~P!#iO_)zO`){Oa^ib^i$m^i~P!:WO_)zO`){Oa)|Ob^i$m^i~P!:WO_)zO`){Oa)|Ob)}O$m^i~P!:WOfaZa~",goto:"Cy$sPPPPPP$tP$t%j'sPP's'sPPPPPPPPPP'sP'sPP)jPP)o+nPP+q'sPP's's's's's+tP+wPPPP+z,pPPP-fP-jP-vP+z.UP.zP/zP+z0YP1O1RP+z1UPPP1zP+z2QP2v2|3P3SP+z3YP4OP+z4UP4zP+z5QP5vP+z5|P6rP6xP+z7WP7|P+z8SP8xP$t$t$tPPPP9O$tPPPPPP$tP9U:j;f;m;w;}<T<g<m<t<z=U=[PPPPP=b>YPPPCcCjCmPPCp$tCsCv!gbOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%k$dkRhijl!e!f!p!q!r!s!x!y!z!{!|#R#S#T#U#V#e$O%P%U%V%t&U&V&X&d&g&x&}'T'W'h(Q(`(p(r(v(y(z({(|(})P)Q)R)S)T)W)Z)[)b)c)f)g)h)i)j)k)l)m)n)s)y)z){)|)}*O*P*Q*R*S*T*UQ$_!kQ$v!}Q&P$`S&f${(XS']&]'|R'b&b$ikRhijl!e!f!p!q!r!s!x!y!z!{!|!}#R#S#T#U#V#e$O%P%U%V%t&U&V&X&b&d&g&x&}'T'W'h(Q(`(p(r(v(y(z({(|(})P)Q)R)S)T)W)Z)[)b)c)f)g)h)i)j)k)l)m)n)s)y)z){)|)}*O*P*Q*R*S*T*UV$b!l#O)O$d#Pg#W#Y#[#_$U$W$i$j$k$l$p$q$r$s$t$u$z${$|$}%O%]%l&h&k&l&y'U'V'X'a'e'f'g'i'm'r'w(R(S(T(U(W(X(Y(Z([(](m(o(t(u(w(x)U)V)X)Y)])^)_)`)a)d)e)o)p)q)r)t)u)v)w)x*V*W*X*YQ&O$_S&Q$a(VR'S&PR$w!}R'c&bR#]jR&m%V!g_OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%k!gSOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kTnSoQqSQtTQ#boR#kuQpSS#aoqS%Z#b#cR&o%[!gTOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ$Y!gQ$[!iQ$]!jQ$d!mQ$f!nQ$g!oQ%e#qQ%z$^Q&v%rQ'Y&[S'[&]'|Q'n'OQ(b'tQ(f'xR(h'{QsTS#htuS%`#i#kR&q%a!gUOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kRyUR#ny!gVOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQzVR#p{!gWOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ$`!kR%y$]R%{$^R'o'OQ}WR#r!O!gXOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!QXR#t!R!gYOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!TYR#v!U!gZOSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!WZR#x!X!g[OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ![[R#}!]Q!Z[S#z![!]S%j#{#}R&t%k!g]OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!_]R$Q!`!g^OSTVWXYZ[]^doqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kQ!b^R$S!cQ'^&]R(i'|QdOQuTQ{VQ!OWQ!RXQ!UYQ!XZQ!][Q!`]Q!c^p!vdu{!O!R!U!X!]!`!c#c#i#{%[%a%kQ#cqQ#itQ#{![Q%[#bQ%a#kR%k#}SQOdSeQm!cmSTVWXYZ[]^oqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kS&c$u$wR'd&cQ%Q#WQ%S#YT&i%Q%SQ%W#]R&n%WQoSR#`oQ%s$YQ&S$dQ&W$gW&w%s&S&W(qR(q(fQxUR#mxS'P%z%{R'p'PQ'u'VR(c'uQ'y'XQ(e'wT(g'y(eQ'}'^R(j'}Q!uaR$m!u!bcOTVWXYZ[]^dqtu{!O!R!U!X![!]!`!c#b#c#i#k#{#}%[%a%kTnSoQgRQ#WhQ#YiQ#[jQ#_lQ$U!eQ$W!fQ$i!pQ$j!qQ$k!rQ$l!sQ$p!xS$q!y)gQ$r!zQ$s!{Q$t!|Q$u!}Q$z#RQ${#SQ$|#TQ$}#UQ%O#VQ%]#eQ%l$OQ&h%PQ&k%UQ&l%VQ&y%tQ'U&UQ'V&VQ'X&XQ'a&bQ'e&dQ'f&gQ'g(yQ'i&xQ'm&}Q'r'TQ'w'WS(R(z)zQ(S({Q(T(|Q(U(}Q(W)PQ(X)QQ(Y)RQ(Z)SQ([)TQ(]'hQ(m(QQ(o(`Q(t)WQ(u(pQ(w(rQ(x(vQ)U)ZQ)V)[Q)X)bQ)Y)cQ)])fQ)^)lQ)_)mQ)`)nQ)a)sQ)d*TQ)e*UQ)o)hQ)p)iQ)q)jQ)r)kQ)t)yQ)u*PQ)v*QQ)w*RQ)x*SQ*V){Q*W)|Q*X)}R*Y*OQ$c!lT$y#O)OR$x!}R#XhR#^jR%|$^R$h!o",nodeNames:`⚠ {{ {# {% {% Template Text }} Interpolation VariableName MemberExpression . PropertyName SubscriptExpression BinaryExpression ConcatOp ArithOp ArithOp CompareOp in is StringLiteral NumberLiteral and or NotExpression not FilterExpression FilterOp FilterName FilterCall ) ( ArgumentList NamedArgument AssignOp , NamedArgument ConditionalExpression if else CallExpression ArrayExpression TupleExpression ParenthesizedExpression DictExpression Entry : Entry BooleanLiteral self super loop IfStatement Tag TagName if %} Tag elif Tag else EndTag endif ForStatement Tag for Definition recursive EndTag endfor RawStatement Tag raw RawText EndTag endraw BlockStatement Tag block scoped required EndTag endblock MacroStatement Tag macro ParamList OptionalParameter OptionalParameter EndTag endmacro CallStatement Tag call EndTag endcall FilterStatement Tag filter EndTag endfilter SetStatement Tag set EndTag endset TransStatement Tag trans Tag pluralize EndTag endtrans WithStatement Tag with EndTag endwith AutoescapeStatement Tag autoescape EndTag endautoescape Tag Tag Tag import as from import ImportItem Tag include ignore missing with without context Comment #}`,maxTerm:173,nodeProps:[[`closedBy`,1,`}}`,2,`#}`,-2,3,4,`%}`,32,`)`],[`openedBy`,7,`{{`,31,`(`,57,`{%`,140,`{#`],[`group`,-18,9,10,13,14,21,22,25,27,38,41,42,43,44,45,49,50,51,52,`Expression`,-11,53,64,71,77,84,92,97,102,107,114,119,`Statement`]],skippedNodes:[0],repeatNodeCount:13,tokenData:".|~RqXY#YYZ#Y]^#Ypq#Yqr#krs#vuv&nwx&{xy)nyz)sz{)x{|*V|}+|}!O,R!O!P,g!P!Q,o!Q![+h![!],w!^!_,|!_!`-U!`!a,|!c!}-^!}#O.U#P#Q.Z#R#S-^#T#o-^#o#p.`#p#q.e#q#r.j#r#s.w%W;'S-^;'S;:j.O<%lO-^~#_S$d~XY#YYZ#Y]^#Ypq#Y~#nP!_!`#q~#vOb~~#yWOY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x<%lO#v~$hOe~~$kYOY#vYZ#vZr#vrs%Zs#O#v#O#P$h#P;'S#v;'S;=`&O;=`<%l#v<%lO#v~%`We~OY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x<%lO#v~%{P;=`<%l#v~&RXOY#vZr#vrs$cs#O#v#O#P$h#P;'S#v;'S;=`%x;=`<%l#v<%lO#v~&sP`~#q#r&v~&{O!Z~~'OWOY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x<%lO&{~'kYOY&{YZ&{Zw&{wx(Zx#O&{#O#P'h#P;'S&{;'S;=`)O;=`<%l&{<%lO&{~(`We~OY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x<%lO&{~({P;=`<%l&{~)RXOY&{Zw&{wx$cx#O&{#O#P'h#P;'S&{;'S;=`(x;=`<%l&{<%lO&{~)sOp~~)xOo~~)}P`~z{*Q~*VO`~~*[Qa~!O!P*b!Q![+h~*eP!Q![*h~*mSf~!Q![*h!g!h*y#R#S*h#X#Y*y~*|R{|+V}!O+V!Q![+]~+YP!Q![+]~+bQf~!Q![+]#R#S+]~+mTf~!O!P*b!Q![+h!g!h*y#R#S+h#X#Y*y~,ROt~~,WRa~uv,a!O!P*b!Q![+h~,dP#q#r&v~,lPZ~!Q![*h~,tP`~!P!Q*Q~,|O!P~~-RPb~!_!`#q~-ZPs~!_!`#q!`-iVm`[p!XS$gY!Q![-^!c!}-^#R#S-^#T#o-^%W;'S-^;'S;:j.O<%lO-^!`.RP;=`<%l-^~.ZO$i~~.`O$h~~.eO$n~~.jOl~^.oP$m[#q#r.rQ.wOVQ~.|O_~",tokenizers:[S,w,1,2,3,4,5,new s(`b~RPstU~XP#q#r[~aO$Q~~`,17,173)],topRules:{Template:[0,5]},specialized:[{term:161,get:e=>T[e]||-1},{term:55,get:e=>E[e]||-1}],tokenPrec:3602});function O(e,t){return e.split(` `).map(e=>({label:e,type:t}))}var k=O(`abs attr batch capitalize center default dictsort escape filesizeformat first float forceescape format groupby indent int items join last length list lower map max min pprint random reject rejectattr replace reverse round safe select selectattr slice sort string striptags sum title tojson trim truncate unique upper urlencode urlize wordcount wordwrap xmlattr`,`function`),A=O(`boolean callable defined divisibleby eq escaped even filter float ge gt in integer iterable le lower lt mapping ne none number odd sameas sequence string test undefined upper range lipsum dict joiner namespace`,`function`),j=O(`loop super self true false varargs kwargs caller name arguments catch_kwargs catch_varargs caller`,`keyword`),M=A.concat(j),N=O(`raw endraw filter endfilter trans pluralize endtrans with endwith autoescape endautoescape if elif else endif for endfor call endcall block endblock set endset macro endmacro import include break continue debug do extends`,`keyword`);function P(e){let{state:t,pos:r}=e,i=n(t).resolveInner(r,-1).enterUnfinishedNodesBefore(r),a=i.childBefore(r)?.name||i.name;if(i.name==`FilterName`)return{type:`filter`,node:i};if(e.explicit&&(a==`FilterOp`||a==`filter`))return{type:`filter`};if(i.name==`TagName`)return{type:`tag`,node:i};if(e.explicit&&a==`{%`)return{type:`tag`};if(i.name==`PropertyName`&&i.parent.name==`MemberExpression`)return{type:`prop`,node:i,target:i.parent};if(i.name==`.`&&i.parent.name==`MemberExpression`)return{type:`prop`,target:i.parent};if(i.name==`MemberExpression`&&a==`.`)return{type:`prop`,target:i};if(i.name==`VariableName`)return{type:`expr`,from:i.from};if(i.name==`Comment`||i.name==`StringLiteral`||i.name==`NumberLiteral`)return null;let o=e.matchBefore(/[\w\u00c0-\uffff]+$/);return o?{type:`expr`,from:o.from}:e.explicit?{type:`expr`}:null}function F(e,t,n,r){let i=[];for(;;){let n=t.getChild(`Expression`);if(!n)return[];if(n.name==`VariableName`){i.unshift(e.sliceDoc(n.from,n.to));break}if(n.name==`MemberExpression`){let r=n.getChild(`PropertyName`);r&&i.unshift(e.sliceDoc(r.from,r.to)),t=n}else return[]}return r(i,e,n)}function I(e={}){let t=e.tags?e.tags.concat(N):N,n=e.variables?e.variables.concat(M):M,{properties:r}=e;return e=>{let i=P(e);if(!i)return null;let a=i.from??(i.node?i.node.from:e.pos),o;return o=i.type==`filter`?k:i.type==`tag`?t:i.type==`expr`?n:r?F(e.state,i.target,e,r):[],o.length?{options:o,from:a,validFor:/^[\w\u00c0-\uffff]*$/}:null}}var L=o.inputHandler.of((e,t,n,r)=>r!=`%`||t!=n||e.state.doc.sliceString(t-1,n+1)!=`{}`?!1:(e.dispatch(e.state.changeByRange(e=>({changes:{from:e.from,to:e.to,insert:`%%`},range:p.cursor(e.from+1)})),{scrollIntoView:!0,userEvent:`input.type`}),!0));function R(e){return t=>{let n=e.test(t.textAfter);return t.lineIndent(t.node.from)+(n?0:t.unit)}}var z=u.define({name:`jinja`,parser:D.configure({props:[r({"TagName raw endraw filter endfilter as trans pluralize endtrans with endwith autoescape endautoescape":i.keyword,"required scoped recursive with without context ignore missing":i.modifier,self:i.self,"loop super":i.standard(i.variableName),"if elif else endif for endfor call endcall":i.controlKeyword,"block endblock set endset macro endmacro import from include":i.definitionKeyword,"Comment/...":i.blockComment,VariableName:i.variableName,Definition:i.definition(i.variableName),PropertyName:i.propertyName,FilterName:i.special(i.variableName),ArithOp:i.arithmeticOperator,AssignOp:i.definitionOperator,"not and or":i.logicOperator,CompareOp:i.compareOperator,"in is":i.operatorKeyword,"FilterOp ConcatOp":i.operator,StringLiteral:i.string,NumberLiteral:i.number,BooleanLiteral:i.bool,"{% %} {# #} {{ }} { }":i.brace,"( )":i.paren,".":i.derefOperator,": , .":i.punctuation}),t.add({Tag:f({closing:`%}`}),"IfStatement ForStatement":R(/^\s*(\{%-?\s*)?(endif|endfor|else|elif)\b/),Statement:R(/^\s*(\{%-?\s*)?end\w/)}),e.add({"Statement Comment"(e){let t=e.firstChild,n=e.lastChild;return!t||t.name!=`Tag`&&t.name!=`{#`?null:{from:t.to,to:n.name==`EndTag`||n.name==`#}`?n.from:e.to}}})]}),languageData:{indentOnInput:/^\s*{%-?\s*(?:end|elif|else)$/}}),B=m();function V(e){return z.configure({wrap:a(t=>t.type.isTop?{parser:e.parser,overlay:e=>e.name==`Text`||e.name==`RawText`}:null)},`jinja`)}var H=V(B.language);function U(e={}){let t=e.base||B,n=t.language==B.language?H:V(t.language);return new d(n,[t.support,n.data.of({autocomplete:I(e)}),t.language.data.of({closeBrackets:{brackets:[`{`]}}),L])}export{U as jinja};