@linzumi/cli 0.0.20-beta → 0.0.22-beta
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 +65 -62
- package/bin/linzumi.js +10 -18
- package/dist/assets/linzumi-logo.svg +1 -0
- package/dist/index.js +9135 -0
- package/package.json +9 -4
- package/src/agentBootstrap.ts +0 -872
- package/src/authCache.ts +0 -157
- package/src/authResolution.ts +0 -77
- package/src/boundedCache.ts +0 -57
- package/src/channelSession.ts +0 -4301
- package/src/channelSessionSupport.ts +0 -308
- package/src/codexAppServer.ts +0 -380
- package/src/codexOutput.ts +0 -846
- package/src/codexRuntimeOptions.ts +0 -80
- package/src/dependencyStatus.ts +0 -198
- package/src/forwardTunnel.ts +0 -859
- package/src/forwardTunnelProtocol.ts +0 -324
- package/src/index.ts +0 -1080
- package/src/json.ts +0 -49
- package/src/kandanQueue.ts +0 -113
- package/src/kandanTls.ts +0 -86
- package/src/localCapabilities.ts +0 -143
- package/src/localCodexMessageState.ts +0 -135
- package/src/localCodexTurnState.ts +0 -108
- package/src/localConfig.ts +0 -99
- package/src/localEditor.ts +0 -1061
- package/src/localEditorRuntime.ts +0 -717
- package/src/localForwarding.ts +0 -523
- package/src/oauth.ts +0 -425
- package/src/pendingKandanMessageQueue.ts +0 -109
- package/src/phoenix.ts +0 -359
- package/src/portForwardApproval.ts +0 -181
- package/src/portForwardWatcher.ts +0 -404
- package/src/protocol.ts +0 -321
- package/src/runner.ts +0 -943
- package/src/runnerConsoleReporter.ts +0 -142
- package/src/runnerLogger.ts +0 -50
- package/src/streamDeltaCoalescing.ts +0 -129
- package/src/streamDeltaQueue.ts +0 -102
package/README.md
CHANGED
|
@@ -16,21 +16,21 @@
|
|
|
16
16
|
║║ \"/` ___ ;_________║║_.'
|
|
17
17
|
║║ ` ^^ ^^ ║║
|
|
18
18
|
──────────╨╨─────────────··────··────────╨╨──────────────
|
|
19
|
-
your agent, your laptop,
|
|
19
|
+
your agent, your laptop, coding live
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Copy this into your terminal
|
|
22
|
+
Copy this into your terminal:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
25
|
codex --ask-for-approval never --sandbox danger-full-access -- 'Get me up and running with Linzumi from https://linzumi.com/agents.md. Read it with curl.'
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
That's the launch path: the first Codex is only the bootstrapper. It
|
|
29
|
-
opens the agent instructions,
|
|
30
|
-
the emailed code when it arrives,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
opens the agent instructions, confirms your email and workspace details,
|
|
30
|
+
asks you for the emailed code when it arrives, creates `/tmp/hello_linzumi`,
|
|
31
|
+
starts that hot-reload app on your computer, creates the shared support
|
|
32
|
+
channel, starts a Linzumi Codex session in a work thread, and opens the
|
|
33
|
+
browser editor pointed at the demo app.
|
|
34
34
|
|
|
35
35
|
The snippet uses automatic command approval and full local process access
|
|
36
36
|
because the bootstrapper must start a real runner and browser editor on this
|
|
@@ -47,26 +47,27 @@ agent" rarely means "works on your laptop." You merge, pull, run the
|
|
|
47
47
|
test suite, and find out at 4pm.
|
|
48
48
|
|
|
49
49
|
Linzumi gives it a third home: **your real laptop, in a thread your
|
|
50
|
-
team can watch live**. Real
|
|
50
|
+
team can watch live**. Real processes, real env vars, real dotfiles,
|
|
51
51
|
real teamwork. Diffs land in chat as the agent makes them. Your
|
|
52
52
|
reviewer opens a browser VS Code pointed at *your folder* and has an
|
|
53
53
|
opinion before the agent's even finished. You approve from your phone
|
|
54
54
|
on the way to lunch.
|
|
55
55
|
|
|
56
|
-
In three minutes from now you'll have it.
|
|
56
|
+
In three minutes from now you'll have it working end to end.
|
|
57
57
|
|
|
58
58
|
## What you'll have in three minutes
|
|
59
59
|
|
|
60
|
-
- **An AI coding agent running on your real laptop**,
|
|
61
|
-
your team can read along with.
|
|
62
|
-
- **A browser VS Code editor** pointed at
|
|
63
|
-
by link
|
|
64
|
-
|
|
60
|
+
- **An AI coding agent running on your real laptop**, editing the
|
|
61
|
+
generated Hello Linzumi app in a thread your team can read along with.
|
|
62
|
+
- **A browser VS Code editor** pointed at `/tmp/hello_linzumi`,
|
|
63
|
+
share-able by link with no clone and no deploy.
|
|
64
|
+
- **A tunneled local preview** of the app running on your computer with
|
|
65
|
+
hot reload.
|
|
65
66
|
- **A private support channel with the Linzumi team**, in case
|
|
66
67
|
anything goes sideways.
|
|
67
68
|
|
|
68
|
-
One pasted command. No cloud VM.
|
|
69
|
-
|
|
69
|
+
One pasted command. No cloud VM. The editor, agent, and dev server stay
|
|
70
|
+
on your laptop the whole time.
|
|
70
71
|
|
|
71
72
|
## Manual Runner Setup
|
|
72
73
|
|
|
@@ -74,9 +75,9 @@ The agent-first command above is the launch path. Use this manual path
|
|
|
74
75
|
when you want to connect your laptop yourself before starting work from
|
|
75
76
|
the browser.
|
|
76
77
|
|
|
77
|
-
You'll need **Node.js 20+**,
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
You'll need **Node.js 20+**, the **Codex CLI**, and a Chromium-based browser
|
|
79
|
+
(Chrome, Edge, Arc, or Brave). Safari mostly works; live collaboration is
|
|
80
|
+
smoother in Chromium.
|
|
80
81
|
|
|
81
82
|
```bash
|
|
82
83
|
npm install -g @linzumi/cli@latest
|
|
@@ -99,72 +100,79 @@ That's it for manual setup. The rest of this README is detail.
|
|
|
99
100
|
|
|
100
101
|
That one prompt is the launch path. The canonical agent instructions are
|
|
101
102
|
hosted at `https://linzumi.com/agents.md`; `https://linzumi.com/skills.md`
|
|
102
|
-
stays available for compatibility. The bootstrap agent will
|
|
103
|
-
email up front, ask for the emailed code after signup
|
|
104
|
-
hello to `@sean` in the shared support channel,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
stays available for compatibility. The bootstrap agent will confirm your
|
|
104
|
+
email and workspace choice up front, ask for the emailed code after signup
|
|
105
|
+
sends it, say hello to `@sean` in the shared support channel,
|
|
106
|
+
generate `/tmp/hello_linzumi`, start its hot-reload Node server, start the
|
|
107
|
+
runner for that folder, start a Linzumi Codex session in a work thread, and
|
|
108
|
+
open the browser editor. The Linzumi Codex session then adds confetti to the
|
|
109
|
+
demo page while you watch. Workspace names are plain display names from 2 to
|
|
110
|
+
100 characters; Linzumi generates the URL-safe workspace slug.
|
|
108
111
|
|
|
109
112
|
Under the hood, the npm package exposes these commands for the bootstrap
|
|
110
113
|
agent to run. They are not extra human setup steps after the one pasted
|
|
111
114
|
Codex command.
|
|
112
115
|
|
|
113
116
|
```bash
|
|
114
|
-
npx -y @linzumi/cli@latest signup --email alice@example.com --agent-name BuildBot
|
|
117
|
+
npx -y @linzumi/cli@latest signup --email alice@example.com --workspace-name "Alice's Linzumi" --agent-name BuildBot
|
|
115
118
|
npx -y @linzumi/cli@latest claim --pending <pending_id> --code <XXXX-XXXX>
|
|
116
119
|
npx -y @linzumi/cli@latest channel post <support_channel_id> "Hello @sean, starting this launch run."
|
|
117
|
-
npx -y @linzumi/cli@latest
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
--
|
|
120
|
+
npx -y @linzumi/cli@latest hello
|
|
121
|
+
(cd /tmp/hello_linzumi && npm run dev > /tmp/hello_linzumi/dev.log 2>&1 &)
|
|
122
|
+
npx -y @linzumi/cli@latest thread new "Hello Linzumi confetti" --message "Please add confetti when the page loads."
|
|
123
|
+
npx -y @linzumi/cli@latest agent runner /tmp/hello_linzumi \
|
|
124
|
+
--runner-id hello-linzumi-agent \
|
|
125
|
+
--allowed-cwd /tmp/hello_linzumi \
|
|
126
|
+
--forward-port 8787 \
|
|
127
|
+
--sandbox danger-full-access \
|
|
122
128
|
--approval-policy never
|
|
123
129
|
```
|
|
124
130
|
|
|
125
131
|
The agent-owned runner reads `~/.linzumi/agent-token.json`, uses the
|
|
126
132
|
workspace/channel scope from the approval flow, trusts only the selected
|
|
127
|
-
folder, and listens only to the
|
|
128
|
-
explicitly passed. The bootstrap
|
|
129
|
-
starting Codex in the Linzumi
|
|
133
|
+
folder, advertises the explicit preview port, and listens only to the
|
|
134
|
+
approving human unless `--listen-user` is explicitly passed. The bootstrap
|
|
135
|
+
agent waits for `Runner connected:` before starting Codex in the Linzumi
|
|
136
|
+
thread.
|
|
130
137
|
|
|
131
138
|
By default, the runner downloads the Linzumi-approved `code-server`
|
|
132
139
|
runtime for your platform and verifies its checksum before enabling the
|
|
133
140
|
browser editor. Linux editor launches are wrapped with `bubblewrap`
|
|
134
141
|
(`bwrap`) for filesystem confinement.
|
|
135
142
|
|
|
136
|
-
`linzumi claim` also prints `
|
|
137
|
-
into `#general` in their own
|
|
138
|
-
`#linzumi-support`, a shared channel
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
`linzumi claim` also prints `workspace_name`, `workspace_id`, and `login_url`.
|
|
144
|
+
That one-time link logs the human into `#general` in their own selected
|
|
145
|
+
workspace. The claim also provisions `#linzumi-support`, a shared channel
|
|
146
|
+
connected to Linzumi's workspace so our team can see setup issues from our
|
|
147
|
+
side; the bootstrap agent posts a hello there with the printed
|
|
148
|
+
`support_channel_id`.
|
|
149
|
+
Keep demo work in task threads; use the support channel when signup, runner,
|
|
150
|
+
preview, or browser-editor setup gets stuck.
|
|
142
151
|
|
|
143
152
|
Once the runner is online, the bootstrap agent can ask Linzumi to start
|
|
144
153
|
Codex and open the browser editor for the same thread and folder:
|
|
145
154
|
|
|
146
155
|
```bash
|
|
147
156
|
npx -y @linzumi/cli@latest codex start <thread_id> \
|
|
148
|
-
--runner hello-
|
|
149
|
-
--cwd
|
|
150
|
-
--work-description "
|
|
157
|
+
--runner hello-linzumi-agent \
|
|
158
|
+
--cwd /tmp/hello_linzumi \
|
|
159
|
+
--work-description "Work only in /tmp/hello_linzumi. Add tasteful confetti when the Hello Linzumi page loads, keep the hot-reload app working on port 8787, and post the exact files changed."
|
|
151
160
|
|
|
152
161
|
npx -y @linzumi/cli@latest editor open <thread_id> \
|
|
153
|
-
--runner hello-
|
|
154
|
-
--cwd
|
|
162
|
+
--runner hello-linzumi-agent \
|
|
163
|
+
--cwd /tmp/hello_linzumi
|
|
155
164
|
```
|
|
156
165
|
|
|
157
|
-
The launch target for this path is zero-to-
|
|
158
|
-
3 minutes, measured from `signup` through
|
|
159
|
-
|
|
166
|
+
The launch target for this path is zero-to-Hello-Linzumi-editor+preview in
|
|
167
|
+
under 3 minutes, measured from `signup` through browser VS Code readiness,
|
|
168
|
+
forwarded preview readiness, and the first visible Codex edit.
|
|
160
169
|
|
|
161
170
|
## What just happened
|
|
162
171
|
|
|
163
172
|
You now have:
|
|
164
173
|
|
|
165
|
-
- **A runner.** Your laptop, listed in the workspace, advertising
|
|
166
|
-
|
|
167
|
-
list).
|
|
174
|
+
- **A runner.** Your laptop, listed in the workspace, advertising
|
|
175
|
+
`/tmp/hello_linzumi` and the explicit preview port.
|
|
168
176
|
- **A workspace** you can invite teammates into. They open the same
|
|
169
177
|
browser app, see the same threads, and can start their own runners
|
|
170
178
|
on their own machines.
|
|
@@ -172,18 +180,16 @@ You now have:
|
|
|
172
180
|
**cannot** see your repo contents, your tokens, your Codex
|
|
173
181
|
transcripts, your editor session, or your other threads. Stuck?
|
|
174
182
|
Post there — we read it.
|
|
175
|
-
- **A browser VS Code editor**,
|
|
176
|
-
|
|
183
|
+
- **A browser VS Code editor**, opened against `/tmp/hello_linzumi` and
|
|
184
|
+
ready for shared editing.
|
|
177
185
|
|
|
178
186
|
## Three things to try first
|
|
179
187
|
|
|
180
|
-
1. **
|
|
181
|
-
|
|
182
|
-
opened a single file. Days saved on day one.
|
|
188
|
+
1. **Watch the demo change live.** The Linzumi Codex session edits the
|
|
189
|
+
generated page, and hot reload shows the change in the tunneled preview.
|
|
183
190
|
2. **Make a real change without context-switching.** The Codex session
|
|
184
191
|
running in Linzumi edits files on your disk. Watch the diff land in
|
|
185
|
-
chat, or jump into the browser editor
|
|
186
|
-
pointed at your folder) and shape it yourself.
|
|
192
|
+
chat, or jump into the browser editor and shape it yourself.
|
|
187
193
|
3. **Show a teammate something on your screen.** Open the browser
|
|
188
194
|
editor or share your local dev server through a normal HTTPS
|
|
189
195
|
link. No exposing localhost, no copy-pasting IPs, no "screenshare
|
|
@@ -241,9 +247,6 @@ intentionally. Every action is auditable from the thread.
|
|
|
241
247
|
- **`linzumi: command not found`** — your global npm bin folder isn't
|
|
242
248
|
on `PATH`. Run `npm prefix -g`; add the printed path's `bin` folder
|
|
243
249
|
to your shell.
|
|
244
|
-
- **`bun: command not found`** — install Bun, then rerun
|
|
245
|
-
`linzumi start`. The `linzumi` binary is a node shim that delegates
|
|
246
|
-
to Bun for fast TypeScript startup.
|
|
247
250
|
- **`codex: command not found`** — install the Codex CLI, or pass
|
|
248
251
|
`--codex-bin <path>` to `linzumi start`.
|
|
249
252
|
- **Browser sign-in opens but never returns to the CLI.** Your browser
|
|
@@ -258,7 +261,7 @@ intentionally. Every action is auditable from the thread.
|
|
|
258
261
|
## Pinning a version
|
|
259
262
|
|
|
260
263
|
```bash
|
|
261
|
-
npm install -g @linzumi/cli@0.0.
|
|
264
|
+
npm install -g @linzumi/cli@0.0.22-beta
|
|
262
265
|
linzumi --version
|
|
263
266
|
```
|
|
264
267
|
|
package/bin/linzumi.js
CHANGED
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
if (globalThis.WebSocket === undefined) {
|
|
4
|
+
const { WebSocket } = await import("ws");
|
|
5
|
+
globalThis.WebSocket = WebSocket;
|
|
6
|
+
}
|
|
6
7
|
|
|
7
|
-
const
|
|
8
|
-
const entrypoint = join(packageRoot, "src", "index.ts");
|
|
9
|
-
const result = spawnSync("bun", ["run", entrypoint, ...process.argv.slice(2)], {
|
|
10
|
-
cwd: process.cwd(),
|
|
11
|
-
env: process.env,
|
|
12
|
-
stdio: "inherit",
|
|
13
|
-
});
|
|
8
|
+
const { main } = await import("../dist/index.js");
|
|
14
9
|
|
|
15
|
-
|
|
16
|
-
process.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
);
|
|
20
|
-
process.exit(127);
|
|
10
|
+
try {
|
|
11
|
+
await main(process.argv.slice(2));
|
|
12
|
+
} catch (error) {
|
|
13
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
14
|
+
process.exit(1);
|
|
21
15
|
}
|
|
22
|
-
|
|
23
|
-
process.exit(result.status ?? 1);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="4096" height="4096" aria-label="Linzumi" color="#0e404b"><path fill="currentColor" fill-rule="evenodd" d="M2111 3966c-37 2-34 3-69 2l-141-7c-34-2-36-1-65-5l-107-15c-30-5-43-7-76-15a3031 3031 0 0 1-217-61l-84-31c-26-10-33-11-70-29a2233 2233 0 0 1-423-259 1796 1796 0 0 1-381-416 1962 1962 0 0 1-168-298c-25-57-54-131-74-191-19-59-35-127-45-168-11-40-11-45-16-76-5-30-11-58-16-107-6-48-13-132-16-183q-2-77 1-122c0-31 1-30 3-61 3-31 8-89 13-126 4-37 4-47 14-95a1863 1863 0 0 1 475-956q51-56 92-94c27-26 36-36 71-65s99-79 137-107 62-43 90-61a1539 1539 0 0 1 156-88c31-15 58-31 104-49a1697 1697 0 0 1 492-133c61-9 144-19 202-22s111 1 145 2c34 2 30 6 57 9s70 5 103 9 56 7 96 15q59 10 141 30c54 15 143 44 187 59s47 18 77 31 59 25 102 48 108 59 157 89a2162 2162 0 0 1 210 153c27 23 50 42 88 80s99 101 141 148c41 48 74 91 106 138 33 46 67 104 90 141a1170 1170 0 0 1 92 180c17 40 44 107 59 149 16 41 22 63 32 99a3000 3000 0 0 1 47 195c5 28 9 46 14 95s13 137 16 198c2 62-1 123-4 172-2 50-7 88-11 126l-16 103a3048 3048 0 0 1-62 248c-10 31-17 49-29 80-12 32-22 60-44 108-23 48-64 130-92 180s-57 90-77 121l-45 62a3211 3211 0 0 1-153 182q-32 35-76 76a2201 2201 0 0 1-349 260c-50 28-132 69-180 91-48 23-76 32-108 44-33 12-42 17-84 30-42 12-109 33-168 46-60 12-130 24-187 31-58 6-119 8-157 10m9-294c18-3 10-6 14-12 4-5 4-11 9-19 6-7 16-19 25-27 10-8 14-12 31-18 16-6 50-14 69-17 18-3 33-1 42-2 8-1 6-3 7-4 1-2 10 3 0-4-11-7-46-26-65-40s-37-32-50-44c-13-13-18-17-29-31-12-14-29-41-39-53s-11-17-19-19q-11-3-31 4c-14 3-40 9-53 14s-15 6-23 15c-8 8-20 28-27 35-6 7-5 5-11 7s-18 5-27 4q-15-2-27-9c-6-6-11-18-14-24-3-7-4-9-4-16l3-26q2-17 12-39c7-13 14-26 31-42 16-15 56-41 68-51s5-5 5-10c1-4 4-6-1-17a341 341 0 0 0-80-101c-18-14-41-24-58-32-16-9-15-9-43-18-28-8-98-27-125-36-27-8-21-7-38-15l-61-32c-13-7-10-4-20-12l-41-34a114 114 0 0 1-34-54q-5-17 0-30c3-10 0-9 15-27 16-18 54-59 76-80 23-21 37-30 58-45a1278 1278 0 0 1 126-78c18-9 40-15 53-20q18-9 23-14c4-3 5 4 3-7-3-11-14-37-17-57-3-21-3-46 0-65q4-27 15-50 13-25 29-46 15-19 35-30c13-8 32-15 46-18q18-5 34-3l34 2q15 2 27 7c8 4 19 11 23 15 3 5 5 1-2 12-8 11-31 34-43 53q-18 30-30 65c-7 24-14 65-15 80-2 16 2 9 5 12l12 8q5 2 8-3c3-2 10-4 13-13 4-8 2-19 8-38 6-18 18-54 29-73 10-19 21-28 34-41q20-21 42-35c14-9 24-13 42-17 18-3 46-5 65-5 18 0 29 1 46 7 16 6 39 20 53 30q20 17 32 35c9 12 14 22 19 38s10 38 10 57c0 20-4 45-9 61q-7 25-18 40c-5 10-7 12-16 21-9 10-24 24-37 34-13 9-33 17-41 24-7 6-5 12-4 15q-2 4 7 3c7 1 13 3 34-1 21-3 62-16 91-21a632 632 0 0 1 271 0c24 4 31 8 47 13l45 17c18 8 41 18 61 31a541 541 0 0 1 153 152q18 27 28 50a878 878 0 0 1 35 103c5 21 9 33 12 61s3 88 4 107c2 19 3 8 5 9 2 2-6 8 8 1 13-7 52-29 73-44s34-28 52-46 41-46 56-65q20-26 29-46c8-13 10-14 18-34s22-57 28-84c7-27 7-58 9-80 1-22 0-35-1-54a481 481 0 0 0-53-194c-13-24-31-52-47-73a530 530 0 0 0-114-99q-33-19-58-31a650 650 0 0 0-99-28l-46-3h-107c-20-2-9-5-11-9s-2-12 0-16q1-4 7-7l27-9 46-7 65-2q32-1 65 3c21 3 46 11 64 16a464 464 0 0 1 256 183c13 17 18 23 31 46 12 23 34 69 43 93 10 24 11 28 16 50l14 80c3 14 1 5 3 6q3 3 8 1c2-1 0 5 6-7q11-20 31-65l45-111a2679 2679 0 0 0 76-279 1612 1612 0 0 0 21-343c-1-36-1-62-7-111s-23-142-31-183c-7-40-7-34-14-61-8-27-16-57-31-99s-40-107-60-153-36-77-62-122a1923 1923 0 0 0-184-266c-38-43-90-98-133-138-44-41-96-81-127-106s-39-29-61-44-36-26-72-46c-37-21-97-55-145-78a1921 1921 0 0 0-245-90 1334 1334 0 0 0-336-55c-40-2-99-4-148-3a1957 1957 0 0 0-248 26c-30 6-35 6-73 16s-106 28-156 46a1494 1494 0 0 0-406 211c-40 31-93 73-133 108-39 36-78 77-106 106-27 29-40 46-58 67l-46 59-76 111q-30 47-48 80a2814 2814 0 0 0-75 153c-12 28-17 39-30 76s-33 96-46 145a1912 1912 0 0 0-48 267 2164 2164 0 0 0-4 233 1469 1469 0 0 0 51 328 1340 1340 0 0 0 62 183c12 32 22 59 45 103 22 45 73 138 89 166 17 29 5 6 8 5 2-1 6 1 7-10 2-12 0-33 3-58a1421 1421 0 0 1 30-145 837 837 0 0 1 59-164c13-26 28-59 46-88a1133 1133 0 0 1 242-274 1321 1321 0 0 1 170-106 890 890 0 0 1 229-76q45-11 80-15c25-4 43-4 69-7 26-4 69-10 88-15s21-11 27-14c5-4 5-3 7-8 1-5 2-16 0-21-2-6 8-7-11-13s-72-14-103-22c-31-9-65-21-84-28s-17-7-29-15l-44-30c-7-7-3-6-2-8s-8 1 6-7l76-41c15-8 8-3 12-3s1-2 11 2c10 5 32 18 50 25a340 340 0 0 0 168 18c10-2 10-4 12-9s6-7-1-20c-7-14-33-49-42-63l-9-17q-3-5 0-7c1-2-8-1 9-6 18-4 78-19 96-21s5 0 13 8 23 27 36 39c14 12 33 24 46 32a144 144 0 0 0 69 21c14 0 37-1 53-5 16-3 27-7 42-15s35-20 50-33 26-38 42-45c16-6 37 4 53 7 17 3 37 9 46 12s7 3 7 6c1 3 8-3-2 11l-60 77c-10 14-4 6-5 11s0 15 1 19q2 6 6 8c2 2-1 3 7 4l42 2c17-1 33 1 57-5 25-6 69-22 88-29 20-7 24-10 31-15q9-6 13-11 5-3 10-2c3 0-5-6 11 2s70 37 84 46c15 9 3 6 3 8s5-1-3 5l-41 29c-11 7-8 7-24 14-16 8-49 22-72 30s-30 13-65 20c-35 6-108 13-145 19s-59 10-77 15c-17 5-16 7-26 14-11 8-20 12-37 29s-44 51-65 73-48 45-62 58c-15 12-12 10-25 18l-52 30-30 15-50 16c-18 5-29 9-57 15l-111 21c-27 6-32 8-53 15q-33 12-73 31-36 16-80 45a709 709 0 0 0-238 270c-15 28-22 49-29 69-8 20-12 30-17 49-5 20-11 39-16 69-4 31-11 83-13 115-2 31-2 45 0 76l14 111c5 28 11 44 16 61l14 42q11 29 32 71c16 28 40 68 60 97a712 712 0 0 0 299 246c33 15 81 34 111 44s39 11 69 17q43 8 107 16c42 4 107 8 148 9s78-2 97-4m915-1801-54 1c-17 0-21 2-49-3-28-6-87-21-119-32-31-10-47-20-72-33-26-13-64-34-80-44-16-9 2-2-16-11a1748 1748 0 0 0-190-90c-32-13-69-24-88-30s-17-2-27-5c-9-3-12-7-30-11a914 914 0 0 0-191-30c-29-2-36-2-61-1q-41-1-92 3a1494 1494 0 0 0-175 28 1889 1889 0 0 0-184 60c-24 10-21 6-68 31s-164 91-214 116-65 26-88 33c-23 8-32 9-49 12a606 606 0 0 1-164 2c-19-4-43-12-58-17-15-4-16-5-30-13-15-8-42-24-58-35a286 286 0 0 1-64-58q-15-17-30-41-17-28-32-61a352 352 0 0 1-22-127c0-22 1-50 5-72q6-32 18-61a361 361 0 0 1 164-183 366 366 0 0 1 125-44c19-3 40-1 50-3s10 10 12-7c3-17 0-70 3-95 2-25 6-37 11-54a388 388 0 0 1 66-127 509 509 0 0 1 87-79 578 578 0 0 1 104-48c19-5 52-10 68-13 16-2 14-1 27-1q20-1 50 2 30 2 68 12c26 8 69 30 84 35s3 2 8-7l19-48 15-27c5-9 8-14 19-27 10-12 25-33 42-49q27-25 59-46a384 384 0 0 1 94-44q20-7 50-12a507 507 0 0 1 137-1q30 5 53 13c16 5 26 8 42 16a561 561 0 0 1 96 58c12 10 18 16 31 31l44 57c10 15 10 17 16 30l19 49c5 10-1 10 8 7 9-2 32-15 48-21a410 410 0 0 1 109-26c18-2 28-4 53-2s69 9 95 16c27 7 49 19 65 26 16 8 19 11 31 19a595 595 0 0 1 73 62q17 19 34 42a439 439 0 0 1 47 107c5 17 8 26 10 50s0 78 3 95c2 17 2 5 12 7 11 2 32 0 50 3q27 3 57 13a412 412 0 0 1 137 79c17 13 22 20 32 32a347 347 0 0 1 62 99c8 16 9 17 14 38 4 22 12 61 12 92s-6 72-10 95c-5 24-8 30-16 46a499 499 0 0 1-59 95q-14 18-30 31c-11 10-20 18-35 28a705 705 0 0 1-88 46l-49 16q-23 5-46 6m-1146 957q10-1 16-9c6-5 13-16 17-21 3-6 2-6 3-12 0-5 2-11-2-19-3-7-13-20-19-26q-12-9-22-10c-6-2-8-2-15 0s-21 7-28 13q-10 11-15 23-3 10-1 19c2 8 9 20 13 27q8 8 16 12c4 3 5 3 11 4s19 1 26-1"/></svg>
|