on master help sign in
63 files changed+2035−4076
since splitsnapshots
unifiedsplit
.gitignore+4 INSTRUCTIONS.md+150 LICENSE+7 NOTICE+39 README.md+307 dev/elm-live.sh+17−5 docs/screenshot.png flake.lock+45 flake.nix+114 frontend/airlock.patch+16 frontend/assets/css/fonts.css+10 frontend/assets/css/main.css+1−1 frontend/assets/img/tile.png frontend/elm-srcs.nix+267 frontend/elm.json+2−2 frontend/index.html+2−2 frontend/registry.dat frontend/script.js+3−2 frontend/src/Main.elm+10−8 zod/seax/app/seax.hoon+102−82 zod/seax/desk.docket-0+10 zod/seax/lib/dbug.hoon+9−3 zod/seax/lib/docket.hoon+223 zod/seax/lib/engines.hoon+1−3 zod/seax/lib/engines/alexandria.hoon−32 zod/seax/lib/engines/crowdview.hoon+3−5 zod/seax/lib/engines/urbit-dev.hoon+16−9 zod/seax/lib/engines/wiby.hoon+3−5 zod/seax/lib/engines/yep.hoon−30 zod/seax/lib/graph-store.hoon−919 zod/seax/lib/migrate.hoon−19 zod/seax/lib/resource.hoon−57 zod/seax/lib/server.hoon+159 zod/seax/lib/strand.hoon−1 zod/seax/lib/strandio.hoon−812 zod/seax/mar/css.hoon+25 zod/seax/mar/docket-0.hoon+25 zod/seax/mar/hoon.hoon+285−31 zod/seax/mar/html.hoon+22 zod/seax/mar/js.hoon+25 zod/seax/mar/png.hoon+12 zod/seax/mar/txt-diff.hoon+16 zod/seax/mar/txt.hoon−1 zod/seax/mar/woff2.hoon+12 zod/seax/sur/cite.hoon−57 zod/seax/sur/diary-0.hoon−323 zod/seax/sur/diary.hoon−335 zod/seax/sur/docket.hoon+82 zod/seax/sur/epic.hoon−15 zod/seax/sur/graph-store.hoon−272 zod/seax/sur/group-store.hoon−39 zod/seax/sur/group.hoon−109 zod/seax/sur/groups.hoon−364 zod/seax/sur/hark-store.hoon−159 zod/seax/sur/meta.hoon−21 zod/seax/sur/metadata-store.hoon−138 zod/seax/sur/notes.hoon−74 zod/seax/sur/post.hoon−91 zod/seax/sur/pull-hook.hoon−11 zod/seax/sur/resource.hoon−10 zod/seax/sur/seax.hoon+10−1 zod/seax/sur/spider.hoon−27 zod/seax/sys.kelvin+1−1
.gitignore+4
@@ -6,3 +6,7 @@ zod/.http.ports
66zod/.run
77zod/.urb
88zod/.vere.lock
9+result
10+result-*
11+frontend/assets/fonts
12+frontend/airlock
INSTRUCTIONS.mdnew file+150
@@ -0,0 +1,150 @@
1+# Installation Instructions
2+
3+You need [Nix](https://nixos.org/download/) with flakes enabled to build the desk, and a ship on Urbit OS 408k to run it.
4+If flakes aren't enabled, add `--extra-experimental-features 'nix-command flakes'` after `nix` in each command.
5+The flake builds on x86_64-linux, aarch64-linux and aarch64-darwin; nixpkgs no longer supports Intel Macs.
6+On an Intel Mac, build the desk on one of those systems and copy the files in `result` over, e.g. with `scp -r` or `cp -RL` (a plain `cp -R` copies only the `result` symlink).
7+
8+## On a fake ship
9+
10+To try %seax out, run it on a fake ~zod. This also needs the Urbit runtime (Vere) 4.4 or newer, or Nix to run it. These steps were tested with Vere 4.6.
11+
12+1. Clone the **seax** project and build the desk. The build ends up in `result`.
13+
14+```bash
15+$ git clone https://github.com/iko-soy/seax
16+$ nix build ./seax
17+```
18+
19+2. Download the v4.6 pill (Urbit OS 408k) and start your fake zod using the pill.
20+
21+```bash
22+$ curl -LO https://bootstrap.urbit.org/urbit-v4.6.pill
23+$ urbit -B urbit-v4.6.pill -F zod --http-port 8080
24+```
25+
26+Without Vere installed, you can run the one from the nixpkgs that the flake pins instead:
27+
28+```bash
29+$ nix run --inputs-from ./seax nixpkgs#urbit -- -B urbit-v4.6.pill -F zod --http-port 8080
30+```
31+
32+On an Intel Mac, download [Vere's macOS x86_64 build](https://bootstrap.urbit.org/vere/live/v4.6/vere-v4.6-macos-x86_64), make it executable with `chmod +x vere-v4.6-macos-x86_64`, and run `./vere-v4.6-macos-x86_64` in place of `urbit`.
33+
34+`--http-port 8080` puts the web interface on port 8080. Without it, Vere tries port 80 first, which works on macOS.
35+If port 8080 is taken, Vere stops; choose another port, and use it in step 6.
36+
37+Booting takes about a minute.
38+The fake ship can't download apps such as Landscape, so it prints errors like `http: fail (..., 504)` and `docket: thread failed`; they don't affect %seax.
39+
40+3. Now, inside dojo run the following:
41+```bash
42+dojo> |new-desk %seax
43+dojo> |mount %seax
44+```
45+
46+4. Back in your shell, in the directory where you ran step 1, replace the mounted desk with the build.
47+Don't do this inside `seax`: its own `zod/seax` holds the desk's source.
48+```bash
49+$ rm -r zod/seax/*
50+$ cp -r result/* zod/seax/
51+$ chmod -R u+w zod/seax
52+```
53+
54+The files Nix builds are read-only, and `chmod` makes the copies writable, so that the next update can replace them.
55+
56+5. In the dojo install the seax agent.
57+```bash
58+dojo> |commit %seax
59+dojo> |install our %seax
60+```
61+
62+6. Go to `http://localhost:8080/apps/seax/` in your browser.
63+Log in with the code that `+code` prints in the dojo.
64+If the page only says "bad session auth", your browser still has a cookie from an earlier fake ship; reload the page.
65+
66+To update the desk later, run `git -C seax pull` and `nix build ./seax`, repeat step 4 and run `|commit %seax`.
67+
68+## On your own ship
69+
70+1. Build the desk as in step 1 above.
71+
72+2. In your ship's dojo, create the desk and mount it. `|mount` puts its files in your pier, at `<pier>/seax`.
73+```bash
74+dojo> |new-desk %seax
75+dojo> |mount %seax
76+```
77+
78+3. Replace the mounted desk with the build:
79+```bash
80+$ rm -r <pier>/seax/*
81+$ cp -r result/* <pier>/seax/
82+$ chmod -R u+w <pier>/seax
83+```
84+
85+4. Install it:
86+```bash
87+dojo> |commit %seax
88+dojo> |install our %seax
89+```
90+
91+5. Open `/apps/seax/` at your ship's web address, or click the %seax tile in Landscape.
92+
93+To update it later, run `git -C seax pull` and `nix build ./seax`, then repeat steps 3 and 4.
94+
95+### Upgrading from the 2023 version
96+
97+The 2023 desk was made for Urbit OS 413k, so it was suspended before your ship could update to 408k.
98+Upgrade it with the steps above, without `|new-desk`: run `|mount %seax` if the desk isn't mounted, then replace its files and run `|commit %seax` and `|install our %seax`.
99+
100+The new agent drops the old searches and closes their subscriptions.
101+It also drops the copy of your Tlon notes, if the old version made one, and the list of peers, and calls off the pings that are still waiting for an answer; see [Peers (disabled)](README.md#peers-disabled).
102+
103+Because the desk dates from before Urbit OS 410k, your ship counts it as essential: a later Urbit OS update waits until %seax supports it, instead of suspending %seax.
104+To have it suspended like other apps, run:
105+```bash
106+dojo> |essential-desk %seax |
107+```
108+`+vats %seax` shows which it is, under `essential desk`.
109+
110+### Removing it
111+
112+- `|uninstall %seax` stops the agent and keeps its data. `/apps/seax/` then answers with an error.
113+- `|nuke %seax` deletes the agent's data. It asks for confirmation first.
114+- `|unmount %seax` deletes `<pier>/seax`. The desk itself stays in your ship, because no command deletes desks.
115+
116+# Development
117+
118+With %seax installed on a running ship (see above), run this in another terminal:
119+```bash
120+$ ./seax/dev/elm-live.sh
121+```
122+
123+This serves the frontend at `http://localhost:8000`, with Elm's debugger, and rebuilds it when the code changes.
124+Requests to `/~/` are passed on to the ship at `http://localhost:8080`; set `SHIP_URL` if your ship is elsewhere.
125+Log in at `http://localhost:8000/~/login` first (reload on "bad session auth"), then open `http://localhost:8000/`.
126+
127+With Nix, the script gets Elm, elm-live, the web font and a patched [airlock](https://github.com/iko-soy/airlock) by itself.
128+Without Nix, you need `elm` 0.19.2 and `elm-live`, and airlock at commit 7e85737 (as pinned in `flake.lock`) in `frontend/airlock`, with `frontend/airlock.patch` applied:
129+```bash
130+$ git clone https://github.com/iko-soy/airlock seax/frontend/airlock
131+$ git -C seax/frontend/airlock checkout 7e85737
132+$ git -C seax/frontend/airlock apply ../airlock.patch
133+```
134+There is no `frontend/assets/fonts/` then, so the browser uses another font wherever the page would use Roboto.
135+
136+To build the desk without Nix, set up airlock as above and run `elm make src/Main.elm --optimize --output elm.js` in `seax/frontend`.
137+Then, in step 4, copy `seax/zod/seax/*` instead of `result/*`, and copy `index.html`, `elm.js`, `script.js`, `fetch-event-source.js` and `assets/` from `seax/frontend` into the mounted desk's `web/` directory.
138+
139+The Nix build pins the Elm packages in `frontend/elm-srcs.nix` and `frontend/registry.dat`.
140+After changing `frontend/elm.json`, regenerate them:
141+```bash
142+$ cd seax/frontend
143+$ nix develop .. --command sh -c 'elm2nix convert > elm-srcs.nix && elm2nix snapshot'
144+```
145+
146+# Usage Instructions
147+
148+Type a query, then press Enter or click "search": %seax collects results from its search sources.
149+On the results page, click a source to show only its results; click more sources to add theirs, and click a source again to remove it.
150+The README's [Usage](README.md#usage) section has more.
LICENSEnew file+7
@@ -0,0 +1,7 @@
1+Copyright 2023 Ilia Kostiuchenko and Evangelos Lamprou
2+
3+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4+
5+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6+
7+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
NOTICEnew file+39
@@ -0,0 +1,39 @@
1+%seax is under the MIT License in LICENSE, except for these files from other
2+projects:
3+
4+- zod/seax/lib/dbug.hoon, zod/seax/lib/server.hoon and the marks in
5+ zod/seax/mar/ other than docket-0.hoon are copied from pkg/base-dev in
6+ urbit/urbit 408k-2 (https://github.com/urbit/urbit).
7+ MIT License, Copyright (c) 2015 Urbit.
8+
9+- zod/seax/lib/docket.hoon, zod/seax/sur/docket.hoon and
10+ zod/seax/mar/docket-0.hoon are copied from pkg/landscape in urbit/urbit
11+ 408k-2. MIT License, Copyright (c) 2015 Urbit.
12+
13+- zod/seax/lib/de-html.hoon is adapted from ++de-xml in
14+ pkg/arvo/sys/zuse.hoon of urbit/urbit, as of July 2023.
15+ MIT License, Copyright (c) 2017 Urbit.
16+
17+- frontend/fetch-event-source.js is the bundle from airlock's example
18+ (https://github.com/iko-soy/airlock), a modified build of
19+ @microsoft/fetch-event-source (https://github.com/Azure/fetch-event-source).
20+ MIT License, Copyright (c) Microsoft Corporation, and
21+ MIT License, Copyright 2023 Ilia Kostiuchenko.
22+
23+- The built frontend includes the Roboto font, which is under the SIL Open
24+ Font License 1.1. Its license is next to it in web/assets/fonts/.
25+
26+- The built frontend's web/elm.js includes compiled code from airlock
27+ (MIT License, Copyright 2023 Ilia Kostiuchenko) and from some of the Elm
28+ packages in frontend/elm.json, all of them under the BSD-3-Clause, MIT or
29+ Apache-2.0 license. elm.json also lists MPL-2.0 packages by ianmackenzie,
30+ such as elm-geometry and elm-3d-scene, but no code from them is compiled
31+ in. Each package's license comes with its source.
32+
33+The MIT License, under the copyright lines above:
34+
35+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
36+
37+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
38+
39+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
README.mdnew file+307
@@ -0,0 +1,307 @@
1+<p align="center">
2+ <img src="frontend/assets/img/logo.png" alt="%seax" width="510">
3+</p>
4+
5+The [Urbit](https://urbit.org/) meta-search engine.
6+
7+<p align="center">
8+ <img src="docs/screenshot.png" alt="%seax showing results for &quot;urbit&quot; from %wiby and %urbit-dev" width="700">
9+</p>
10+
11+## About
12+
13+It's time Urbit got some searching capabilities.
14+
15+For most people, their computer is a bootloader to the closest search engine. Searching is a central part of everyone's computing workflow.
16+
17+The `%seax` meta-search engine is able to aggregate results from open search APIs and bring them inside the comfort of your Urbit ship. No longer do you have to keep a second tab open.
18+
19+Let's make searching fun again. :)
20+
21+## Contents
22+
23+- [Features](#features)
24+- [Search sources](#search-sources)
25+- [Requirements](#requirements)
26+- [Installation](#installation)
27+- [Usage](#usage)
28+- [How it works](#how-it-works)
29+- [Ranking](#ranking)
30+- [Privacy and network traffic](#privacy-and-network-traffic)
31+- [Peers (disabled)](#peers-disabled)
32+- [Debugging](#debugging)
33+- [Adding a search source](#adding-a-search-source)
34+- [Development](#development)
35+- [Project layout](#project-layout)
36+- [Known issues](#known-issues)
37+- [History](#history)
38+- [Credits](#credits)
39+- [License](#license)
40+
41+## Features
42+
43+- One search box for several search engines. Your ship sends the query to all of them and shows their results on one page.
44+- Results appear as each source answers, without waiting for the slowest.
45+- A page that more than one source returns is shown once and ranked higher.
46+- Click a source's name to see only its results.
47+- Runs on your own ship at `/apps/seax/`, with a tile in Landscape. Only you can search: visitors who aren't logged in are sent to the login page.
48+- Nothing runs in the background: %seax sends requests only when you search.
49+
50+## Search sources
51+
52+| Source | Shown as | What it is | Request your ship sends | Status (October 2026) |
53+|---|---|---|---|---|
54+| [wiby](https://wiby.me/) | `%wiby` | "Search Engine for the Classic Web", an index of simple, older-style pages | `GET https://wiby.me/json/?q=<query>`, wiby's public JSON API | Works |
55+| [Urbit docs](https://docs.urbit.org/) | `%urbit-dev` | The site search of docs.urbit.org, which is built on GitBook | `POST https://docs.urbit.org/~gitbook/search` with `{"query": "<query>", "scope": {"mode": "all"}}` | Works |
56+| [CrowdView](https://crowdview.ai/) | `%crowdview` | A search engine for forum discussions (Reddit, Hacker News, Stack Exchange and others) | `GET https://crowdview-next-js.onrender.com/api/search-v3?query=<query>`, the endpoint crowdview.ai's own page uses | Works, but has no results for many queries, such as "urbit" |
57+
58+The query is URL-encoded in the GET requests, and sent as a JSON string to the Urbit docs, whose request also has a `content-type: application/json` header. Your ship adds no user agent, cookies or other headers: Vere sends only `Host`, and `Content-Length` when there's a body.
59+
60+The page's sources row shows each source that is still loading or found something. A source that fails, or has no results, is hidden.
61+
62+Until October 2026, %seax also searched [Yep](https://yep.com/). By then Yep blocked requests that don't come from a browser, so it returned no results, but every search still sent it your query. Its official API needs an API key and is paid after 1,000 requests.
63+
64+## Requirements
65+
66+- A ship running Urbit OS 408k, which needs Vere 4.4 or newer (4.6 is current). The desk declares `[%zuse 408]` in `zod/seax/sys.kelvin`. When your ship moves to a newer Urbit OS, it suspends %seax until you install a version of the desk that declares the new one. A desk upgraded from the 2023 version is the exception; see [Installation](#installation).
67+- To build the desk: [Nix](https://nixos.org/download/) with flakes enabled, on x86_64-linux, aarch64-linux or aarch64-darwin. Nix fetches Elm and the other build tools already built from cache.nixos.org, so the build only compiles the frontend and copies files.
68+
69+## Installation
70+
71+[INSTRUCTIONS.md](INSTRUCTIONS.md) has the full steps: on a fake ship to try %seax out, on your own ship, upgrading the 2023 version, and removing %seax. In short:
72+
73+1. Build the desk: `nix build` in a clone of this repository puts it in `result/`.
74+2. In your ship's dojo, create and mount a desk: `|new-desk %seax`, then `|mount %seax`.
75+3. Replace the files of the mounted desk, `<pier>/seax/`, with those in `result/`. Nix's files are read-only, so make the copies writable with `chmod -R u+w <pier>/seax`, or the next update can't replace them.
76+4. In the dojo: `|commit %seax`, then `|install our %seax`.
77+
78+If you installed the 2023 version, which was made for Urbit OS 413k, it was suspended before your ship could update to 408k. Upgrade it the same way, without `|new-desk`. The new agent drops the old searches, the list of peers, and the copy of your Tlon notes if the old version made one. Because the desk dates from before Urbit OS 410k, your ship counts it as essential: a later Urbit OS update waits until %seax supports it, instead of suspending %seax. Run `|essential-desk %seax |` to have it suspended like other apps.
79+
80+To remove %seax, run `|uninstall %seax`, which stops it and keeps its data. `|nuke %seax` then deletes the data.
81+
82+## Usage
83+
84+Open `/apps/seax/` at your ship's web address, e.g. `http://localhost:8080/apps/seax/`, or click the %seax tile in Landscape. If you aren't logged in, you'll be asked for your `+code` first.
85+
86+- Type a query, then press Enter or click **search**.
87+- The **Sources** row names each source that is still loading or has results. Sources that are loading pulse between grey and black, and can't be clicked until they finish.
88+- Click a source to show only its results. Click more sources to add theirs, and click a source again to remove it. With no source selected, all results are shown. The selection stays when you search again.
89+- Each result shows an emoji, the title and the address. The emoji is picked from a hash of the title and is only decoration. Titles are shown without HTML tags, and with HTML entities and `%` escapes decoded.
90+- Click a title to open the result in a new tab. The address under it isn't a link.
91+- While no source has results, the page says "No results found... :)". It also says so while the sources are still loading.
92+- The logo on the start page tilts as you move the mouse over it.
93+- The page's address doesn't change when you search, so you can't bookmark a search. The back button leaves the app, and reloading the page brings back the start page.
94+- The **[About]** link at the bottom leads to this README, and **[Code]** to this repository.
95+
96+## How it works
97+
98+%seax is a Gall agent, [`zod/seax/app/seax.hoon`](zod/seax/app/seax.hoon), and an Elm app, [`frontend/`](frontend). The agent serves the built Elm app from the desk's `web/` directory.
99+
100+```mermaid
101+sequenceDiagram
102+ participant B as Browser (Elm app)
103+ participant E as Eyre
104+ participant S as %seax
105+ participant I as Iris
106+ participant W as wiby, Urbit docs, CrowdView
107+ B->>E: subscribe to /search/<query> on %seax
108+ E->>S: watch /search/<query>
109+ S-->>B: %flush: every source is loading
110+ S->>I: one HTTP request per source
111+ I->>W: requests from your ship
112+ W-->>I: responses
113+ I-->>S: a response
114+ S-->>B: %drain: what changed in the sources and ranked results
115+```
116+
117+- **Serving the app.** The agent binds `/apps/seax` in Eyre and serves the files in the desk's `web/` directory to logged-in users. Everyone else is redirected to `/~/login`. The Landscape tile comes from `zod/seax/desk.docket-0`.
118+- **Searching.** The Elm app subscribes to `/search/<query>` on the agent through an Eyre channel, using [airlock](https://github.com/iko-soy/airlock). The agent accepts the subscription only from the ship itself. For a query that isn't open yet, it sends one HTTP request per source through Iris. Every new subscriber gets the current state right away.
119+- **Streaming.** Each time a source answers, the agent parses the answer, ranks all the results so far and sends the change. The first message is the whole state (`%flush`), and later ones are diffs of it (`%drain`), made by [`lib/sink.hoon`](zod/seax/lib/sink.hoon) and [`lib/noun-diff.hoon`](zod/seax/lib/noun-diff.hoon). airlock's `Ur.Sub.sink` applies them in the browser.
120+- **Sharing searches.** While a query has subscribers, its results stay in the agent's state. Another tab that searches for the same query gets them right away, without new requests. Queries have to match exactly, including case and spaces. When the last subscriber of a query leaves, the agent forgets the query. A new search in the same tab leaves the old query, but closing or reloading a tab doesn't: Eyre ends the tab's subscriptions when it closes the tab's channel, 12 hours after the tab disconnects. Results aren't refreshed while a query stays open.
121+- **Failures.** A source fails when its response has no body, or the body isn't the JSON the source's parser expects. The agent doesn't look at the HTTP status. When Vere can't make a request (DNS, connection or TLS errors, or a connection that stalls for 5 minutes), Iris returns status 504 with no body, so that source fails too. Iris follows redirects with status 301, 303 and 307; other redirects make the source fail. Failed requests aren't retried.
122+
123+## Ranking
124+
125+Each source has a weight in [`zod/seax/lib/engines.hoon`](zod/seax/lib/engines.hoon), currently `.2` (2.0) for all of them. [`zod/seax/lib/rank.hoon`](zod/seax/lib/rank.hoon) merges the results that have exactly the same URL. Each URL gets a score, which is the product of three numbers:
126+
127+- the weights of the sources that returned it, multiplied together,
128+- the number of times it was returned,
129+- the sum of 1/position for each time, counting positions from 1.
130+
131+Results are shown with the highest score first. For a URL that only one source returns, the score is the source's weight divided by the position: a first result scores 2, a second one 1, a third one 0.67. Since the weights are all the same, the first results of all sources come first, then their second results, and so on. Results with the same score come in no particular order.
132+
133+URLs that differ only by a trailing slash or by `http`/`https` count as different URLs. A merged result keeps the title from one of its sources. See [Known issues](#known-issues) for a bug in the scores of merged results.
134+
135+## Privacy and network traffic
136+
137+- **Searches.** Your query goes from your ship to wiby.me, docs.urbit.org and crowdview-next-js.onrender.com, over HTTPS. Those services see the query and your ship's IP address.
138+- **Nothing else.** %seax makes requests only when you search for a query that isn't already open. It has no timers, and it doesn't contact other ships, except once: an upgrade from an older version calls off that version's pings to its peers that are still waiting for an answer. See [Peers (disabled)](#peers-disabled).
139+- **The page.** It loads nothing from other sites: the fonts, scripts and images all come from your ship. airlock normally pokes ~zod when it opens a channel, and [`frontend/airlock.patch`](frontend/airlock.patch) removes that poke. The bug is reported at [iko-soy/airlock#15](https://github.com/iko-soy/airlock/issues/15). Eyre's login page, which comes with Urbit, loads its fonts from rsms.me and storage.googleapis.com.
140+- **Stored data.** Search results stay in the agent's state while their query is open, which can be up to 12 hours after you close its tab. As with everything your ship does, the requests and responses are also recorded in your pier's event log. The agent also prints your queries and their results in the dojo.
141+- **Other ships.** Only you can search. %seax refuses other ships' pokes and searches, so they can't use it through your ship.
142+
143+## Peers (disabled)
144+
145+From August 2023 until this version, %seax kept a list of peers: other ships that might run %seax. The list started with ~zod and ~racfer-hattes. Every 30 seconds, %seax pinged its peers by subscribing to `/ping` on their %seax, and told them which peers had answered, so that ships running %seax could find each other.
146+
147+Nothing ever used the list, and neither the code nor the commit messages say what it was for. The 2023 code didn't work well either: a peer was dropped after missing one ping, every other check emptied the list, and from October 2023 ships refused the peer lists that other ships sent them, because `+on-poke` couldn't read pokes from other ships.
148+
149+This version disables the peer network:
150+
151+- It doesn't ping other ships or send them anything, and it has no timers.
152+- An upgrade drops the list and calls off the pings that are still waiting for an answer.
153+- It refuses pings and peer lists from other ships.
154+
155+## Debugging
156+
157+%seax prints a lot to the dojo:
158+
159+- the wire of every response it gets from Arvo, e.g. `/search-result/<query>/<source>` for each HTTP response,
160+- each source's parsed results, followed by the state of every source,
161+- the path of every search that closes,
162+- the stack trace of every crash while it handles a response, such as the late answers in [Known issues](#known-issues).
163+
164+A few dojo commands help:
165+
166+- `:seax +dbug` prints the agent's state: each open query, with its number of subscribers and the results of each source. A source that is still loading has no entry, `~` means that it failed, and `[~ ~]` that it found nothing.
167+- `:seax +dbug [%incoming ~]` lists the subscriptions to the agent, i.e. open searches.
168+- `:seax +dbug [%outgoing ~]` lists the agent's own subscriptions. It should print "no matching subscriptions", also right after an upgrade from an older version.
169+- `:seax +dbug [%state '~(key by search-subscriptions)']` evaluates Hoon against the state, here listing the open queries.
170+- `+vats %seax` shows whether the desk is running or suspended, e.g. after an Urbit OS update, and which Urbit OS version it declares in `/sys/kelvin`.
171+
172+When Vere can't make a request, it prints `http: fail (<n>, 504): <reason>`, e.g. `unknown node or service` when a DNS lookup fails, and that source counts as failed.
173+
174+## Adding a search source
175+
176+1. Create `zod/seax/lib/engines/<name>.hoon`. It holds an `engine` core: `++request` builds the HTTP request for a query, and `++results` parses the response into a list of `[title url]`, or `~` if it can't. `++get` in [`zod/seax/sur/seax.hoon`](zod/seax/sur/seax.hoon) makes a GET request with the query appended to a URL. It escapes the query twice, because Vere unescapes the URL once before sending it. For example, for an API that returns `[{"title": ..., "url": ...}, ...]`:
177+
178+ ```hoon
179+ /- *seax
180+ ^- engine
181+ =<
182+ |%
183+ ++ request
184+ |= query=tape
185+ ^- request:http
186+ (get "https://example.com/search?q=" query)
187+ ++ results
188+ |= response=mime-data:iris
189+ ^- (unit (list search-result))
190+ ;< jon=json _biff (de:json:html q.data.response)
191+ (apex jon)
192+ --
193+ |%
194+ ++ apex
195+ =, dejs-soft:format
196+ (ar (ot ~[title+so url+so]))
197+ --
198+ ```
199+
200+2. In [`zod/seax/lib/engines.hoon`](zod/seax/lib/engines.hoon), import it (`/+ engines-<name>`) and add `[name=%<name> engine=engines-<name> weight=.2]` to the list. The weight is a floating-point literal: `.2` is 2.0.
201+3. Build and commit the desk again. Nix only sees files that git tracks, so `git add` the new file before building. The Elm app shows every source the agent has, so it doesn't need any change.
202+
203+A source counts as failed if `++results` returns `~` or an empty list. Note that `ar` from `dejs-soft` gives `~` if even one result doesn't parse.
204+
205+## Development
206+
207+[INSTRUCTIONS.md](INSTRUCTIONS.md#development) explains how to work on the frontend. `dev/elm-live.sh` serves it at `http://localhost:8000` with Elm's debugger, rebuilds it when the code changes, and passes requests for `/~/` on to a running ship.
208+
209+The flake has these outputs:
210+
211+- `packages.<system>.desk`, the default: the desk, with the built frontend in `web/`.
212+- `packages.<system>.frontend`: the built frontend.
213+- `packages.<system>.fonts`: the Roboto Light web font, converted to WOFF2 from nixpkgs' Roboto, and its license.
214+- `packages.<system>.airlock-src`: airlock at the commit pinned in `flake.lock`, with `frontend/airlock.patch` applied.
215+- `devShells.<system>.default`: a shell with `elm` 0.19.2, `elm-live` and `elm2nix`.
216+
217+To change the agent, edit `zod/seax`, rebuild the desk and copy it into your mounted desk, as in the installation steps, then `|commit %seax`. The agent reloads with its state. Nix only sees files that git tracks, so `git add` new files before building.
218+
219+## Project layout
220+
221+```
222+README.md, INSTRUCTIONS.md this file, and how to install and develop
223+LICENSE, NOTICE the MIT License, and the files from other projects
224+flake.nix, flake.lock the Nix build: desk, frontend, font and airlock
225+dev/elm-live.sh frontend development server, with a proxy to a ship
226+docs/screenshot.png the screenshot above
227+zod/seax/ the %seax desk
228+ app/seax.hoon the agent
229+ sur/seax.hoon the search-result and engine types, and ++get
230+ lib/engines.hoon the sources and their weights
231+ lib/engines/*.hoon one file per source
232+ lib/rank.hoon merges and ranks results
233+ lib/sink.hoon sends state as a %flush and then %drain diffs
234+ lib/noun-diff.hoon diffs of nouns, for lib/sink.hoon
235+ lib/dbug.hoon, lib/server.hoon from Urbit's base-dev files
236+ lib/docket.hoon, sur/docket.hoon for the Landscape tile
237+ lib/de-html.hoon, lib/extract-links.hoon, lib/extract-text.hoon, lib/words.hoon
238+ HTML and text helpers from the first, crawler
239+ version, which nothing uses now
240+ mar/ marks for the desk's files
241+ desk.docket-0 the tile: title, description, colour, image, URL,
242+ version, website and license
243+ desk.bill the agent to start: %seax
244+ sys.kelvin [%zuse 408]
245+frontend/ the Elm app
246+ src/Main.elm the whole app
247+ src/Route.elm, src/Pages/Search.elm unused leftovers of an early version;
248+ Pages/Search.elm doesn't compile
249+ index.html, script.js the page, and the glue between Elm and the event stream
250+ fetch-event-source.js event-stream client, from airlock's example
251+ assets/ CSS, the logo and tile images, the logo tilt script
252+ elm.json Elm 0.19.2 and its packages; airlock's code comes from airlock/src
253+ elm-srcs.nix, registry.dat pinned Elm packages, for the Nix build
254+ airlock.patch stops airlock from poking ~zod when it opens a channel
255+```
256+
257+## Known issues
258+
259+The search sources:
260+
261+- **CrowdView often has no results,** and %seax shows a source without results the same way as a failed one: it's hidden.
262+- **One malformed result fails a whole source.** If any result in a source's response doesn't parse, the whole source counts as failed.
263+
264+The agent:
265+
266+- **Scores of merged results are wrong.** `lib/rank.hoon` adds the 1/position terms of a merged URL, and compares scores, as integers instead of floating-point numbers. As a result:
267+ - URLs that 2 sources return always come before URLs that only 1 returns. Among themselves, they come roughly in order of the product of their two positions, smallest first, instead of by their scores, and those whose positions multiply to 4 or less tie at the top.
268+ - URLs that all 3 sources return come before those.
269+ - Single-source results are ranked correctly.
270+- **Late answers crash the agent.** If you search for something else before every source has answered, the late answers to the old query crash the agent's `+on-arvo`, and the dojo prints a stack trace for each one. Nothing else is affected. The agent never cancels its requests.
271+- **Restarting the ship during a search leaves sources loading.** When Vere restarts, Iris cancels the requests that are still open. The agent crashes on each cancellation, and those sources keep loading until the query closes, which can be 12 hours after you close its tab.
272+- **A source that stalls keeps loading** until Vere's HTTP client gives up after 5 minutes.
273+- **Results are never refreshed.** A query that is open in any tab, or in a tab closed less than 12 hours ago, gives the results it already has.
274+
275+The page:
276+
277+- **A `%` in a title can hide it.** Titles are `%`-decoded, and when that fails, as on a lone `%`, the title disappears and the result can't be clicked. Escapes that do decode are decoded even when they are part of the real title.
278+- **Narrow screens are cut off.** The logo and the search box have fixed widths, so on a phone the search box and the search button are cut off, and on the start page the logo too. Titles and addresses never wrap, so long ones are cut off as well. The page can't scroll sideways.
279+- **The source filter stays for the next search.** If the selected sources have no results for the new query, the list is empty without the "No results found" message, and a selected source that is hidden can't be unselected.
280+- **"Come back later" doesn't help.** The no-results message says "We'll try and find you something. Just come back later.", but nothing searches again.
281+- **Searching for the same query again does nothing,** so the page can't refresh its results.
282+- **Searches can't be bookmarked,** because the page's address doesn't change.
283+- **Smaller things:** only the title of a result is a link, although the whole result looks clickable; the logo tilts only on the start page; the page has no favicon; the search box isn't focused when the page opens; and the page logs every event from the ship to the browser console.
284+
285+## History
286+
287+- **July 2023.** iko created the repository on 23 July and started %seax on 27 July, as a web crawler with a reverse word index. On 29 July it switched to searching other search engines, with Yep, CrowdView, wiby and Alexandria as sources, and from 31 July it sent each query to all of them. Streaming results through `%sink` and noun diffs, ranking and the first Elm frontend were in place by 2 August, and filtering by source and animations by 5 August.
288+- **August 2023.** iko added liveness checks between %seax ships on 9 August, and "bad peer discovery" (gossip) on 27 August.
289+- **October 2023.** Evangelos Lamprou added the logo and its tilt effect, improvements to the results page including the emoji, the Urbit developer docs as a source, and the first INSTRUCTIONS.md. He also added a `%get-notes` poke that copied the ship's Tlon notebook notes into the agent's state. The notes were never searched.
290+- **Upstream.** iko also contributed `%sink` and the noun-diff library to urbit/urbit in July 2023 ([#6712](https://github.com/urbit/urbit/pull/6712), [#6681](https://github.com/urbit/urbit/pull/6681)), where they live in `pkg/base-dev`.
291+- **2026.** %seax was ported to Urbit OS 408k:
292+ - It is built with a Nix flake, served from the ship, and has a Landscape tile.
293+ - The docs.urbit.org search replaced the old urbit.org developer search.
294+ - Alexandria, whose API is gone, and the Tlon notes were removed.
295+ - The peer network, which nothing used, was disabled.
296+ - Yep, which blocks requests that don't come from a browser, was dropped.
297+
298+## Credits
299+
300+Created by [~racfer-hattes](https://iko.soy) and [~dopnyr-figbud](https://vagos.lamprou.xyz/).
301+
302+- Results come from [wiby](https://wiby.me/), the [Urbit docs](https://docs.urbit.org/) and [CrowdView](https://crowdview.ai/).
303+- The frontend is written in [Elm](https://elm-lang.org/) with [airlock](https://github.com/iko-soy/airlock), [elm-ui](https://github.com/mdgriffith/elm-ui) and [elm-animator](https://github.com/mdgriffith/elm-animator), and includes the [Roboto](https://github.com/googlefonts/roboto-3-classic) font.
304+
305+## License
306+
307+MIT, see [LICENSE](LICENSE). Files from other projects are listed in [NOTICE](NOTICE).
dev/elm-live.sh+17−5
@@ -1,12 +1,24 @@
1−#!/bin/sh
1+#!/usr/bin/env bash
2+# Serves the frontend at http://localhost:8000 and rebuilds it on changes.
3+# Requests to /~/ are passed on to the ship at $SHIP_URL, so log in at
4+# http://localhost:8000/~/login first. Extra arguments go to `elm make`.
25
36set -e
47
58cd "$(dirname "$0")/../frontend"
69
7−if [[ -z $(command -v nix) ]] && [[ -z $(command -v elm-live) ]]; then
10+ship=${SHIP_URL:-http://localhost:8080}
11+args=(src/Main.elm --start-page=index.html --proxy-prefix=/~ "--proxy-host=$ship/~" -- --debug --output=elm.js "$@")
12+
13+if command -v nix >/dev/null; then
14+ nix build ..#airlock-src --out-link airlock
15+ nix build ..#fonts --out-link assets/fonts
16+ exec nix develop .. --command elm-live "${args[@]}"
17+elif command -v elm-live >/dev/null; then
18+ if [ ! -d airlock ]; then
19+ echo "Please clone https://github.com/iko-soy/airlock into frontend/airlock and apply frontend/airlock.patch" && exit 1
20+ fi
21+ exec elm-live "${args[@]}"
22+else
823 echo "Please install either 'nix' or 'elm-live'" && exit 1
924fi
10−
11−command -v nix && nix run nixpkgs#elmPackages.elm-live -- src/Main.elm --start-page=index.html -- --debug --output=elm.js "$@"
12−command -v elm-live && elm-live src/Main.elm --start-page=index.html -- --debug --output=elm.js "$@"
docs/screenshot.pngnew file

Binary file not shown.

flake.locknew file+45
@@ -0,0 +1,45 @@
1+{
2+ "nodes": {
3+ "airlock": {
4+ "flake": false,
5+ "locked": {
6+ "lastModified": 1692952961,
7+ "narHash": "sha256-xz4esBLKyzcBp0rNkne26lrhIB993gLRJqxg217d8Yk=",
8+ "owner": "iko-soy",
9+ "repo": "airlock",
10+ "rev": "7e857379f10b362a9ee9e271312a4deb1fe65b66",
11+ "type": "github"
12+ },
13+ "original": {
14+ "owner": "iko-soy",
15+ "repo": "airlock",
16+ "rev": "7e857379f10b362a9ee9e271312a4deb1fe65b66",
17+ "type": "github"
18+ }
19+ },
20+ "nixpkgs": {
21+ "locked": {
22+ "lastModified": 1792210252,
23+ "narHash": "sha256-Mh0PUaIv4nFY+8wAGonaEh8iBzwsmdNlwjVHmFg1Biw=",
24+ "owner": "NixOS",
25+ "repo": "nixpkgs",
26+ "rev": "09063bd1f2b36fd9fd793c36dfade7bd40a93dfc",
27+ "type": "github"
28+ },
29+ "original": {
30+ "owner": "NixOS",
31+ "ref": "nixos-unstable",
32+ "repo": "nixpkgs",
33+ "type": "github"
34+ }
35+ },
36+ "root": {
37+ "inputs": {
38+ "airlock": "airlock",
39+ "nixpkgs": "nixpkgs"
40+ }
41+ }
42+ },
43+ "root": "root",
44+ "version": 7
45+}
flake.nixnew file+114
@@ -0,0 +1,114 @@
1+{
2+ description = "seax: an Urbit search agent";
3+
4+ inputs = {
5+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6+ # The Elm library the frontend talks to the ship with.
7+ airlock = {
8+ url = "github:iko-soy/airlock/7e857379f10b362a9ee9e271312a4deb1fe65b66";
9+ flake = false;
10+ };
11+ };
12+
13+ outputs =
14+ {
15+ self,
16+ nixpkgs,
17+ airlock,
18+ }:
19+ let
20+ # nixpkgs 26.11 dropped x86_64-darwin.
21+ forAllSystems = nixpkgs.lib.genAttrs [
22+ "x86_64-linux"
23+ "aarch64-linux"
24+ "aarch64-darwin"
25+ ];
26+ in
27+ {
28+ packages = forAllSystems (
29+ system:
30+ let
31+ pkgs = nixpkgs.legacyPackages.${system};
32+ inherit (self.packages.${system}) airlock-src fonts frontend;
33+ in
34+ {
35+ # The %seax desk, ready to be copied into a mounted desk directory
36+ # and committed with `|commit %seax`. The agent serves the frontend
37+ # from web/ at /apps/seax/.
38+ desk = pkgs.runCommand "seax-desk" { } ''
39+ cp -r --no-preserve=mode ${./zod/seax} $out
40+ cp -r --no-preserve=mode ${frontend} $out/web
41+ '';
42+
43+ frontend = pkgs.stdenv.mkDerivation {
44+ name = "seax-frontend";
45+ src = ./frontend;
46+ nativeBuildInputs = [ pkgs.elmPackages.elm ];
47+ # elm-srcs.nix and registry.dat come from `elm2nix convert` and
48+ # `elm2nix snapshot`; regenerate them when elm.json changes.
49+ configurePhase =
50+ pkgs.elmPackages.fetchElmDeps {
51+ elmPackages = import ./frontend/elm-srcs.nix;
52+ elmVersion = "0.19.2";
53+ registryDat = ./frontend/registry.dat;
54+ }
55+ + ''
56+ # A checkout without .git can still contain dev/elm-live.sh's link.
57+ rm -rf airlock
58+ ln -s ${airlock-src} airlock
59+ '';
60+ buildPhase = ''
61+ elm make src/Main.elm --optimize --output elm.js
62+ '';
63+ installPhase = ''
64+ mkdir -p $out/assets
65+ cp index.html elm.js script.js fetch-event-source.js $out/
66+ cp -r assets/css assets/img assets/js $out/assets/
67+ cp -r ${fonts} $out/assets/fonts
68+ '';
69+ };
70+
71+ # airlock, patched to not poke ~zod when it opens a channel.
72+ airlock-src = pkgs.applyPatches {
73+ name = "airlock";
74+ src = airlock;
75+ patches = [ ./frontend/airlock.patch ];
76+ };
77+
78+ # The web font used by the frontend, served from assets/fonts/.
79+ fonts =
80+ let
81+ robotoLicense = pkgs.fetchurl {
82+ url = "https://raw.githubusercontent.com/googlefonts/roboto-3-classic/v3.016/OFL.txt";
83+ hash = "sha256-BhQCMnqWqtsL+2lKlg7SiezTjTg+OWJDgxq4H+sQnEE=";
84+ };
85+ in
86+ pkgs.runCommand "seax-fonts" { nativeBuildInputs = [ pkgs.woff2 ]; } ''
87+ mkdir -p $out
88+ cp ${pkgs.roboto.src}/web/static/Roboto-Light.ttf roboto-light.ttf
89+ woff2_compress roboto-light.ttf
90+ cp roboto-light.woff2 $out/roboto-light.woff2
91+ cp ${robotoLicense} $out/roboto-license.txt
92+ '';
93+
94+ default = self.packages.${system}.desk;
95+ }
96+ );
97+
98+ devShells = forAllSystems (
99+ system:
100+ let
101+ pkgs = nixpkgs.legacyPackages.${system};
102+ in
103+ {
104+ default = pkgs.mkShell {
105+ packages = [
106+ pkgs.elmPackages.elm
107+ pkgs.elmPackages.elm-live
108+ pkgs.elm2nix
109+ ];
110+ };
111+ }
112+ );
113+ };
114+}
frontend/airlock.patchnew file+16
@@ -0,0 +1,16 @@
1+diff --git a/src/Ur/Run.elm b/src/Ur/Run.elm
2+index 4802e86..fe67d11 100644
3+--- a/src/Ur/Run.elm
4++++ b/src/Ur/Run.elm
5+@@ -312,8 +312,10 @@ update inp msg model =
6+
7+ NeedsActivation ->
8+ let
9++ -- Any PUT creates the channel. An ack of nothing does so
10++ -- without poking ~zod (`ship = ""`) over the network.
11+ ( eventId, reqs ) =
12+- [ Poke { ship = "", agent = "hood", mark = "helm-hi", noun = C.cord "Opening airlock!" } ]
13++ [ Ack 0 ]
14+ |> tag model.eventId
15+ in
16+ ( { model | eventId = eventId }
frontend/assets/css/fonts.cssnew file+10
@@ -0,0 +1,10 @@
1+/* The font file is taken from nixpkgs at build time (`nix build .#fonts`),
2+ see flake.nix. Its license is next to it in ../fonts/. */
3+
4+@font-face {
5+ font-family: 'Roboto';
6+ font-style: normal;
7+ font-weight: 300;
8+ font-display: swap;
9+ src: url('../fonts/roboto-light.woff2') format('woff2');
10+}
frontend/assets/css/main.css+1−1
@@ -1,4 +1,4 @@
1−@import url('https://fonts.googleapis.com/css2?family=Inter:wght@200&family=Roboto+Mono:wght@200&family=Roboto:wght@300&display=swap');
1+@import url('fonts.css');
22
33.button {
44 border: none;
frontend/assets/img/tile.pngnew file

Binary file not shown.

frontend/elm-srcs.nixnew file+267
@@ -0,0 +1,267 @@
1+{
2+
3+ "Evelios/elm-hash" = {
4+ sha256 = "0xiypbcqd8bfv0lzpna6is5a63vf91jy8xa2350asi5y5c5fzrkq";
5+ version = "1.0.0";
6+ };
7+
8+ "TSFoster/elm-bytes-extra" = {
9+ sha256 = "1ip5br0kszhr8kmk19jsqqqhgna89drn3cwb6zn8ncwfrxc8xvs9";
10+ version = "1.3.0";
11+ };
12+
13+ "avh4/elm-color" = {
14+ sha256 = "0n16wnvp87x9az3m5qjrl6smsg7051m719xn5d244painx8xmpzq";
15+ version = "1.0.0";
16+ };
17+
18+ "cmditch/elm-bigint" = {
19+ sha256 = "00wfcvl3kg8l85cyljvgal51qksnqfqkc4g4diljggz6dcl155w2";
20+ version = "2.0.1";
21+ };
22+
23+ "elm-community/list-extra" = {
24+ sha256 = "02grd0p5hc2gvdy4n723d1s28pm1grn95jrzic6jcgb26qh16vcc";
25+ version = "8.7.0";
26+ };
27+
28+ "elm-community/maybe-extra" = {
29+ sha256 = "185jy9jxx3bqf0xl3rmdxfqqmxzcr084llf32glr6hgl5agshywk";
30+ version = "5.3.0";
31+ };
32+
33+ "elm-community/string-extra" = {
34+ sha256 = "014l3lkglaniizwvr5pqbi4z7bb0piq0pp3fdifyd4rdp53ac23f";
35+ version = "4.0.1";
36+ };
37+
38+ "elm/browser" = {
39+ sha256 = "0nagb9ajacxbbg985r4k9h0jadqpp0gp84nm94kcgbr5sf8i9x13";
40+ version = "1.0.2";
41+ };
42+
43+ "elm/bytes" = {
44+ sha256 = "02ywbf52akvxclpxwj9n04jydajcbsbcbsnjs53yjc5lwck3abwj";
45+ version = "1.0.8";
46+ };
47+
48+ "elm/core" = {
49+ sha256 = "19w0iisdd66ywjayyga4kv2p1v9rxzqjaxhckp8ni6n8i0fb2dvf";
50+ version = "1.0.5";
51+ };
52+
53+ "elm/html" = {
54+ sha256 = "1n3gpzmpqqdsldys4ipgyl1zacn0kbpc3g4v3hdpiyfjlgh8bf3k";
55+ version = "1.0.0";
56+ };
57+
58+ "elm/http" = {
59+ sha256 = "008bs76mnp48b4dw8qwjj4fyvzbxvlrl4xpa2qh1gg2kfwyw56v1";
60+ version = "2.0.0";
61+ };
62+
63+ "elm/json" = {
64+ sha256 = "0kjwrz195z84kwywaxhhlnpl3p251qlbm5iz6byd6jky2crmyqyh";
65+ version = "1.1.3";
66+ };
67+
68+ "elm/svg" = {
69+ sha256 = "1cwcj73p61q45wqwgqvrvz3aypjyy3fw732xyxdyj6s256hwkn0k";
70+ version = "1.0.1";
71+ };
72+
73+ "elm/time" = {
74+ sha256 = "0vch7i86vn0x8b850w1p69vplll1bnbkp8s383z7pinyg94cm2z1";
75+ version = "1.0.0";
76+ };
77+
78+ "elm/url" = {
79+ sha256 = "0av8x5syid40sgpl5vd7pry2rq0q4pga28b4yykn9gd9v12rs3l4";
80+ version = "1.0.0";
81+ };
82+
83+ "figbus/elm-urbit-api" = {
84+ sha256 = "1qpb8gv2giqp5rysmh0ar66j341bra6wzqka8qcr6xk82ad6afch";
85+ version = "4.0.1";
86+ };
87+
88+ "hecrj/html-parser" = {
89+ sha256 = "19rr5w9lca7akwyvq1fbi5vrib4x2b9sf1p76dxhf6vmiw71xrxr";
90+ version = "2.4.0";
91+ };
92+
93+ "ianmackenzie/elm-1d-parameter" = {
94+ sha256 = "08r1q80k7w2kyasqk54k1xzd5d1607wj4ahx66jdh7gkrni9m8n5";
95+ version = "1.0.1";
96+ };
97+
98+ "ianmackenzie/elm-3d-camera" = {
99+ sha256 = "1cp7ws6kn4sakzk0hpwy83qyz4mr6xfsk2jb4vbf97wjc1fs1gf7";
100+ version = "3.1.0";
101+ };
102+
103+ "ianmackenzie/elm-3d-scene" = {
104+ sha256 = "0h1yhxdycyayxp31g7dsj2iarhfzb6gls2rbzqydmd1v4px4rafr";
105+ version = "1.0.1";
106+ };
107+
108+ "ianmackenzie/elm-geometry" = {
109+ sha256 = "11vjnr9h1742pn9z55bclsxm5hal1f1v4dd055zd6z14fr91pysn";
110+ version = "3.11.0";
111+ };
112+
113+ "ianmackenzie/elm-triangular-mesh" = {
114+ sha256 = "00n08cc3qj610g2f7f77qpl6b6pwr456czf3prkz6iddmi52h3gp";
115+ version = "1.1.0";
116+ };
117+
118+ "ianmackenzie/elm-units" = {
119+ sha256 = "053nibhpkf906c7g14z48pvinzzfhnrnk5hkj4mjvjnv3r457h97";
120+ version = "2.10.0";
121+ };
122+
123+ "jasonliang-dev/elm-heroicons" = {
124+ sha256 = "038j32fniz3q9kpm7mcjz053fycs2nl7pnishgrrs5djjc6djw1z";
125+ version = "2.0.0";
126+ };
127+
128+ "jxxcarlson/hex" = {
129+ sha256 = "0dd0f2lfny4qwzkqbvixkcgprza2n289y46y1y2mgiay8iisfkx9";
130+ version = "4.0.0";
131+ };
132+
133+ "marcosh/elm-html-to-unicode" = {
134+ sha256 = "1f1b32qkqxl9lqc4g5737kw4yrz32jxcylgbsbmq871jwv4gwdp8";
135+ version = "1.0.4";
136+ };
137+
138+ "mdgriffith/elm-animator" = {
139+ sha256 = "0rbsycykmcjgjlm5r48ycbr9halv2big52ifhs7wpslz0df3hhmh";
140+ version = "1.1.1";
141+ };
142+
143+ "mdgriffith/elm-ui" = {
144+ sha256 = "0ffcqv4a4ad400hwp824m3qq4jy82cqp5ghmhp1m0q7n004z6kgv";
145+ version = "1.1.8";
146+ };
147+
148+ "rtfeldman/elm-css" = {
149+ sha256 = "1gwhgqwclc7clk1ns4qqzyn7b4wvcmccg9qavvb8m694qmwlkzjy";
150+ version = "18.0.0";
151+ };
152+
153+ "rtfeldman/elm-hex" = {
154+ sha256 = "1y0aa16asvwdqmgbskh5iba6psp43lkcjjw9mgzj3gsrg33lp00d";
155+ version = "1.0.0";
156+ };
157+
158+ "toastal/either" = {
159+ sha256 = "1yfgvw81szsipibafnllik65vhki9n1lxdylbyy6fsmj6406g1yv";
160+ version = "3.6.3";
161+ };
162+
163+ "zwilias/elm-html-string" = {
164+ sha256 = "0pfqbva3rawly0cr448lvajgx2lzqq6avb8wgrp67i6sh9zd06f7";
165+ version = "2.0.2";
166+ };
167+
168+ "AdrianRibao/elm-derberos-date" = {
169+ sha256 = "0w4ld89akhhr0zr17vnwcwdiwygmnqdf9nb2g2f3w1b2p3p73acp";
170+ version = "1.2.3";
171+ };
172+
173+ "NoRedInk/elm-string-conversions" = {
174+ sha256 = "0xhjyypf5jmnjih9m3rr2ccyf15i403yvpv5xmknqmhmnnhrkf63";
175+ version = "1.0.1";
176+ };
177+
178+ "bitsoflogic/elm-radixint" = {
179+ sha256 = "0625xbi9bw3xdixhids82gcx7bhmrcd9q0cxpc6rpiy8br7d2lfn";
180+ version = "2.0.0";
181+ };
182+
183+ "bonzaico/murmur3" = {
184+ sha256 = "1ccyaz8n2c9szv25y5pfdp62pdmm81n9h6yhr1r26hab9c15gcxx";
185+ version = "1.0.0";
186+ };
187+
188+ "chain-partners/elm-bignum" = {
189+ sha256 = "17fqqmm83r905zw03gjc0dif3ach4d1aar3cv7dlcn2szp0qpgfs";
190+ version = "1.0.1";
191+ };
192+
193+ "elm-explorations/linear-algebra" = {
194+ sha256 = "19zf3dgrx5bvhybjwq3bp171wzsb4bfk5rrfjv234b2f8q3yi59g";
195+ version = "1.0.3";
196+ };
197+
198+ "elm-explorations/webgl" = {
199+ sha256 = "0ma7laa3ax8zd41s838px1y5s1dsmlqzp4j321lwngxjzvxkm3zy";
200+ version = "1.1.3";
201+ };
202+
203+ "elm/file" = {
204+ sha256 = "1rljcb41dl97myidyjih2yliyzddkr2m7n74x7gg46rcw4jl0ny8";
205+ version = "1.0.5";
206+ };
207+
208+ "elm/parser" = {
209+ sha256 = "0a3cxrvbm7mwg9ykynhp7vjid58zsw03r63qxipxp3z09qks7512";
210+ version = "1.1.0";
211+ };
212+
213+ "elm/random" = {
214+ sha256 = "138n2455wdjwa657w6sjq18wx2r0k60ibpc4frhbqr50sncxrfdl";
215+ version = "1.0.0";
216+ };
217+
218+ "elm/regex" = {
219+ sha256 = "0lijsp50w7n1n57mjg6clpn9phly8vvs07h0qh2rqcs0f1jqvsa2";
220+ version = "1.0.0";
221+ };
222+
223+ "elm/virtual-dom" = {
224+ sha256 = "1yvb8px2z62xd578ag2q0r5hd1vkz9y7dfkx05355iiy1d7jwq4v";
225+ version = "1.0.3";
226+ };
227+
228+ "ianmackenzie/elm-float-extra" = {
229+ sha256 = "0l499d14iabyigdysvx3xa572izmqqki7b1ym2gc7kv4sprrq194";
230+ version = "1.1.0";
231+ };
232+
233+ "ianmackenzie/elm-geometry-linear-algebra-interop" = {
234+ sha256 = "15gjd1h0jv3d35p0hyv4k8z1gpag23dip8yacclajjrnkdxmcpgj";
235+ version = "2.0.2";
236+ };
237+
238+ "ianmackenzie/elm-interval" = {
239+ sha256 = "086x40s9gnl2r7700ff75w0p3wfrxh144ks24ni5cwhirxwwf0pq";
240+ version = "3.1.0";
241+ };
242+
243+ "ianmackenzie/elm-units-interval" = {
244+ sha256 = "0xwb5vj8jcnn88cnwniibgncfvyaxnmwwkrbk1n7ji3aj6w8f8dj";
245+ version = "3.2.0";
246+ };
247+
248+ "ktonon/elm-word" = {
249+ sha256 = "055rs4aacvhl4m25lj70wlk71f4yinwgd74wa4nx36mpj2m743b6";
250+ version = "2.1.2";
251+ };
252+
253+ "myrho/elm-round" = {
254+ sha256 = "0zv0a60wzkx4xib7h07ijcg72mcyb3vb914hk5pjp6rf4k2lv9kj";
255+ version = "1.0.5";
256+ };
257+
258+ "robinheghan/murmur3" = {
259+ sha256 = "15asmgr2zqh7rkywrg5647rpdqkpzxk02v5qc6ndj60jza3gsmjk";
260+ version = "1.0.0";
261+ };
262+
263+ "chelovek0v/bbase64" = {
264+ sha256 = "01fj6lf2xpc3byw89zivh11i6kl5bimlsdjd6m3gsi1v88nfj17d";
265+ version = "1.0.1";
266+ };
267+}
frontend/elm.json+2−2
@@ -2,9 +2,9 @@
22 "type": "application",
33 "source-directories": [
44 "src",
5− "../../airlock/src"
5+ "airlock/src"
66 ],
7− "elm-version": "0.19.1",
7+ "elm-version": "0.19.2",
88 "dependencies": {
99 "direct": {
1010 "Evelios/elm-hash": "1.0.0",
frontend/index.html+2−2
@@ -28,8 +28,8 @@
2828 </head>
2929 <body>
3030 <div id="elm"></div>
31− <script src="/elm.js"></script>
32− <script type="module" src="/script.js"></script>
31+ <script src="elm.js"></script>
32+ <script type="module" src="script.js"></script>
3333 </body>
3434 <script type="text/javascript" src="assets/js/tilt.js" defer></script>
3535</html>
frontend/registry.datnew file

Binary file not shown.

frontend/script.js+3−2
@@ -1,6 +1,7 @@
1−import { fetchEventSource } from "/fetch-event-source.js"
1+import { fetchEventSource } from "./fetch-event-source.js"
22
3−const uid = `${Math.floor(Date.now() / 1000)}-${Math.random()}`;
3+// No dots: Eyre would read anything after a dot as a file extension.
4+const uid = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
45
56function searchForInit(obj) {
67 if (obj.init) {
frontend/src/Main.elm+10−8
@@ -18,6 +18,7 @@ import Html.String
1818import Html.Styled.Attributes exposing (css)
1919import Html.Styled.Attributes exposing (css)
2020import Html.Events exposing (on)
21+import Http
2122import Json.Decode as JD
2223import List
2324import List.Extra
@@ -36,9 +37,11 @@ import ElmEscapeHtml
3637import Json.Encode
3738import Hash
3839
40+{-| The frontend is served by the ship itself, so Eyre is on the same origin.
41+-}
3942url : String
4043url =
41− "http://localhost:8080"
44+ ""
4245
4346
4447type SearchEngineState
@@ -96,11 +99,10 @@ main =
9699 , engines = []
97100 , selectedEngines = Set.empty
98101 }
99− , Cmd.batch
100− [ Ur.logIn url "lidlut-tabwed-pillex-ridrup"
101− |> Cmd.map (always Noop)
102− , Ur.getShipName url |> Cmd.map (result (always Noop) GotShipName)
103− ]
102+ , Http.get
103+ { url = url ++ "/~/host"
104+ , expect = Http.expectString (result (always Noop) GotShipName)
105+ }
104106 |> Ur.Cmd.cmd
105107 )
106108 , update = update
@@ -188,8 +190,8 @@ subtleLinkView text href =
188190
189191aboutView : Element Msg
190192aboutView = row [ centerX, padding 10, spacing 10]
191− [ subtleLinkView "[About]" "https://vagos.github.io/seax"
192− , subtleLinkView "[Code]" "https://github.com/ilyakooo0/seax"
193+ [ subtleLinkView "[About]" "https://github.com/iko-soy/seax#readme"
194+ , subtleLinkView "[Code]" "https://github.com/iko-soy/seax"
193195 ]
194196
195197titleEmoji : String -> String
zod/seax/app/seax.hoon+102−82
@@ -1,6 +1,5 @@
11/- *seax
2−/- diary
3−/+ dbug, engines, rank, sink, strandio
2+/+ dbug, engines, rank, server, sink
43|%
54+$ query cord
65+$ search-state
@@ -8,18 +7,16 @@ $:
87 number-of-subscriptions=@u
98 search-results=(map term (unit (list search-result)))
109==
11−+$ state-0
10+:: state-0 (2023), and state-1 and state-2 (only in development builds of
11+:: the 408k port), also kept peers: other ships that may run %seax. They
12+:: were pinged and told about each other, but never searched, so they are
13+:: dropped on load. state-0 also kept notes from Tlon's %diary agent.
14+::
15++$ state-3
1216$:
13− notes=shelf:diary
17+ %3
1418 search-subscriptions=(map query search-state)
15− peers=_(silt ~[~zod ~racfer-hattes])
16− alive-peers=(set @p)
1719==
18−+$ poke
19− $%
20− [%add-peers (set @p)]
21− [%get-notes ~]
22− ==
2320++ rank-results
2421 |= search-results=(map term (unit (list search-result)))
2522 %- rank
@@ -41,13 +38,41 @@ $:
4138 |= [engine-name=term engine=engine *]
4239 =/ req
4340 ^- task:iris
44− [%request [%'GET' (crip (url.engine (trip query))) ~ ~] *outbound-config:iris]
41+ [%request (request.engine (trip query)) *outbound-config:iris]
4542 [%pass ~[%search-result query engine-name] %arvo %i req]
46− ++ liveness-interval ~s30
47− ++ gossip-interval ~s30
43+:: +serve: the frontend, served from /web in this desk at /apps/seax/
44+::
45+++ serve
46+ |= [=bowl:gall url=@t]
47+ ^- simple-payload:http
48+ =/ [[ext=(unit @ta) site=(list @t)] *] (parse-request-line:server url)
49+ ?+ site not-found:gen:server
50+ [%apps %seax ~]
51+ (redirect:gen:server '/apps/seax/')
52+ ::
53+ [%apps %seax %$ ~]
54+ (serve-file bowl /index/html)
55+ ::
56+ [%apps %seax *]
57+ ?~ ext not-found:gen:server
58+ =/ pax=(list @t) (snoc t.t.site u.ext)
59+ ?. (levy pax (sane %ta)) not-found:gen:server
60+ (serve-file bowl ;;(path pax))
61+ ==
62+++ serve-file
63+ |= [=bowl:gall pax=path]
64+ ^- simple-payload:http
65+ =/ root=path /(scot %p our.bowl)/[q.byk.bowl]/(scot %da now.bowl)
66+ =/ file=path (weld root (welp /web pax))
67+ ?. .^(? %cu file) not-found:gen:server
68+ =/ =mark ;;(mark (rear pax))
69+ =/ =dais:clay .^(dais:clay %cb (snoc root mark))
70+ =/ =tube:clay .^(tube:clay %cc (weld root /[mark]/mime))
71+ =/ =mime !<(mime (tube (vale:dais .^(* %cx file))))
72+ [[200 ['content-type' (rsh [3 1] (spat p.mime))]~] `q.mime]
4873--
4974
50−=/ state *state-0
75+=/ state *state-3
5176=* current-engines
5277 |= =query
5378 ^- (list [term ?(%loading %failed %completed)])
@@ -77,33 +102,59 @@ $:
77102%- agent:dbug
78103|_ =bowl:gall
79104+* this .
80− liveness-behn-card [%pass /check-liveness %arvo %b %wait (add now.bowl liveness-interval)]
81− gossip-behn-card [%pass /gossip %arvo %b %wait (add now.bowl gossip-interval)]
105+ eyre-connect-card [%pass /eyre/connect %arvo %e %connect [~ /apps/seax] dap.bowl]
82106++ on-init
83− [~[liveness-behn-card gossip-behn-card] this]
107+ [~[eyre-connect-card] this]
84108++ on-save !>(state)
85−++ on-load
109+++ on-load
86110 |= =vase
87− =/ state !<(state-0 vase)
88− :- ~
89− %= this
90− state state
91− ==
92−++ on-poke
111+ ^- (quip card:agent:gall _this)
112+ ?: ?=([%3 *] q.vase)
113+ [~ this(state !<(state-3 vase))]
114+ :: an older state. its searches are dropped, but gall still has their
115+ :: subscribers, so kick them, or they would leave a new search for the
116+ :: same query. a state-0 agent stayed suspended until this upgrade, so
117+ :: its searches are stale anyway
118+ ::
119+ =/ stale=(list path)
120+ %~ tap in
121+ %- silt
122+ %+ murn ~(val by sup.bowl)
123+ |= [ship =path]
124+ ?.(?=([%search *] path) ~ `path)
125+ =/ kick=(list card:agent:gall)
126+ ?~(stale ~ [%give %kick stale ~]~)
127+ :: call off the pings to peers that are still waiting for an answer
128+ ::
129+ =/ leaves=(list card:agent:gall)
130+ %+ murn ~(tap by wex.bowl)
131+ |= [[=wire =ship =term] *]
132+ ^- (unit card:agent:gall)
133+ ?. ?=([%alive ~] wire) ~
134+ `[%pass wire %agent [ship term] %leave ~]
135+ :_ this(state [%3 ~])
136+ [eyre-connect-card (weld kick leaves)]
137+++ on-poke
93138 |= [=mark =vase]
94139 ^- (quip card:agent:gall _this)
95− =/ poke !<(poke vase)
96− ~& poke
97− ?- -.poke
98− %add-peers
99− [~ this(peers.state (~(put in (~(uni in peers.state) +.poke)) src.bowl))]
100− %get-notes
101− `this(notes.state .^(shelf:diary %gx /(scot %p our.bowl)/diary/(scot %da now.bowl)/shelf/noun))
102− ==
103−++ on-watch
104− |= =path
140+ :: only eyre pokes us. older versions also took peers from other ships
141+ ::
142+ ?> ?=(%handle-http-request mark)
143+ =/ [eyre-id=@ta =inbound-request:eyre] !<([@ta inbound-request:eyre] vase)
144+ :_ this
145+ %+ give-simple-payload:app:server eyre-id
146+ %+ require-authorization:app:server inbound-request
147+ |= =inbound-request:eyre
148+ (serve bowl url.request.inbound-request)
149+++ on-watch
150+ |= =path
105151 ?+ path !!
152+ [%http-response *]
153+ `this
106154 [%search query ~]
155+ :: searching makes requests to every engine, so only we can do it
156+ ::
157+ ?> =(our src):bowl
107158 =/ query +<.path
108159 =/ subscription=(unit search-state)
109160 (~(get by search-subscriptions.state) query)
@@ -118,49 +169,38 @@ $:
118169 =. search-subscriptions.state
119170 (~(put by search-subscriptions.state) query subscription)
120171 [~[flush:(sink query)] this]
121− [%ping ~]
122− ~& path
123− :-
124− :~
125− [%give %fact ~ %noun !>(%pong)]
126− [%give %kick ~ ~]
127− ==
128− this
129−
130172 ==
131173
132−:: This was not tested because it requires waiting 12 hours.
133174++ on-leave
134175 |= =path
135176 ?+ path `this
136177 [%search query ~]
137178 =/ query +<.path
138179 ~& path
139− =/ search-state (~(got by search-subscriptions.state) query)
140− =/ number-of-subscriptions (dec number-of-subscriptions.search-state)
180+ =/ search-state (~(get by search-subscriptions.state) query)
181+ :: searches from before an upgrade are dropped in +on-load
182+ ::
183+ ?~ search-state `this
184+ =/ number-of-subscriptions (dec number-of-subscriptions.u.search-state)
141185 =. search-subscriptions.state
142− ?~ number-of-subscriptions
186+ ?~ number-of-subscriptions
143187 (~(del by search-subscriptions.state) query)
144− (~(put by search-subscriptions.state) query search-state(number-of-subscriptions number-of-subscriptions))
188+ (~(put by search-subscriptions.state) query u.search-state(number-of-subscriptions number-of-subscriptions))
145189 `this
146190 ==
147191
148−++ on-peek
192+++ on-peek
149193 |= path
150194 ~
151−++ on-agent
195+:: older versions poked their peers with peer lists, and the acks to
196+:: those pokes can still arrive after an upgrade
197+::
198+++ on-agent
152199 |= [=wire =sign:agent:gall]
153− ?+ wire `this
154− [%alive ~]
155− ?+ -.sign `this
156− %fact
157− ~& "{<src.bowl>} is alive"
158− =. alive-peers.state (~(put in alive-peers.state) src.bowl)
200+ ^- (quip card:agent:gall _this)
159201 `this
160− ==
161− ==
162202++ on-arvo
163− |= [=wire =sign-arvo]
203+ |= [=wire =sign-arvo]
164204 ^- (quip card:agent:gall _this)
165205 ~& wire
166206 ?+ wire `this
@@ -178,32 +218,12 @@ $:
178218 =. search-results.search-subscription
179219 (~(put by search-results.search-subscription) engine-name results)
180220 =. search-subscriptions.state
181− (~(put by search-subscriptions.state) query search-subscription)
221+ (~(put by search-subscriptions.state) query search-subscription)
182222 =^ card sink (sync:sink (sink-for-query query))
183223 ~& (current-engines query)
184224 [~[card] this]
185− [%check-liveness ~]
186− =/ checks
187− %+ turn ~(tap in peers.state)
188− |= peer=@p
189− [%pass /alive %agent [peer %seax] %watch /ping]
190− =. peers.state alive-peers.state
191− =. alive-peers.state *(set @p)
192− =/ timer
193− liveness-behn-card
194− :-
195− [timer checks]
196− this
197− [%gossip ~]
198− :-
199− :- gossip-behn-card
200− %+ turn ~(tap in peers.state)
201− |= peer=@p
202− [%pass / %agent [peer %seax] %poke %noun !>([%add-peers peers.state])]
203− this
204225 ==
205226++ on-fail
206− |= [term =tang]
227+ |= [term =tang]
207228 ((slog tang) `this)
208229--
209−
zod/seax/desk.docket-0new file+10
@@ -0,0 +1,10 @@
1+:~
2+ title+'%seax'
3+ info+'The Urbit meta-search engine. Sends your query to several search engines from your ship and merges their results.'
4+ color+0xff.ffff
5+ image+'/apps/seax/assets/img/tile.png'
6+ site+/apps/seax
7+ version+[0 1 0]
8+ website+'https://github.com/iko-soy/seax'
9+ license+'MIT'
10+==
zod/seax/lib/dbug.hoon+9−3
@@ -4,7 +4,8 @@
44::
55|%
66+$ poke
7− $% [%bowl ~]
7+ $% [%skip depth=@ud =poke]
8+ [%bowl ~]
89 [%state grab=cord]
910 [%incoming =about]
1011 [%outgoing =about]
@@ -32,8 +33,13 @@
3233 ?. ?=(%dbug mark)
3334 =^ cards agent (on-poke:ag mark vase)
3435 [cards this]
35− =/ dbug
36− !<(poke vase)
36+ =/ dbug !<(poke vase)
37+ =? dbug ?=([%skip %0 *] dbug) poke.dbug
38+ ?: ?=(%skip -.dbug)
39+ =^ cards agent
40+ %+ on-poke:ag %dbug
41+ !>(`poke`dbug(depth (dec depth.dbug)))
42+ [cards this]
3743 =; =tang
3844 ((%*(. slog pri 1) tang) [~ this])
3945 ?- -.dbug
zod/seax/lib/docket.hoonnew file+223
@@ -0,0 +1,223 @@
1+/- *docket
2+|%
3+::
4+++ mime
5+ |%
6+ +$ draft
7+ $: title=(unit @t)
8+ info=(unit @t)
9+ color=(unit @ux)
10+ glob-http=(unit [=url hash=@uvH])
11+ glob-ames=(unit [=ship hash=@uvH])
12+ base=(unit term)
13+ site=(unit path)
14+ image=(unit url)
15+ version=(unit version)
16+ website=(unit url)
17+ license=(unit cord)
18+ ==
19+ ::
20+ ++ finalize
21+ |= =draft
22+ ^- (unit docket)
23+ ?~ title.draft ~
24+ ?~ info.draft ~
25+ ?~ color.draft ~
26+ ?~ version.draft ~
27+ ?~ website.draft ~
28+ ?~ license.draft ~
29+ =/ href=(unit href)
30+ ?^ site.draft `[%site u.site.draft]
31+ ?~ base.draft ~
32+ ?^ glob-http.draft
33+ `[%glob u.base hash.u.glob-http %http url.u.glob-http]:draft
34+ ?~ glob-ames.draft
35+ ~
36+ `[%glob u.base hash.u.glob-ames %ames ship.u.glob-ames]:draft
37+ ?~ href ~
38+ =, draft
39+ :- ~
40+ :* %1
41+ u.title
42+ u.info
43+ u.color
44+ u.href
45+ image
46+ u.version
47+ u.website
48+ u.license
49+ ==
50+ ::
51+ ++ from-clauses
52+ =| =draft
53+ |= cls=(list clause)
54+ ^- (unit docket)
55+ =* loop $
56+ ?~ cls (finalize draft)
57+ =* clause i.cls
58+ =. draft
59+ ?- -.clause
60+ %title draft(title `title.clause)
61+ %info draft(info `info.clause)
62+ %color draft(color `color.clause)
63+ %glob-http draft(glob-http `[url hash]:clause)
64+ %glob-ames draft(glob-ames `[ship hash]:clause)
65+ %base draft(base `base.clause)
66+ %site draft(site `path.clause)
67+ %image draft(image `url.clause)
68+ %version draft(version `version.clause)
69+ %website draft(website `website.clause)
70+ %license draft(license `license.clause)
71+ ==
72+ loop(cls t.cls)
73+ ::
74+ ++ to-clauses
75+ |= d=docket
76+ ^- (list clause)
77+ %- zing
78+ :~ :~ title+title.d
79+ info+info.d
80+ color+color.d
81+ version+version.d
82+ website+website.d
83+ license+license.d
84+ ==
85+ ?~ image.d ~ ~[image+u.image.d]
86+ ?: ?=(%site -.href.d) ~[site+path.href.d]
87+ =/ ref=glob-reference glob-reference.href.d
88+ :~ base+base.href.d
89+ ?- -.location.ref
90+ %http [%glob-http url.location.ref hash.ref]
91+ %ames [%glob-ames ship.location.ref hash.ref]
92+ == == ==
93+ ::
94+ ++ spit-clause
95+ |= =clause
96+ ^- tape
97+ %+ weld " {(trip -.clause)}+"
98+ ?+ -.clause "'{(trip +.clause)}'"
99+ %color (scow %ux color.clause)
100+ %site (spud path.clause)
101+ ::
102+ %glob-http
103+ "['{(trip url.clause)}' {(scow %uv hash.clause)}]"
104+ ::
105+ %glob-ames
106+ "[{(scow %p ship.clause)} {(scow %uv hash.clause)}]"
107+ ::
108+ %version
109+ =, version.clause
110+ "[{(scow %ud major)} {(scow %ud minor)} {(scow %ud patch)}]"
111+ ==
112+ ::
113+ ++ spit-docket
114+ |= dock=docket
115+ ^- tape
116+ ;: welp
117+ ":~\0a"
118+ `tape`(zing (join "\0a" (turn (to-clauses dock) spit-clause)))
119+ "\0a=="
120+ ==
121+ --
122+::
123+++ enjs
124+ =, enjs:format
125+ |%
126+ ::
127+ ++ charge-update
128+ |= u=^charge-update
129+ ^- json
130+ %+ frond -.u
131+ ^- json
132+ ?- -.u
133+ %del-charge s+desk.u
134+ ::
135+ %initial
136+ %- pairs
137+ %+ turn ~(tap by initial.u)
138+ |=([=desk c=^charge] [desk (charge c)])
139+ ::
140+ %add-charge
141+ %- pairs
142+ :~ desk+s+desk.u
143+ charge+(charge charge.u)
144+ ==
145+ ==
146+ ::
147+ ++ num
148+ |= a=@u
149+ ^- ^tape
150+ =/ p=json (numb a)
151+ ?> ?=(%n -.p)
152+ (trip p.p)
153+ ::
154+ ++ version
155+ |= v=^version
156+ ^- json
157+ :- %s
158+ %- crip
159+ "{(num major.v)}.{(num minor.v)}.{(num patch.v)}"
160+ ::
161+ ++ merge
162+ |= [a=json b=json]
163+ ^- json
164+ ?> &(?=(%o -.a) ?=(%o -.b))
165+ [%o (~(uni by p.a) p.b)]
166+ ::
167+ ++ href
168+ |= h=^href
169+ %+ frond -.h
170+ ?- -.h
171+ %site s+(spat path.h)
172+ %glob
173+ %- pairs
174+ :~ base+s+base.h
175+ glob-reference+(glob-reference glob-reference.h)
176+ ==
177+ ==
178+ ::
179+ ++ glob-reference
180+ |= ref=^glob-reference
181+ %- pairs
182+ :~ hash+s+(scot %uv hash.ref)
183+ location+(glob-location location.ref)
184+ ==
185+ ::
186+ ++ glob-location
187+ |= loc=^glob-location
188+ ^- json
189+ %+ frond -.loc
190+ ?- -.loc
191+ %http s+url.loc
192+ %ames s+(scot %p ship.loc)
193+ ==
194+ ::
195+ ++ charge
196+ |= c=^charge
197+ %+ merge (docket docket.c)
198+ %- pairs
199+ :~ chad+(chad chad.c)
200+ ==
201+ ::
202+ ++ docket
203+ |= d=^docket
204+ ^- json
205+ %- pairs
206+ :~ title+s+title.d
207+ info+s+info.d
208+ color+s+(scot %ux color.d)
209+ href+(href href.d)
210+ image+?~(image.d ~ s+u.image.d)
211+ version+(version version.d)
212+ license+s+license.d
213+ website+s+website.d
214+ ==
215+ ::
216+ ++ chad
217+ |= c=^chad
218+ %+ frond -.c
219+ ?+ -.c ~
220+ %hung s+err.c
221+ ==
222+ --
223+--
zod/seax/lib/engines.hoon+1−3
@@ -1,15 +1,13 @@
11/- *seax
2−/+ engines-yep, engines-crowdview, engines-wiby, engines-alexandria, engines-urbit-dev
2+/+ engines-crowdview, engines-wiby, engines-urbit-dev
33
44^- engines
55
66%- malt
77%- limo
88:~
9− [name=%yep engine=engines-yep weight=.1]
109 [name=%crowdview engine=engines-crowdview weight=.2]
1110 [name=%wiby engine=engines-wiby weight=.2]
12− [name=%alexandria engine=engines-alexandria weight=.2]
1311 [name=%urbit-dev engine=engines-urbit-dev weight=.2]
1412==
1513
zod/seax/lib/engines/alexandria.hoondeleted−32
@@ -1,32 +0,0 @@
1−/- *seax
2−
3−^- engine
4−=<
5−|%
6−++ url
7− |= query=tape
8− ^- tape
9− %+ weld
10− "https://api.alexandria.org/?a=1&q="
11− (en-urlt:html query)
12−++ results
13− |= response=mime-data:iris
14− ^- (unit (list search-result))
15− =/ body q.data.response
16− ;< jon=json _biff (de:json:html body)
17− (apex jon)
18−--
19−::
20−|%
21−++ apex
22− =, dejs-soft:format
23− %- ot
24− ~[results+(ar parse-search-result)]
25−++ parse-search-result
26− =, dejs-soft:format
27− %- ot
28− ~[title+so url+so]
29−--
30−
31−
32−
zod/seax/lib/engines/crowdview.hoon+3−5
@@ -3,12 +3,10 @@
33^- engine
44=<
55|%
6−++ url
6+++ request
77 |= query=tape
8− ^- tape
9− %+ weld
10− "https://crowdview-next-js.onrender.com/api/search-v3?query="
11− (en-urlt:html query)
8+ ^- request:http
9+ (get "https://crowdview-next-js.onrender.com/api/search-v3?query=" query)
1210++ results
1311 |= response=mime-data:iris
1412 ^- (unit (list search-result))
zod/seax/lib/engines/urbit-dev.hoon+16−9
@@ -3,12 +3,18 @@
33^- engine
44=<
55|%
6−++ url
6+++ request
77 |= query=tape
8− ^- tape
9− %+ weld
10− "https://urbit.org/api/dev-search?q="
11− (en-urlt:html query)
8+ ^- request:http
9+ :^ %'POST' 'https://docs.urbit.org/~gitbook/search'
10+ ~[['content-type' 'application/json']]
11+ %- some
12+ %- as-octs:mimes:html
13+ %- en:json:html
14+ %- pairs:enjs:format
15+ :~ query+s+(crip query)
16+ scope+(pairs:enjs:format ~[mode+s+'all'])
17+ ==
1218++ results
1319 |= response=mime-data:iris
1420 ^- (unit (list search-result))
@@ -20,10 +26,11 @@
2026|%
2127++ apex
2228 =, dejs-soft:format
23− %- ot
24− ~[glossary+(ar parse-search-result)]
29+ (ar parse-search-result)
2530++ parse-search-result
31+ |= jon=json
32+ ^- (unit search-result)
2633 =, dejs-soft:format
27− %- ot
28− ~[[%'name' so] [%'url' so]]
34+ ;< [title=@t href=@t] _biff ((ot ~[title+so href+so]) jon)
35+ `[title (cat 3 'https://docs.urbit.org' href)]
2936--
zod/seax/lib/engines/wiby.hoon+3−5
@@ -3,12 +3,10 @@
33^- engine
44=<
55|%
6−++ url
6+++ request
77 |= query=tape
8− ^- tape
9− %+ weld
10− "https://wiby.me/json/?q="
11− (en-urlt:html query)
8+ ^- request:http
9+ (get "https://wiby.me/json/?q=" query)
1210++ results
1311 |= response=mime-data:iris
1412 ^- (unit (list search-result))
zod/seax/lib/engines/yep.hoondeleted−30
@@ -1,30 +0,0 @@
1−/- *seax
2−
3−^- engine
4−=<
5−|%
6−++ url
7− |= query=tape
8− ^- tape
9− %+ weld
10− "https://api.yep.com/fs/1/?type=web&no_correct=false&limit=100&q="
11− (en-urlt:html query)
12−++ results
13− |= response=mime-data:iris
14− =/ body q.data.response
15− ;< jon=json _biff (de:json:html body)
16− (apex jon)
17−--
18−::
19−|%
20−++ apex
21− |= jon=json
22− ^- (unit (list search-result))
23− =, dejs-soft:format
24− ;< [* results=(list search-result)] _biff %- (at ~[so (ot ~[results+(ar parse-search-result)])]) jon
25− `results
26−++ parse-search-result
27− =, dejs-soft:format
28− %- ot
29− ~[title+so url+so]
30−--
zod/seax/lib/graph-store.hoondeleted−919
@@ -1,919 +0,0 @@
1−/- sur=graph-store, pos=post, pull-hook, hark=hark-store
2−/+ res=resource, migrate
3−=< [sur .]
4−=< [pos .]
5−=, sur
6−=, pos
7−|%
8−++ hark-content
9− |= =content
10− ^- content:hark
11− ?- -.content
12− %text content
13− %mention ship+ship.content
14− %url text+url.content
15− %code text+'A code excerpt'
16− %reference text+'A reference'
17− ==
18−::
19−++ hark-contents
20− |= cs=(list content)
21− (turn cs hark-content)
22−:: NOTE: move these functions to zuse
23−++ nu :: parse number as hex
24− |= jon=json
25− ?> ?=([%s *] jon)
26− (rash p.jon hex)
27−::
28−++ re :: recursive reparsers
29− |* [gar=* sef=_|.(fist:dejs-soft:format)]
30− |= jon=json
31− ^- (unit _gar)
32− =- ~! gar ~! (need -) -
33− ((sef) jon)
34−::
35−++ dank :: tank
36− ^- $-(json (unit tank))
37− =, ^? dejs-soft:format
38− %+ re *tank |. ~+
39− %- of :~
40− leaf+sa
41− palm+(ot style+(ot mid+sa cap+sa open+sa close+sa ~) lines+(ar dank) ~)
42− rose+(ot style+(ot mid+sa open+sa close+sa ~) lines+(ar dank) ~)
43− ==
44−::
45−++ orm ((on atom node) gth)
46−++ orm-log ((on time logged-update) gth)
47−::
48−++ enjs
49− =, enjs:format
50− |%
51− ::
52− ++ signatures
53− |= s=^signatures
54− ^- json
55− [%a (turn ~(tap in s) signature)]
56− ::
57− ++ signature
58− |= s=^signature
59− ^- json
60− %- pairs
61− :~ [%signature s+(scot %ux p.s)]
62− [%ship (ship q.s)]
63− [%life (numb r.s)]
64− ==
65− ::
66− ++ index
67− |= ind=^index
68− ^- json
69− :- %s
70− ?: =(~ ind)
71− '/'
72− %+ roll ind
73− |= [cur=@ acc=@t]
74− ^- @t
75− =/ num (numb cur)
76− ?> ?=(%n -.num)
77− (rap 3 acc '/' p.num ~)
78− ::
79− ++ uid
80− |= u=^uid
81− ^- json
82− %- pairs
83− :~ [%resource (enjs:res resource.u)]
84− [%index (index index.u)]
85− ==
86− ::
87− ++ content
88− |= c=^content
89− ^- json
90− ?- -.c
91− %mention (frond %mention (ship ship.c))
92− %text (frond %text s+text.c)
93− %url (frond %url s+url.c)
94− %reference (frond %reference (reference +.c))
95− %code
96− %+ frond %code
97− %- pairs
98− :- [%expression s+expression.c]
99− :_ ~
100− :- %output
101− :: virtualize output rendering, +tank:enjs:format might crash
102− ::
103− =/ result=(each (list json) tang)
104− (mule |.((turn output.c tank)))
105− ?- -.result
106− %& a+p.result
107− %| a+[a+[%s '[[output rendering error]]']~]~
108− ==
109− ==
110− ::
111− ++ reference
112− |= ref=^reference
113− |^
114− %+ frond -.ref
115− ?- -.ref
116− %graph (graph +.ref)
117− %group (group +.ref)
118− %app (app +.ref)
119− ==
120− ::
121− ++ graph
122− |= [grp=res gra=res idx=^index]
123− %- pairs
124− :~ graph+s+(enjs-path:res gra)
125− group+s+(enjs-path:res grp)
126− index+(index idx)
127− ==
128− ::
129− ++ group
130− |= grp=res
131− s+(enjs-path:res grp)
132− ::
133− ++ app
134− |= [=^ship =desk p=^path]
135− %- pairs
136− :~ ship+s+(scot %p ship)
137− desk+s+desk
138− path+(path p)
139− ==
140− --
141− ::
142− ++ maybe-post
143− |= mp=^maybe-post
144− ^- json
145− ?- -.mp
146− %| s+(scot %ux p.mp)
147− %& (post p.mp)
148− ==
149− ::
150− ++ post
151− |= p=^post
152− ^- json
153− %- pairs
154− :~ [%author (ship author.p)]
155− [%index (index index.p)]
156− [%time-sent (time time-sent.p)]
157− [%contents [%a (turn contents.p content)]]
158− [%hash ?~(hash.p ~ s+(scot %ux u.hash.p))]
159− [%signatures (signatures signatures.p)]
160− ==
161− ::
162− ++ update
163− |= upd=^update
164− ^- json
165− |^ (frond %graph-update (pairs ~[(encode q.upd)]))
166− ::
167− ++ encode
168− |= upd=action
169− ^- [cord json]
170− ?- -.upd
171− %add-graph
172− :- %add-graph
173− %- pairs
174− :~ [%resource (enjs:res resource.upd)]
175− [%graph (graph graph.upd)]
176− [%mark ?~(mark.upd ~ s+u.mark.upd)]
177− [%overwrite b+overwrite.upd]
178− ==
179− ::
180− %remove-graph
181− [%remove-graph (enjs:res resource.upd)]
182− ::
183− %add-nodes
184− :- %add-nodes
185− %- pairs
186− :~ [%resource (enjs:res resource.upd)]
187− [%nodes (nodes nodes.upd)]
188− ==
189− ::
190− %remove-posts
191− :- %remove-posts
192− %- pairs
193− :~ [%resource (enjs:res resource.upd)]
194− [%indices (indices indices.upd)]
195− ==
196− ::
197− %add-signatures
198− :- %add-signatures
199− %- pairs
200− :~ [%uid (uid uid.upd)]
201− [%signatures (signatures signatures.upd)]
202− ==
203− ::
204− %remove-signatures
205− :- %remove-signatures
206− %- pairs
207− :~ [%uid (uid uid.upd)]
208− [%signatures (signatures signatures.upd)]
209− ==
210− ::
211− %add-tag
212− :- %add-tag
213− %- pairs
214− :~ [%term s+term.upd]
215− [%uid (uid uid.upd)]
216− ==
217− ::
218− %remove-tag
219− :- %remove-tag
220− %- pairs
221− :~ [%term s+term.upd]
222− [%uid (uid uid.upd)]
223− ==
224− ::
225− %archive-graph
226− [%archive-graph (enjs:res resource.upd)]
227− ::
228− %unarchive-graph
229− [%unarchive-graph (enjs:res resource.upd)]
230− ::
231− %keys
232− [%keys [%a (turn ~(tap in resources.upd) enjs:res)]]
233− ::
234− %tags
235− [%tags [%a (turn ~(tap in tags.upd) |=(=term s+term))]]
236− ::
237− %run-updates
238− [%run-updates ~]
239− ::
240− %tag-queries
241− :- %tag-queries
242− %- pairs
243− %+ turn ~(tap by tag-queries.upd)
244− |= [=term uids=(set ^uid)]
245− ^- [cord json]
246− [term [%a (turn ~(tap in uids) uid)]]
247− ==
248− ::
249− ++ graph
250− |= g=^graph
251− ^- json
252− %- pairs
253− %+ turn
254− (tap:orm g)
255− |= [a=atom n=^node]
256− ^- [@t json]
257− :_ (node n)
258− =/ idx (numb a)
259− ?> ?=(%n -.idx)
260− p.idx
261− ::
262− ++ node
263− |= n=^node
264− ^- json
265− %- pairs
266− :~ [%post (maybe-post post.n)]
267− :- %children
268− ?- -.children.n
269− %empty ~
270− %graph (graph +.children.n)
271− ==
272− ==
273− ::
274− ++ nodes
275− |= m=(map ^index ^node)
276− ^- json
277− %- pairs
278− %+ turn ~(tap by m)
279− |= [n=^index o=^node]
280− ^- [@t json]
281− :_ (node o)
282− =/ idx (index n)
283− ?> ?=(%s -.idx)
284− p.idx
285− ::
286− ++ indices
287− |= i=(set ^index)
288− ^- json
289− [%a (turn ~(tap in i) index)]
290− ::
291− --
292− --
293−::
294−++ dejs
295− =, dejs:format
296− |%
297− ++ update
298− |= jon=json
299− ^- ^update
300− :- *time
301− ^- action
302− =< (decode jon)
303− |%
304− ++ decode
305− %- of
306− :~ [%add-nodes add-nodes]
307− [%remove-posts remove-posts]
308− [%add-signatures add-signatures]
309− [%remove-signatures remove-signatures]
310− ::
311− [%add-graph add-graph]
312− [%remove-graph remove-graph]
313− ::
314− [%add-tag add-tag]
315− [%remove-tag remove-tag]
316− ::
317− [%archive-graph archive-graph]
318− [%unarchive-graph unarchive-graph]
319− [%run-updates run-updates]
320− ::
321− [%keys keys]
322− [%tags tags]
323− [%tag-queries tag-queries]
324− ==
325− ::
326− ++ add-graph
327− %- ot
328− :~ [%resource dejs:res]
329− [%graph graph]
330− [%mark (mu so)]
331− [%overwrite bo]
332− ==
333− ::
334− ++ graph
335− |= a=json
336− ^- ^graph
337− =/ or-mp ((on atom ^node) gth)
338− %+ gas:or-mp ~
339− %+ turn ~(tap by ((om node) a))
340− |* [b=cord c=*]
341− ^- [atom ^node]
342− => .(+< [b c]=+<)
343− [(rash b dem) c]
344− ::
345− ++ remove-graph (ot [%resource dejs:res]~)
346− ++ archive-graph (ot [%resource dejs:res]~)
347− ++ unarchive-graph (ot [%resource dejs:res]~)
348− ::
349− ++ add-nodes
350− %- ot
351− :~ [%resource dejs:res]
352− [%nodes nodes]
353− ==
354− ::
355− ++ nodes (op ;~(pfix fas (more fas dem)) node)
356− ::
357− ++ node
358− %- ot
359− :~ [%post maybe-post]
360− [%children internal-graph]
361− ==
362− ::
363− ++ internal-graph
364− |= jon=json
365− ^- ^internal-graph
366− ?~ jon
367− [%empty ~]
368− [%graph (graph jon)]
369− ::
370− ++ maybe-post
371− |= jon=json
372− ^- ^maybe-post
373− ?~ jon !!
374− ?+ -.jon !!
375− %s [%| (nu jon)]
376− %o [%& (post jon)]
377− ==
378− ::
379− ++ post
380− %- ot
381− :~ [%author (su ;~(pfix sig fed:ag))]
382− [%index index]
383− [%time-sent di]
384− [%contents (ar content)]
385− [%hash (mu nu)]
386− [%signatures (as signature)]
387− ==
388− ::
389− ++ content
390− %- of
391− :~ [%mention (su ;~(pfix sig fed:ag))]
392− [%text so]
393− [%url so]
394− [%reference reference]
395− [%code eval]
396− ==
397− ::
398− ++ reference
399− |^
400− %- of
401− :~ graph+graph
402− group+dejs-path:res
403− app+app
404− ==
405− ::
406− ++ graph
407− %- ot
408− :~ group+dejs-path:res
409− graph+dejs-path:res
410− index+index
411− ==
412− ::
413− ++ app
414− %- ot
415− :~ ship+(su ;~(pfix sig fed:ag))
416− desk+so
417− path+pa
418− ==
419− --
420− ::
421− ++ tang
422− |= jon=^json
423− ^- ^tang
424− ?> ?=(%a -.jon)
425− %- zing
426− %+ turn
427− p.jon
428− |= jo=^json
429− ^- (list tank)
430− ?> ?=(%a -.jo)
431− %+ turn
432− p.jo
433− |= j=^json
434− ?> ?=(%s -.j)
435− ^- tank
436− leaf+(trip p.j)
437− ::
438− ++ eval
439− %- ot
440− :~ expression+so
441− output+tang
442− ==
443− ::
444− ++ remove-posts
445− %- ot
446− :~ [%resource dejs:res]
447− [%indices (as index)]
448− ==
449− ::
450− ++ add-signatures
451− %- ot
452− :~ [%uid uid]
453− [%signatures (as signature)]
454− ==
455− ::
456− ++ remove-signatures
457− %- ot
458− :~ [%uid uid]
459− [%signatures (as signature)]
460− ==
461− ::
462− ++ signature
463− %- ot
464− :~ [%hash nu]
465− [%ship (su ;~(pfix sig fed:ag))]
466− [%life ni]
467− ==
468− ::
469− ++ uid
470− %- ot
471− :~ [%resource dejs:res]
472− [%index index]
473− ==
474− ::
475− ++ index (su ;~(pfix fas (more fas dem)))
476− ::
477− ++ add-tag
478− %- ot
479− :~ [%term so]
480− [%uid uid]
481− ==
482− ::
483− ++ remove-tag
484− %- ot
485− :~ [%term so]
486− [%uid uid]
487− ==
488− ::
489− ++ keys
490− |= =json
491− *resources
492− ::
493− ++ tags
494− |= =json
495− *(set term)
496− ::
497− ++ tag-queries
498− |= =json
499− *^tag-queries
500− ::
501− ++ run-updates
502− |= a=json
503− ^- [resource update-log]
504− [*resource *update-log]
505− --
506− ++ pa
507− |= j=json
508− ^- path
509− ?> ?=(%s -.j)
510− ?: =('/' p.j) /
511− (stab p.j)
512− ::
513− --
514−::
515−++ create
516− |_ [our=ship now=time]
517− ++ post
518− |= [=index contents=(list content)]
519− ^- ^post
520− :* our
521− index
522− now
523− contents
524− ~
525− *signatures
526− ==
527− --
528−::
529−++ upgrade
530− |%
531− ::
532− :: +two
533− ::
534− ++ marked-graph-to-two
535− |= [=graph:one m=(unit mark)]
536− [(graph-to-two graph) m]
537− ::
538− ++ graph-to-two
539− |= =graph:one
540− (graph:(upgrade ,post:one ,maybe-post:two) graph post-to-two)
541− ::
542− ++ post-to-two
543− |= p=post:one
544− ^- maybe-post:two
545− [%& p]
546− ::
547− ::
548− :: +one
549− ::
550− ++ update-log-to-one
551− |= =update-log:zero
552− ^- update-log:one
553− %+ gas:orm-log:one *update-log:one
554− %+ turn (tap:orm-log:zero update-log)
555− |= [=time =logged-update:zero]
556− ^- [^time logged-update:one]
557− :- time
558− :- p.logged-update
559− (logged-update-to-one q.logged-update)
560− ::
561− ++ logged-update-to-one
562− |= upd=logged-update-0:zero
563− ^- logged-action:one
564− ?+ -.upd upd
565− %add-graph upd(graph (graph-to-one graph.upd))
566− %add-nodes upd(nodes (~(run by nodes.upd) node-to-one))
567− ==
568− ::
569− ++ node-to-one
570− |= =node:zero
571− (node:(upgrade ,post:zero ,post:one) node post-to-one)
572− ::
573− ++ graph-to-one
574− |= =graph:zero
575− (graph:(upgrade ,post:zero ,post:one) graph post-to-one)
576− ::
577− ++ marked-graph-to-one
578− |= [=graph:zero m=(unit mark)]
579− [(graph-to-one graph) m]
580− ::
581− ++ post-to-one
582− |= p=post:zero
583− ^- post:one
584− p(contents (contents-to-one contents.p))
585− ::
586− ++ contents-to-one
587− |= cs=(list content:zero)
588− ^- (list content:one)
589− %+ murn cs
590− |= =content:zero
591− ^- (unit content:one)
592− ?: ?=(%reference -.content) ~
593− `content
594− ::
595− ++ upgrade
596− |* [in-pst=mold out-pst=mold]
597− =>
598− |%
599− ++ in-orm
600− ((on atom in-node) gth)
601− +$ in-node
602− [post=in-pst children=in-internal-graph]
603− +$ in-graph
604− ((mop atom in-node) gth)
605− +$ in-internal-graph
606− $~ [%empty ~]
607− $% [%graph p=in-graph]
608− [%empty ~]
609− ==
610− ::
611− ++ out-orm
612− ((on atom out-node) gth)
613− +$ out-node
614− [post=out-pst children=out-internal-graph]
615− +$ out-graph
616− ((mop atom out-node) gth)
617− +$ out-internal-graph
618− $~ [%empty ~]
619− $% [%graph p=out-graph]
620− [%empty ~]
621− ==
622− --
623− |%
624− ::
625− ++ graph
626− |= $: gra=in-graph
627− fn=$-(in-pst out-pst)
628− ==
629− ^- out-graph
630− %+ gas:out-orm *out-graph
631− ^- (list [atom out-node])
632− %+ turn (tap:in-orm gra)
633− |= [a=atom n=in-node]
634− ^- [atom out-node]
635− [a (node n fn)]
636− ::
637− ++ node
638− |= [nod=in-node fn=$-(in-pst out-pst)]
639− ^- out-node
640− :- (fn post.nod)
641− ^- out-internal-graph
642− ?: ?=(%empty -.children.nod)
643− [%empty ~]
644− [%graph (graph p.children.nod fn)]
645− --
646− ::
647− ++ zero-load
648− :: =* infinitely recurses
649− =, store=zero
650− =, orm=orm:zero
651− =, orm-log=orm-log:zero
652− |%
653− ++ change-revision-graph
654− |= [=graph:store q=(unit mark)]
655− ^- [graph:store (unit mark)]
656− |^
657− :_ q
658− ?+ q graph
659− [~ %graph-validator-link] convert-links
660− [~ %graph-validator-publish] convert-publish
661− ==
662− ::
663− ++ convert-links
664− %+ gas:orm *graph:store
665− %+ turn (tap:orm graph)
666− |= [=atom =node:store]
667− ^- [^atom node:store]
668− :: top-level
669− ::
670− :+ atom post.node
671− ?: ?=(%empty -.children.node)
672− [%empty ~]
673− :- %graph
674− %+ gas:orm *graph:store
675− %+ turn (tap:orm p.children.node)
676− |= [=^atom =node:store]
677− ^- [^^atom node:store]
678− :: existing comments get turned into containers for revisions
679− ::
680− :^ atom
681− post.node(contents ~, hash ~)
682− %graph
683− %+ gas:orm *graph:store
684− :_ ~ :- %0
685− :_ [%empty ~]
686− post.node(index (snoc index.post.node atom), hash ~)
687− ::
688− ++ convert-publish
689− %+ gas:orm *graph:store
690− %+ turn (tap:orm graph)
691− |= [=atom =node:store]
692− ^- [^atom node:store]
693− :: top-level
694− ::
695− :+ atom post.node
696− ?: ?=(%empty -.children.node)
697− [%empty ~]
698− :- %graph
699− %+ gas:orm *graph:store
700− %+ turn (tap:orm p.children.node)
701− |= [=^atom =node:store]
702− ^- [^^atom node:store]
703− :: existing container for publish note revisions
704− ::
705− ?+ atom !!
706− %1 [atom node]
707− %2
708− :+ atom post.node
709− ?: ?=(%empty -.children.node)
710− [%empty ~]
711− :- %graph
712− %+ gas:orm *graph:store
713− %+ turn (tap:orm p.children.node)
714− |= [=^^atom =node:store]
715− ^- [^^^atom node:store]
716− :+ atom post.node(contents ~, hash ~)
717− :- %graph
718− %+ gas:orm *graph:store
719− :_ ~ :- %1
720− :_ [%empty ~]
721− post.node(index (snoc index.post.node atom), hash ~)
722− ==
723− --
724− ::
725− ++ maybe-unix-to-da
726− |= =atom
727− ^- @
728− :: (bex 127) is roughly 226AD
729− ?. (lte atom (bex 127))
730− atom
731− (add ~1970.1.1 (div (mul ~s1 atom) 1.000))
732− ::
733− ++ convert-unix-timestamped-node
734− |= =node:store
735− ^- node:store
736− =. index.post.node
737− (convert-unix-timestamped-index index.post.node)
738− ?. ?=(%graph -.children.node)
739− node
740− :+ post.node
741− %graph
742− (convert-unix-timestamped-graph p.children.node)
743− ::
744− ++ convert-unix-timestamped-index
745− |= =index:store
746− (turn index maybe-unix-to-da)
747− ::
748− ++ convert-unix-timestamped-graph
749− |= =graph:store
750− %+ gas:orm *graph:store
751− %+ turn
752− (tap:orm graph)
753− |= [=atom =node:store]
754− ^- [^atom node:store]
755− :- (maybe-unix-to-da atom)
756− (convert-unix-timestamped-node node)
757− --
758− --
759−++ import
760− |= [arc=* our=ship]
761− ^- (quip card:agent:gall [%6 network])
762− |^
763− =/ sty [%6 (remake-network ;;(tree-network +.arc))]
764− :_ sty
765− %+ turn ~(tap by graphs.sty)
766− |= [rid=resource =marked-graph]
767− ^- card:agent:gall
768− ?: =(our entity.rid)
769− =/ =cage [%push-hook-action !>([%add rid])]
770− [%pass / %agent [our %graph-push-hook] %poke cage]
771− (try-rejoin rid 0)
772− ::
773− +$ tree-network
774− $: graphs=tree-graphs
775− tag-queries=(tree [term (tree uid)])
776− update-logs=tree-update-logs
777− archive=tree-graphs
778− ~
779− ==
780− +$ tree-graphs (tree [resource tree-marked-graph])
781− +$ tree-marked-graph [p=tree-graph q=(unit ^mark)]
782− +$ tree-graph (tree [atom tree-node])
783− +$ tree-node [post=tree-maybe-post children=tree-internal-graph]
784− +$ tree-internal-graph
785− $~ [%empty ~]
786− $% [%graph p=tree-graph]
787− [%empty ~]
788− ==
789− +$ tree-update-logs (tree [resource tree-update-log])
790− +$ tree-update-log (tree [time tree-logged-update])
791− +$ tree-logged-update
792− $: p=time
793− $= q
794− $% [%add-graph =resource =tree-graph mark=(unit ^mark) ow=?]
795− [%add-nodes =resource nodes=(tree [index tree-node])]
796− [%remove-posts =resource indices=(tree index)]
797− [%add-signatures =uid signatures=tree-signatures]
798− [%remove-signatures =uid signatures=tree-signatures]
799− ==
800− ==
801− +$ tree-signatures (tree signature)
802− +$ tree-maybe-post (each tree-post hash)
803− +$ tree-post
804− $: author=ship
805− =index
806− time-sent=time
807− contents=(list content)
808− hash=(unit hash)
809− signatures=tree-signatures
810− ==
811− ::
812− ++ remake-network
813− |= t=tree-network
814− ^- network
815− :* (remake-graphs graphs.t)
816− (remake-jug:migrate tag-queries.t)
817− (remake-update-logs update-logs.t)
818− (remake-graphs archive.t)
819− ~
820− ==
821− ::
822− ++ remake-graphs
823− |= t=tree-graphs
824− ^- graphs
825− %- remake-map:migrate
826− (~(run by t) remake-marked-graph)
827− ::
828− ++ remake-marked-graph
829− |= t=tree-marked-graph
830− ^- marked-graph
831− [(remake-graph p.t) q.t]
832− ::
833− ++ remake-graph
834− |= t=tree-graph
835− ^- graph
836− %+ gas:orm *graph
837− %+ turn ~(tap by t)
838− |= [a=atom tn=tree-node]
839− ^- [atom node]
840− [a (remake-node tn)]
841− ::
842− ++ remake-internal-graph
843− |= t=tree-internal-graph
844− ^- internal-graph
845− ?: ?=(%empty -.t)
846− [%empty ~]
847− [%graph (remake-graph p.t)]
848− ::
849− ++ remake-node
850− |= t=tree-node
851− ^- node
852− :- (remake-post post.t)
853− (remake-internal-graph children.t)
854− ::
855− ++ remake-update-logs
856− |= t=tree-update-logs
857− ^- update-logs
858− %- remake-map:migrate
859− (~(run by t) remake-update-log)
860− ::
861− ++ remake-update-log
862− |= t=tree-update-log
863− ^- update-log
864− =/ ulm ((on time logged-update) gth)
865− %+ gas:ulm *update-log
866− %+ turn ~(tap by t)
867− |= [=time tlu=tree-logged-update]
868− ^- [^time logged-update]
869− [time (remake-logged-update tlu)]
870− ::
871− ++ remake-logged-update
872− |= t=tree-logged-update
873− ^- logged-update
874− :- p.t
875− ?- -.q.t
876− %add-graph
877− :* %add-graph
878− resource.q.t
879− (remake-graph tree-graph.q.t)
880− mark.q.t
881− ow.q.t
882− ==
883− ::
884− %add-nodes
885− :- %add-nodes
886− :- resource.q.t
887− %- remake-map:migrate
888− (~(run by nodes.q.t) remake-node)
889− ::
890− %remove-posts
891− [%remove-posts resource.q.t (remake-set:migrate indices.q.t)]
892− ::
893− %add-signatures
894− [%add-signatures uid.q.t (remake-set:migrate signatures.q.t)]
895− ::
896− %remove-signatures
897− [%remove-signatures uid.q.t (remake-set:migrate signatures.q.t)]
898− ==
899− ::
900− ++ remake-post
901− |= t=tree-maybe-post
902− ^- maybe-post
903− ?- -.t
904− %| t
905− %& t(signatures.p (remake-set:migrate signatures.p.t))
906− ==
907− ::
908− ++ try-rejoin
909− |= [rid=resource nack-count=@]
910− ^- card:agent:gall
911− =/ res-path (en-path:res rid)
912− =/ wire [%try-rejoin (scot %ud nack-count) res-path]
913− =/ =cage
914− :- %pull-hook-action
915− !> ^- action:pull-hook
916− [%add [entity .]:rid]
917− [%pass wire %agent [our %graph-pull-hook] %poke cage]
918− --
919−--
zod/seax/lib/migrate.hoondeleted−19
@@ -1,19 +0,0 @@
1−^? |%
2−++ remake-set
3− |* s=(tree)
4− (sy ~(tap in s))
5−::
6−++ remake-map
7− |* m=(tree)
8− (my ~(tap by m))
9−::
10−++ remake-jug
11− |* j=(tree [* (tree)])
12− %- remake-map
13− (~(run by j) remake-set)
14−::
15−++ remake-map-of-map
16− |* mm=(tree [* (tree)])
17− %- remake-map
18− (~(run by mm) remake-map)
19−--
zod/seax/lib/resource.hoondeleted−57
@@ -1,57 +0,0 @@
1−/- sur=resource
2−=< resource
3−|%
4−+$ resource resource:sur
5−++ en-path
6− |= =resource
7− ^- path
8− ~[%ship (scot %p entity.resource) name.resource]
9−::
10−++ de-path
11− |= =path
12− ^- resource
13− (need (de-path-soft path))
14−::
15−++ de-path-soft
16− |= =path
17− ^- (unit resource)
18− ?. ?=([%ship @ @ *] path)
19− ~
20− =/ ship
21− (slaw %p i.t.path)
22− ?~ ship
23− ~
24− `[u.ship i.t.t.path]
25−::
26−++ enjs
27− |= =resource
28− ^- json
29− =, enjs:format
30− %- pairs
31− :~ ship+(ship entity.resource)
32− name+s+name.resource
33− ==
34−::
35−++ enjs-path
36− |= =resource
37− %- spat
38− (en-path resource)
39−::
40−++ dejs-path
41− %- su:dejs:format
42− ;~ pfix
43− (jest '/ship/')
44− ;~((glue fas) ;~(pfix sig fed:ag) urs:ab)
45− ==
46−::
47−++ dejs
48− =, dejs:format
49− ^- $-(json resource)
50− |= jon=json
51− ~| dejs+%resource
52− %. jon
53− %- ot
54− :~ ship+(su ;~(pfix sig fed:ag))
55− name+so
56− ==
57−--
zod/seax/lib/server.hoonnew file+159
@@ -0,0 +1,159 @@
1+=, eyre
2+|%
3++$ request-line
4+ $: [ext=(unit @ta) site=(list @t)]
5+ args=(list [key=@t value=@t])
6+ ==
7+:: +parse-request-line: take a cord and parse out a url
8+::
9+++ parse-request-line
10+ |= url=@t
11+ ^- request-line
12+ (fall (rush url ;~(plug apat:de-purl:html yque:de-purl:html)) [[~ ~] ~])
13+::
14+++ manx-to-octs
15+ |= man=manx
16+ ^- octs
17+ (as-octt:mimes:html (en-xml:html man))
18+::
19+++ json-to-octs
20+ |= jon=json
21+ ^- octs
22+ (as-octs:mimes:html (en:json:html jon))
23+::
24+++ app
25+ |%
26+ ::
27+ :: +require-authorization:
28+ :: redirect to the login page when unauthenticated
29+ :: otherwise call handler on inbound request
30+ ::
31+ ++ require-authorization
32+ |= $: =inbound-request:eyre
33+ handler=$-(inbound-request:eyre simple-payload:http)
34+ ==
35+ ^- simple-payload:http
36+ ::
37+ ?: authenticated.inbound-request
38+ ~! this
39+ ~! +:*handler
40+ (handler inbound-request)
41+ ::
42+ =- [[307 ['location' -]~] ~]
43+ %^ cat 3
44+ '/~/login?redirect='
45+ url.request.inbound-request
46+ ::
47+ :: +require-authorization-simple:
48+ :: redirect to the login page when unauthenticated
49+ :: otherwise pass through simple-paylod
50+ ::
51+ ++ require-authorization-simple
52+ |= [=inbound-request:eyre =simple-payload:http]
53+ ^- simple-payload:http
54+ ::
55+ ?: authenticated.inbound-request
56+ ~! this
57+ simple-payload
58+ ::
59+ =- [[307 ['location' -]~] ~]
60+ %^ cat 3
61+ '/~/login?redirect='
62+ url.request.inbound-request
63+ ::
64+ ++ give-simple-payload
65+ |= [eyre-id=@ta =simple-payload:http]
66+ ^- (list card:agent:gall)
67+ =/ header-cage
68+ [%http-response-header !>(response-header.simple-payload)]
69+ =/ data-cage
70+ [%http-response-data !>(data.simple-payload)]
71+ :~ [%give %fact ~[/http-response/[eyre-id]] header-cage]
72+ [%give %fact ~[/http-response/[eyre-id]] data-cage]
73+ [%give %kick ~[/http-response/[eyre-id]] ~]
74+ ==
75+ --
76+++ gen
77+ |%
78+ ::
79+ ++ max-1-da ['cache-control' 'max-age=86400']
80+ ++ max-1-wk ['cache-control' 'max-age=604800']
81+ ::
82+ ++ html-response
83+ =| cache=?
84+ |= =octs
85+ ^- simple-payload:http
86+ :_ `octs
87+ [200 [['content-type' 'text/html'] ?:(cache [max-1-wk ~] ~)]]
88+ ::
89+ ++ css-response
90+ =| cache=?
91+ |= =octs
92+ ^- simple-payload:http
93+ :_ `octs
94+ [200 [['content-type' 'text/css'] ?:(cache [max-1-wk ~] ~)]]
95+ ::
96+ ++ js-response
97+ =| cache=?
98+ |= =octs
99+ ^- simple-payload:http
100+ :_ `octs
101+ [200 [['content-type' 'text/javascript'] ?:(cache [max-1-wk ~] ~)]]
102+ ::
103+ ++ png-response
104+ =| cache=?
105+ |= =octs
106+ ^- simple-payload:http
107+ :_ `octs
108+ [200 [['content-type' 'image/png'] ?:(cache [max-1-wk ~] ~)]]
109+ ::
110+ ++ svg-response
111+ =| cache=?
112+ |= =octs
113+ ^- simple-payload:http
114+ :_ `octs
115+ [200 [['content-type' 'image/svg+xml'] ?:(cache [max-1-wk ~] ~)]]
116+ ::
117+ ++ ico-response
118+ |= =octs
119+ ^- simple-payload:http
120+ [[200 [['content-type' 'image/x-icon'] max-1-wk ~]] `octs]
121+ ::
122+ ++ woff2-response
123+ =| cache=?
124+ |= =octs
125+ ^- simple-payload:http
126+ [[200 [['content-type' 'font/woff2'] max-1-wk ~]] `octs]
127+ ::
128+ ++ json-response
129+ =| cache=_|
130+ |= =json
131+ ^- simple-payload:http
132+ :_ `(json-to-octs json)
133+ [200 [['content-type' 'application/json'] ?:(cache [max-1-da ~] ~)]]
134+ ::
135+ ++ manx-response
136+ =| cache=_|
137+ |= man=manx
138+ ^- simple-payload:http
139+ :_ `(manx-to-octs man)
140+ [200 [['content-type' 'text/html'] ?:(cache [max-1-da ~] ~)]]
141+ ::
142+ ++ not-found
143+ ^- simple-payload:http
144+ [[404 ~] ~]
145+ ::
146+ ++ login-redirect
147+ |= =request:http
148+ ^- simple-payload:http
149+ =- [[307 ['location' -]~] ~]
150+ %^ cat 3
151+ '/~/login?redirect='
152+ url.request
153+ ::
154+ ++ redirect
155+ |= redirect=cord
156+ ^- simple-payload:http
157+ [[307 ['location' redirect]~] ~]
158+ --
159+--
zod/seax/lib/strand.hoondeleted−1
@@ -1 +0,0 @@
1−rand
zod/seax/lib/strandio.hoondeleted−812
@@ -1,812 +0,0 @@
1−/- spider
2−/+ libstrand=strand
3−=, strand=strand:libstrand
4−=, strand-fail=strand-fail:libstrand
5−|%
6−++ send-raw-cards
7− |= cards=(list =card:agent:gall)
8− =/ m (strand ,~)
9− ^- form:m
10− |= strand-input:strand
11− [cards %done ~]
12−::
13−++ send-raw-card
14− |= =card:agent:gall
15− =/ m (strand ,~)
16− ^- form:m
17− (send-raw-cards card ~)
18−::
19−++ ignore
20− |= tin=strand-input:strand
21− `[%fail %ignore ~]
22−::
23−++ get-bowl
24− =/ m (strand ,bowl:strand)
25− ^- form:m
26− |= tin=strand-input:strand
27− `[%done bowl.tin]
28−::
29−++ get-beak
30− =/ m (strand ,beak)
31− ^- form:m
32− |= tin=strand-input:strand
33− `[%done [our q.byk da+now]:bowl.tin]
34−::
35−++ get-time
36− =/ m (strand ,@da)
37− ^- form:m
38− |= tin=strand-input:strand
39− `[%done now.bowl.tin]
40−::
41−++ get-our
42− =/ m (strand ,ship)
43− ^- form:m
44− |= tin=strand-input:strand
45− `[%done our.bowl.tin]
46−::
47−++ get-entropy
48− =/ m (strand ,@uvJ)
49− ^- form:m
50− |= tin=strand-input:strand
51− `[%done eny.bowl.tin]
52−::
53−:: Convert skips to %ignore failures.
54−::
55−:: This tells the main loop to try the next handler.
56−::
57−++ handle
58− |* a=mold
59− =/ m (strand ,a)
60− |= =form:m
61− ^- form:m
62− |= tin=strand-input:strand
63− =/ res (form tin)
64− =? next.res ?=(%skip -.next.res)
65− [%fail %ignore ~]
66− res
67−::
68−:: Wait for a poke with a particular mark
69−::
70−++ take-poke
71− |= =mark
72− =/ m (strand ,vase)
73− ^- form:m
74− |= tin=strand-input:strand
75− ?+ in.tin `[%skip ~]
76− ~
77− `[%wait ~]
78− ::
79− [~ %poke @ *]
80− ?. =(mark p.cage.u.in.tin)
81− `[%skip ~]
82− `[%done q.cage.u.in.tin]
83− ==
84−::
85−++ take-sign-arvo
86− =/ m (strand ,[wire sign-arvo])
87− ^- form:m
88− |= tin=strand-input:strand
89− ?+ in.tin `[%skip ~]
90− ~
91− `[%wait ~]
92− ::
93− [~ %sign *]
94− `[%done [wire sign-arvo]:u.in.tin]
95− ==
96−::
97−:: Wait for a subscription update on a wire
98−::
99−++ take-fact-prefix
100− |= =wire
101− =/ m (strand ,[path cage])
102− ^- form:m
103− |= tin=strand-input:strand
104− ?+ in.tin `[%skip ~]
105− ~ `[%wait ~]
106− [~ %agent * %fact *]
107− ?. =(watch+wire (scag +((lent wire)) wire.u.in.tin))
108− `[%skip ~]
109− `[%done (slag (lent wire) wire.u.in.tin) cage.sign.u.in.tin]
110− ==
111−::
112−:: Wait for a subscription update on a wire
113−::
114−++ take-fact
115− |= =wire
116− =/ m (strand ,cage)
117− ^- form:m
118− |= tin=strand-input:strand
119− ?+ in.tin `[%skip ~]
120− ~ `[%wait ~]
121− [~ %agent * %fact *]
122− ?. =(watch+wire wire.u.in.tin)
123− `[%skip ~]
124− `[%done cage.sign.u.in.tin]
125− ==
126−::
127−:: Wait for a subscription close
128−::
129−++ take-kick
130− |= =wire
131− =/ m (strand ,~)
132− ^- form:m
133− |= tin=strand-input:strand
134− ?+ in.tin `[%skip ~]
135− ~ `[%wait ~]
136− [~ %agent * %kick *]
137− ?. =(watch+wire wire.u.in.tin)
138− `[%skip ~]
139− `[%done ~]
140− ==
141−::
142−++ echo
143− =/ m (strand ,~)
144− ^- form:m
145− %- (main-loop ,~)
146− :~ |= ~
147− ^- form:m
148− ;< =vase bind:m ((handle ,vase) (take-poke %echo))
149− =/ message=tape !<(tape vase)
150− %- (slog leaf+"{message}..." ~)
151− ;< ~ bind:m (sleep ~s2)
152− %- (slog leaf+"{message}.." ~)
153− (pure:m ~)
154− ::
155− |= ~
156− ^- form:m
157− ;< =vase bind:m ((handle ,vase) (take-poke %over))
158− %- (slog leaf+"over..." ~)
159− (pure:m ~)
160− ==
161−::
162−++ take-watch
163− =/ m (strand ,path)
164− |= tin=strand-input:strand
165− ?+ in.tin `[%skip ~]
166− ~ `[%wait ~]
167− [~ %watch *]
168− `[%done path.u.in.tin]
169− ==
170−::
171−++ take-wake
172− |= until=(unit @da)
173− =/ m (strand ,~)
174− ^- form:m
175− |= tin=strand-input:strand
176− ?+ in.tin `[%skip ~]
177− ~ `[%wait ~]
178− [~ %sign [%wait @ ~] %behn %wake *]
179− ?. |(?=(~ until) =(`u.until (slaw %da i.t.wire.u.in.tin)))
180− `[%skip ~]
181− ?~ error.sign-arvo.u.in.tin
182− `[%done ~]
183− `[%fail %timer-error u.error.sign-arvo.u.in.tin]
184− ==
185−::
186−++ take-tune
187− |= =wire
188− =/ m (strand ,[spar:ames (unit roar:ames)])
189− ^- form:m
190− |= tin=strand-input:strand
191− ?+ in.tin `[%skip ~]
192− ~ `[%wait ~]
193− ::
194− [~ %sign * %ames %tune ^ *]
195− ?. =(wire wire.u.in.tin)
196− `[%skip ~]
197− `[%done +>.sign-arvo.u.in.tin]
198− ==
199−::
200−++ take-poke-ack
201− |= =wire
202− =/ m (strand ,~)
203− ^- form:m
204− |= tin=strand-input:strand
205− ?+ in.tin `[%skip ~]
206− ~ `[%wait ~]
207− [~ %agent * %poke-ack *]
208− ?. =(wire wire.u.in.tin)
209− `[%skip ~]
210− ?~ p.sign.u.in.tin
211− `[%done ~]
212− `[%fail %poke-fail u.p.sign.u.in.tin]
213− ==
214−::
215−++ take-watch-ack
216− |= =wire
217− =/ m (strand ,~)
218− ^- form:m
219− |= tin=strand-input:strand
220− ?+ in.tin `[%skip ~]
221− ~ `[%wait ~]
222− [~ %agent * %watch-ack *]
223− ?. =(watch+wire wire.u.in.tin)
224− `[%skip ~]
225− ?~ p.sign.u.in.tin
226− `[%done ~]
227− `[%fail %watch-ack-fail u.p.sign.u.in.tin]
228− ==
229−::
230−++ poke
231− |= [=dock =cage]
232− =/ m (strand ,~)
233− ^- form:m
234− =/ =card:agent:gall [%pass /poke %agent dock %poke cage]
235− ;< ~ bind:m (send-raw-card card)
236− (take-poke-ack /poke)
237−::
238−++ raw-poke
239− |= [=dock =cage]
240− =/ m (strand ,~)
241− ^- form:m
242− =/ =card:agent:gall [%pass /poke %agent dock %poke cage]
243− ;< ~ bind:m (send-raw-card card)
244− =/ m (strand ,~)
245− ^- form:m
246− |= tin=strand-input:strand
247− ?+ in.tin `[%skip ~]
248− ~
249− `[%wait ~]
250− ::
251− [~ %agent * %poke-ack *]
252− ?. =(/poke wire.u.in.tin)
253− `[%skip ~]
254− `[%done ~]
255− ==
256−::
257−++ raw-poke-our
258− |= [app=term =cage]
259− =/ m (strand ,~)
260− ^- form:m
261− ;< =bowl:spider bind:m get-bowl
262− (raw-poke [our.bowl app] cage)
263−::
264−++ poke-our
265− |= [=term =cage]
266− =/ m (strand ,~)
267− ^- form:m
268− ;< our=@p bind:m get-our
269− (poke [our term] cage)
270−::
271−++ watch
272− |= [=wire =dock =path]
273− =/ m (strand ,~)
274− ^- form:m
275− =/ =card:agent:gall [%pass watch+wire %agent dock %watch path]
276− ;< ~ bind:m (send-raw-card card)
277− (take-watch-ack wire)
278−::
279−++ watch-one
280− |= [=wire =dock =path]
281− =/ m (strand ,cage)
282− ^- form:m
283− ;< ~ bind:m (watch wire dock path)
284− ;< =cage bind:m (take-fact wire)
285− ;< ~ bind:m (take-kick wire)
286− (pure:m cage)
287−::
288−++ watch-our
289− |= [=wire =term =path]
290− =/ m (strand ,~)
291− ^- form:m
292− ;< our=@p bind:m get-our
293− (watch wire [our term] path)
294−::
295−++ scry
296− |* [=mold =path]
297− =/ m (strand ,mold)
298− ^- form:m
299− ?> ?=(^ path)
300− ?> ?=(^ t.path)
301− ;< =bowl:spider bind:m get-bowl
302− %- pure:m
303− .^(mold i.path (scot %p our.bowl) i.t.path (scot %da now.bowl) t.t.path)
304−::
305−++ leave
306− |= [=wire =dock]
307− =/ m (strand ,~)
308− ^- form:m
309− =/ =card:agent:gall [%pass watch+wire %agent dock %leave ~]
310− (send-raw-card card)
311−::
312−++ leave-our
313− |= [=wire =term]
314− =/ m (strand ,~)
315− ^- form:m
316− ;< our=@p bind:m get-our
317− (leave wire [our term])
318−::
319−++ rewatch
320− |= [=wire =dock =path]
321− =/ m (strand ,~)
322− ;< ~ bind:m ((handle ,~) (take-kick wire))
323− ;< ~ bind:m (flog-text "rewatching {<dock>} {<path>}")
324− ;< ~ bind:m (watch wire dock path)
325− (pure:m ~)
326−::
327−++ wait
328− |= until=@da
329− =/ m (strand ,~)
330− ^- form:m
331− ;< ~ bind:m (send-wait until)
332− (take-wake `until)
333−::
334−++ keen
335− |= [=wire =spar:ames]
336− =/ m (strand ,~)
337− ^- form:m
338− (send-raw-card %pass wire %arvo %a %keen spar)
339−::
340−++ sleep
341− |= for=@dr
342− =/ m (strand ,~)
343− ^- form:m
344− ;< now=@da bind:m get-time
345− (wait (add now for))
346−::
347−++ send-wait
348− |= until=@da
349− =/ m (strand ,~)
350− ^- form:m
351− =/ =card:agent:gall
352− [%pass /wait/(scot %da until) %arvo %b %wait until]
353− (send-raw-card card)
354−::
355−++ map-err
356− |* computation-result=mold
357− =/ m (strand ,computation-result)
358− |= [f=$-([term tang] [term tang]) computation=form:m]
359− ^- form:m
360− |= tin=strand-input:strand
361− =* loop $
362− =/ c-res (computation tin)
363− ?: ?=(%cont -.next.c-res)
364− c-res(self.next ..loop(computation self.next.c-res))
365− ?. ?=(%fail -.next.c-res)
366− c-res
367− c-res(err.next (f err.next.c-res))
368−::
369−++ set-timeout
370− |* computation-result=mold
371− =/ m (strand ,computation-result)
372− |= [time=@dr computation=form:m]
373− ^- form:m
374− ;< now=@da bind:m get-time
375− =/ when (add now time)
376− =/ =card:agent:gall
377− [%pass /timeout/(scot %da when) %arvo %b %wait when]
378− ;< ~ bind:m (send-raw-card card)
379− |= tin=strand-input:strand
380− =* loop $
381− ?: ?& ?=([~ %sign [%timeout @ ~] %behn %wake *] in.tin)
382− =((scot %da when) i.t.wire.u.in.tin)
383− ==
384− `[%fail %timeout ~]
385− =/ c-res (computation tin)
386− ?: ?=(%cont -.next.c-res)
387− c-res(self.next ..loop(computation self.next.c-res))
388− ?: ?=(%done -.next.c-res)
389− =/ =card:agent:gall
390− [%pass /timeout/(scot %da when) %arvo %b %rest when]
391− c-res(cards [card cards.c-res])
392− c-res
393−::
394−++ send-request
395− |= =request:http
396− =/ m (strand ,~)
397− ^- form:m
398− (send-raw-card %pass /request %arvo %i %request request *outbound-config:iris)
399−::
400−++ send-cancel-request
401− =/ m (strand ,~)
402− ^- form:m
403− (send-raw-card %pass /request %arvo %i %cancel-request ~)
404−::
405−++ take-client-response
406− =/ m (strand ,client-response:iris)
407− ^- form:m
408− |= tin=strand-input:strand
409− ?+ in.tin `[%skip ~]
410− ~ `[%wait ~]
411− ::
412− [~ %sign [%request ~] %iris %http-response %cancel *]
413− ::NOTE iris does not (yet?) retry after cancel, so it means failure
414− :- ~
415− :+ %fail
416− %http-request-cancelled
417− ['http request was cancelled by the runtime']~
418− ::
419− [~ %sign [%request ~] %iris %http-response %finished *]
420− `[%done client-response.sign-arvo.u.in.tin]
421− ==
422−::
423−:: Wait until we get an HTTP response or cancelation and unset contract
424−::
425−++ take-maybe-sigh
426− =/ m (strand ,(unit httr:eyre))
427− ^- form:m
428− ;< rep=(unit client-response:iris) bind:m
429− take-maybe-response
430− ?~ rep
431− (pure:m ~)
432− :: XX s/b impossible
433− ::
434− ?. ?=(%finished -.u.rep)
435− (pure:m ~)
436− (pure:m (some (to-httr:iris +.u.rep)))
437−::
438−++ take-maybe-response
439− =/ m (strand ,(unit client-response:iris))
440− ^- form:m
441− |= tin=strand-input:strand
442− ?+ in.tin `[%skip ~]
443− ~ `[%wait ~]
444− [~ %sign [%request ~] %iris %http-response %cancel *]
445− `[%done ~]
446− [~ %sign [%request ~] %iris %http-response %finished *]
447− `[%done `client-response.sign-arvo.u.in.tin]
448− ==
449−::
450−++ extract-body
451− |= =client-response:iris
452− =/ m (strand ,cord)
453− ^- form:m
454− ?> ?=(%finished -.client-response)
455− %- pure:m
456− ?~ full-file.client-response ''
457− q.data.u.full-file.client-response
458−::
459−++ fetch-cord
460− |= url=tape
461− =/ m (strand ,cord)
462− ^- form:m
463− =/ =request:http [%'GET' (crip url) ~ ~]
464− ;< ~ bind:m (send-request request)
465− ;< =client-response:iris bind:m take-client-response
466− (extract-body client-response)
467−::
468−++ fetch-json
469− |= url=tape
470− =/ m (strand ,json)
471− ^- form:m
472− ;< =cord bind:m (fetch-cord url)
473− =/ json=(unit json) (de:json:html cord)
474− ?~ json
475− (strand-fail %json-parse-error ~)
476− (pure:m u.json)
477−::
478−++ hiss-request
479− |= =hiss:eyre
480− =/ m (strand ,(unit httr:eyre))
481− ^- form:m
482− ;< ~ bind:m (send-request (hiss-to-request:html hiss))
483− take-maybe-sigh
484−::
485−:: +build-file: build the source file at the specified $beam
486−::
487−++ build-file
488− |= [[=ship =desk =case] =spur]
489− =* arg +<
490− =/ m (strand ,(unit vase))
491− ^- form:m
492− ;< =riot:clay bind:m
493− (warp ship desk ~ %sing %a case spur)
494− ?~ riot
495− (pure:m ~)
496− ?> =(%vase p.r.u.riot)
497− (pure:m (some !<(vase q.r.u.riot)))
498−::
499−++ build-file-hard
500− |= [[=ship =desk =case] =spur]
501− =* arg +<
502− =/ m (strand ,vase)
503− ^- form:m
504− ;< =riot:clay
505− bind:m
506− (warp ship desk ~ %sing %a case spur)
507− ?> ?=(^ riot)
508− ?> ?=(%vase p.r.u.riot)
509− (pure:m !<(vase q.r.u.riot))
510−:: +build-mark: build a mark definition to a $dais
511−::
512−++ build-mark
513− |= [[=ship =desk =case] mak=mark]
514− =* arg +<
515− =/ m (strand ,dais:clay)
516− ^- form:m
517− ;< =riot:clay bind:m
518− (warp ship desk ~ %sing %b case /[mak])
519− ?~ riot
520− (strand-fail %build-mark >arg< ~)
521− ?> =(%dais p.r.u.riot)
522− (pure:m !<(dais:clay q.r.u.riot))
523−:: +build-tube: build a mark conversion gate ($tube)
524−::
525−++ build-tube
526− |= [[=ship =desk =case] =mars:clay]
527− =* arg +<
528− =/ m (strand ,tube:clay)
529− ^- form:m
530− ;< =riot:clay bind:m
531− (warp ship desk ~ %sing %c case /[a.mars]/[b.mars])
532− ?~ riot
533− (strand-fail %build-tube >arg< ~)
534− ?> =(%tube p.r.u.riot)
535− (pure:m !<(tube:clay q.r.u.riot))
536−::
537−:: +build-nave: build a mark definition to a $nave
538−::
539−++ build-nave
540− |= [[=ship =desk =case] mak=mark]
541− =* arg +<
542− =/ m (strand ,vase)
543− ^- form:m
544− ;< =riot:clay bind:m
545− (warp ship desk ~ %sing %e case /[mak])
546− ?~ riot
547− (strand-fail %build-nave >arg< ~)
548− ?> =(%nave p.r.u.riot)
549− (pure:m q.r.u.riot)
550−:: +build-cast: build a mark conversion gate (static)
551−::
552−++ build-cast
553− |= [[=ship =desk =case] =mars:clay]
554− =* arg +<
555− =/ m (strand ,vase)
556− ^- form:m
557− ;< =riot:clay bind:m
558− (warp ship desk ~ %sing %f case /[a.mars]/[b.mars])
559− ?~ riot
560− (strand-fail %build-cast >arg< ~)
561− ?> =(%cast p.r.u.riot)
562− (pure:m q.r.u.riot)
563−::
564−:: Read from Clay
565−::
566−++ warp
567− |= [=ship =riff:clay]
568− =/ m (strand ,riot:clay)
569− ;< ~ bind:m (send-raw-card %pass /warp %arvo %c %warp ship riff)
570− (take-writ /warp)
571−::
572−++ read-file
573− |= [[=ship =desk =case] =spur]
574− =* arg +<
575− =/ m (strand ,cage)
576− ;< =riot:clay bind:m (warp ship desk ~ %sing %x case spur)
577− ?~ riot
578− (strand-fail %read-file >arg< ~)
579− (pure:m r.u.riot)
580−::
581−++ check-for-file
582− |= [[=ship =desk =case] =spur]
583− =/ m (strand ,?)
584− ;< =riot:clay bind:m (warp ship desk ~ %sing %u case spur)
585− ?> ?=(^ riot)
586− (pure:m !<(? q.r.u.riot))
587−::
588−++ list-tree
589− |= [[=ship =desk =case] =spur]
590− =* arg +<
591− =/ m (strand ,(list path))
592− ;< =riot:clay bind:m (warp ship desk ~ %sing %t case spur)
593− ?~ riot
594− (strand-fail %list-tree >arg< ~)
595− (pure:m !<((list path) q.r.u.riot))
596−::
597−:: Take Clay read result
598−::
599−++ take-writ
600− |= =wire
601− =/ m (strand ,riot:clay)
602− ^- form:m
603− |= tin=strand-input:strand
604− ?+ in.tin `[%skip ~]
605− ~ `[%wait ~]
606− [~ %sign * ?(%behn %clay) %writ *]
607− ?. =(wire wire.u.in.tin)
608− `[%skip ~]
609− `[%done +>.sign-arvo.u.in.tin]
610− ==
611−:: +check-online: require that peer respond before timeout
612−::
613−++ check-online
614− |= [who=ship lag=@dr]
615− =/ m (strand ,~)
616− ^- form:m
617− %+ (map-err ,~) |=(* [%offline *tang])
618− %+ (set-timeout ,~) lag
619− ;< ~ bind:m
620− (poke [who %hood] %helm-hi !>(~))
621− (pure:m ~)
622−::
623−++ eval-hoon
624− |= [gen=hoon bez=(list beam)]
625− =/ m (strand ,vase)
626− ^- form:m
627− =/ sut=vase !>(..zuse)
628− |-
629− ?~ bez
630− (pure:m (slap sut gen))
631− ;< vax=vase bind:m (build-file-hard i.bez)
632− $(bez t.bez, sut (slop vax sut))
633−::
634−++ send-thread
635− |= [=bear:khan =shed:khan =wire]
636− =/ m (strand ,~)
637− ^- form:m
638− (send-raw-card %pass wire %arvo %k %lard bear shed)
639−::
640−:: Queue on skip, try next on fail %ignore
641−::
642−++ main-loop
643− |* a=mold
644− =/ m (strand ,~)
645− =/ m-a (strand ,a)
646− =| queue=(qeu (unit input:strand))
647− =| active=(unit [in=(unit input:strand) =form:m-a forms=(list $-(a form:m-a))])
648− =| state=a
649− |= forms=(lest $-(a form:m-a))
650− ^- form:m
651− |= tin=strand-input:strand
652− =* top `form:m`..$
653− =. queue (~(put to queue) in.tin)
654− |^ (continue bowl.tin)
655− ::
656− ++ continue
657− |= =bowl:strand
658− ^- output:m
659− ?> =(~ active)
660− ?: =(~ queue)
661− `[%cont top]
662− =^ in=(unit input:strand) queue ~(get to queue)
663− ^- output:m
664− =. active `[in (i.forms state) t.forms]
665− ^- output:m
666− (run bowl in)
667− ::
668− ++ run
669− ^- form:m
670− |= tin=strand-input:strand
671− ^- output:m
672− ?> ?=(^ active)
673− =/ res (form.u.active tin)
674− =/ =output:m
675− ?- -.next.res
676− %wait `[%wait ~]
677− %skip `[%cont ..$(queue (~(put to queue) in.tin))]
678− %cont `[%cont ..$(active `[in.u.active self.next.res forms.u.active])]
679− %done (continue(active ~, state value.next.res) bowl.tin)
680− %fail
681− ?: &(?=(^ forms.u.active) ?=(%ignore p.err.next.res))
682− %= $
683− active `[in.u.active (i.forms.u.active state) t.forms.u.active]
684− in.tin in.u.active
685− ==
686− `[%fail err.next.res]
687− ==
688− [(weld cards.res cards.output) next.output]
689− --
690−::
691−++ retry
692− |* result=mold
693− |= [crash-after=(unit @ud) computation=_*form:(strand (unit result))]
694− =/ m (strand ,result)
695− =| try=@ud
696− |- ^- form:m
697− =* loop $
698− ?: =(crash-after `try)
699− (strand-fail %retry-too-many ~)
700− ;< ~ bind:m (backoff try ~m1)
701− ;< res=(unit result) bind:m computation
702− ?^ res
703− (pure:m u.res)
704− loop(try +(try))
705−::
706−++ backoff
707− |= [try=@ud limit=@dr]
708− =/ m (strand ,~)
709− ^- form:m
710− ;< eny=@uvJ bind:m get-entropy
711− %- sleep
712− %+ min limit
713− ?: =(0 try) ~s0
714− %+ add
715− (mul ~s1 (bex (dec try)))
716− (mul ~s0..0001 (~(rad og eny) 1.000))
717−::
718−:: ----
719−::
720−:: Output
721−::
722−++ flog
723− |= =flog:dill
724− =/ m (strand ,~)
725− ^- form:m
726− (send-raw-card %pass / %arvo %d %flog flog)
727−::
728−++ flog-text
729− |= =tape
730− =/ m (strand ,~)
731− ^- form:m
732− (flog %text tape)
733−::
734−++ flog-tang
735− |= =tang
736− =/ m (strand ,~)
737− ^- form:m
738− =/ =wall
739− (zing (turn (flop tang) (cury wash [0 80])))
740− |- ^- form:m
741− =* loop $
742− ?~ wall
743− (pure:m ~)
744− ;< ~ bind:m (flog-text i.wall)
745− loop(wall t.wall)
746−::
747−++ trace
748− |= =tang
749− =/ m (strand ,~)
750− ^- form:m
751− (pure:m ((slog tang) ~))
752−::
753−++ app-message
754− |= [app=term =cord =tang]
755− =/ m (strand ,~)
756− ^- form:m
757− =/ msg=tape :(weld (trip app) ": " (trip cord))
758− ;< ~ bind:m (flog-text msg)
759− (flog-tang tang)
760−::
761−:: ----
762−::
763−:: Handle domains
764−::
765−++ install-domain
766− |= =turf
767− =/ m (strand ,~)
768− ^- form:m
769− (send-raw-card %pass / %arvo %e %rule %turf %put turf)
770−::
771−:: ----
772−::
773−:: Threads
774−::
775−++ start-thread
776− |= file=term
777− =/ m (strand ,tid:spider)
778− ;< =bowl:spider bind:m get-bowl
779− (start-thread-with-args byk.bowl file *vase)
780−::
781−++ start-thread-with-args
782− |= [=beak file=term args=vase]
783− =/ m (strand ,tid:spider)
784− ^- form:m
785− ;< =bowl:spider bind:m get-bowl
786− =/ tid
787− (scot %ta (cat 3 (cat 3 'strand_' file) (scot %uv (sham file eny.bowl))))
788− =/ poke-vase !>(`start-args:spider`[`tid.bowl `tid beak file args])
789− ;< ~ bind:m (poke-our %spider %spider-start poke-vase)
790− ;< ~ bind:m (sleep ~s0) :: wait for thread to start
791− (pure:m tid)
792−::
793−+$ thread-result
794− (each vase [term tang])
795−::
796−++ await-thread
797− |= [file=term args=vase]
798− =/ m (strand ,thread-result)
799− ^- form:m
800− ;< =bowl:spider bind:m get-bowl
801− =/ tid (scot %ta (cat 3 'strand_' (scot %uv (sham file eny.bowl))))
802− =/ poke-vase !>(`start-args:spider`[`tid.bowl `tid byk.bowl file args])
803− ;< ~ bind:m (watch-our /awaiting/[tid] %spider /thread-result/[tid])
804− ;< ~ bind:m (poke-our %spider %spider-start poke-vase)
805− ;< ~ bind:m (sleep ~s0) :: wait for thread to start
806− ;< =cage bind:m (take-fact /awaiting/[tid])
807− ;< ~ bind:m (take-kick /awaiting/[tid])
808− ?+ p.cage ~|([%strange-thread-result p.cage file tid] !!)
809− %thread-done (pure:m %& q.cage)
810− %thread-fail (pure:m %| ;;([term tang] q.q.cage))
811− ==
812−--
zod/seax/mar/css.hoonnew file+25
@@ -0,0 +1,25 @@
1+::
2+:::: /hoon/css/mar
3+ ::
4+/? 310
5+=, eyre
6+=, mimes:html
7+|_ mud=@t
8+++ grow :: convert to
9+ |%
10+ ++ mime [/text/css (as-octs mud)] :: convert to %mime
11+ ++ hymn :: convert to %hymn
12+ |^ html
13+ ++ style ;style
14+ ;- (trip mud)
15+ ==
16+ ++ html ;html:(head:"{style}" body)
17+ --
18+ --
19+++ grab
20+ |% :: convert from
21+ ++ mime |=([p=mite q=octs] (@t q.q))
22+ ++ noun @t :: clam from %noun
23+ --
24+++ grad %mime
25+--
zod/seax/mar/docket-0.hoonnew file+25
@@ -0,0 +1,25 @@
1+/+ dock=docket
2+|_ =docket:dock
3+++ grow
4+ |%
5+ ++ mime
6+ ^- ^mime
7+ [/text/x-docket (as-octt:mimes:html (spit-docket:mime:dock docket))]
8+ ++ noun docket
9+ ++ json (docket:enjs:dock docket)
10+ --
11+++ grab
12+ |%
13+ ::
14+ ++ mime
15+ |= [=mite len=@ud tex=@]
16+ ^- docket:dock
17+ %- need
18+ %- from-clauses:mime:dock
19+ !<((list clause:dock) (slap !>(~) (ream tex)))
20+
21+ ::
22+ ++ noun docket:dock
23+ --
24+++ grad %noun
25+--
zod/seax/mar/hoon.hoon+285−31
@@ -1,41 +1,295 @@
1−:::: /hoon/hoon/mar
2− ::
3−/? 310
4−::
5−=, eyre
61|_ own=@t
72::
83++ grow :: convert to
94 |%
105 ++ mime `^mime`[/text/x-hoon (as-octs:mimes:html own)] :: convert to %mime
11− ++ elem :: convert to %html
12− ;div:pre(urb_codemirror "", mode "hoon"):"{(trip own)}"
13− :: =+ gen-id="src-{<`@ui`(mug own)>}"
14− :: ;div
15− :: ;textarea(id "{gen-id}"):"{(trip own)}"
16− :: ;script:"""
17− :: CodeMirror.fromTextArea(
18− :: window[{<gen-id>}],
19− :: \{lineNumbers:true, readOnly:true}
20− :: )
21− :: """
22− :: ==
236 ++ hymn
24− :: ;html:(head:title:"Source" "+{elem}")
25− ;html
26− ;head
27− ;title:"Source"
28− ;script@"//cdnjs.cloudflare.com/ajax/libs/codemirror/4.3.0/codemirror.js";
29− ;script@"/lib/syntax/hoon.js";
30− ;link(rel "stylesheet", href "//cdnjs.cloudflare.com/ajax/libs/".
31− "codemirror/4.3.0/codemirror.min.css");
32− ;link/"/lib/syntax/codemirror.css"(rel "stylesheet");
33− ==
34− ;body
35− ;textarea#src:"{(trip own)}"
36− ;script:'CodeMirror.fromTextArea(src, {lineNumbers:true, readOnly:true})'
7+ ^- manx
8+ =/ to-wall
9+ |= =tape
10+ ^- wall
11+ %+ roll (flop tape)
12+ |= [char=@tD =wall]
13+ ?~ wall
14+ [[char ~] ~]
15+ ?: =('\0a' char)
16+ [~ wall]
17+ [[char i.wall] t.wall]
18+ ::
19+ =/ src=tape (trip own)
20+ =/ count=@ud (lent (to-wall src))
21+ =; [style=tape script=tape]
22+ ;html
23+ ;head
24+ ;title: source
25+ ;meta(charset "utf-8");
26+ ;meta(name "viewport", content "width=device-width, initial-scale=1");
27+ ;style: {style}
28+ ==
29+ ;body
30+ ;div.viewer
31+ :: ;div.viewer-bar
32+ :: ;span.viewer-name: {(scow %ud count)} lines
33+ :: ;button.copy-link(id "copy-link", hidden ""): copy link
34+ :: ==
35+ ;div.code
36+ ;pre.gutter(id "gutter");
37+ ;div.code-body
38+ ;div(id "hl");
39+ ;pre.code-pre(id "code"): {src}
40+ ==
41+ ==
42+ ==
43+ ;script: {script}
44+ ==
3745 ==
38− ==
46+ ::
47+ :-
48+ ^~ ^= style
49+ ^- tape
50+ %- trip
51+ '''
52+ :root {
53+ --bg: #fbfbf9;
54+ --panel: #ffffff;
55+ --gutter-bg: #f3f3ef;
56+ --line: #e4e4dd;
57+ --fg: #2b2b2b;
58+ --fg-dim: #9a9a90;
59+ --sel: #fff7d6;
60+ --sel-edge: #f1e4a8;
61+ --accent: #4a6da7;
62+ --lh: 20px;
63+ --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
64+ "Liberation Mono", "Courier New", monospace;
65+ }
66+ * { box-sizing: border-box; }
67+ html, body {
68+ margin: 0;
69+ height: 100%;
70+ background: var(--bg);
71+ color: var(--fg);
72+ font-family: var(--mono);
73+ -webkit-font-smoothing: antialiased;
74+ }
75+ .viewer {
76+ height: 100vh;
77+ display: flex;
78+ flex-direction: column;
79+ padding: 16px;
80+ gap: 12px;
81+ }
82+ .viewer-bar {
83+ flex: 0 0 auto;
84+ display: flex;
85+ align-items: center;
86+ gap: 12px;
87+ font-size: 13px;
88+ color: var(--fg-dim);
89+ }
90+ .viewer-name {
91+ flex: 1 1 auto;
92+ min-width: 0;
93+ overflow: hidden;
94+ text-overflow: ellipsis;
95+ white-space: nowrap;
96+ color: var(--fg);
97+ }
98+ .copy-link {
99+ flex: 0 0 auto;
100+ padding: 4px 12px;
101+ border: 1px solid var(--line);
102+ border-radius: 6px;
103+ background: var(--panel);
104+ color: var(--fg-dim);
105+ font: inherit;
106+ font-size: 12px;
107+ cursor: pointer;
108+ transition: color .12s, border-color .12s;
109+ }
110+ .copy-link:hover { color: var(--accent); border-color: var(--accent); }
111+ .copy-link[hidden] { display: none; }
112+ .code {
113+ flex: 1 1 auto;
114+ min-height: 0;
115+ display: flex;
116+ align-items: flex-start;
117+ overflow: auto;
118+ background: var(--panel);
119+ border: 1px solid var(--line);
120+ border-radius: 8px;
121+ }
122+ .code-body {
123+ position: relative;
124+ flex: 1 1 auto;
125+ min-width: 0;
126+ width: max-content;
127+ }
128+ #gutter, #code {
129+ margin: 0;
130+ padding: 14px 0;
131+ font-family: var(--mono);
132+ font-size: 13px;
133+ line-height: var(--lh);
134+ white-space: pre;
135+ tab-size: 2;
136+ }
137+ #gutter {
138+ position: sticky;
139+ left: 0;
140+ z-index: 2;
141+ flex: 0 0 auto;
142+ padding-left: 16px;
143+ padding-right: 12px;
144+ text-align: right;
145+ color: var(--fg-dim);
146+ background: var(--gutter-bg);
147+ border-right: 1px solid var(--line);
148+ user-select: none;
149+ -webkit-user-select: none;
150+ cursor: pointer;
151+ }
152+ #code {
153+ display: block;
154+ padding-left: 14px;
155+ padding-right: 18px;
156+ color: var(--fg);
157+ }
158+ #hl {
159+ position: absolute;
160+ left: 0;
161+ right: 0;
162+ z-index: 0; /* under the text */
163+ display: none;
164+ background: var(--sel);
165+ box-shadow: inset 2px 0 0 var(--sel-edge);
166+ pointer-events: none;
167+ }
168+ #code { position: relative; z-index: 1; } /* text above the bar */
169+ :focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
170+ '''
171+ ^~ ^= code
172+ ^- tape
173+ %- trip
174+ '''
175+ (function () {
176+ "use strict";
177+ const panel = document.querySelector(".code"); // the scroll container
178+ const code = document.getElementById("code");
179+ const gutter = document.getElementById("gutter");
180+ const hl = document.getElementById("hl");
181+ if (!panel || !code || !gutter || !hl) return;
182+ const text = code.textContent;
183+ let lineCount = text.length ? text.split("\n").length : 1;
184+ if (text.endsWith("\n")) lineCount -= 1;
185+ if (lineCount < 1) lineCount = 1;
186+ (function fillGutter() {
187+ let s = "";
188+ for (let i = 1; i <= lineCount; i++) s += i + "\n";
189+ gutter.textContent = s;
190+ })();
191+ let lineH = 0;
192+ let codeTop = 0; // code's content-box top padding, the y-origin of line 1
193+ function measure() {
194+ const cs = getComputedStyle(code);
195+ const lh = parseFloat(cs.lineHeight);
196+ lineH = isNaN(lh) ? parseFloat(cs.fontSize) * 1.55 : lh;
197+ codeTop = parseFloat(cs.paddingTop) || 0;
198+ positionHighlight(); // keep the bar correct after a re-measure
199+ }
200+ let anchor = null;
201+ let selLo = 0;
202+ let selHi = 0;
203+ function positionHighlight() {
204+ if (!selLo) { hl.style.display = "none"; return; }
205+ hl.style.display = "block";
206+ hl.style.top = (codeTop + (selLo - 1) * lineH) + "px";
207+ hl.style.height = ((selHi - selLo + 1) * lineH) + "px";
208+ }
209+ function applySel(lo, hi) {
210+ selLo = lo;
211+ selHi = hi;
212+ positionHighlight();
213+ }
214+ function deselect() {
215+ selLo = selHi = 0;
216+ anchor = null;
217+ positionHighlight();
218+ history.replaceState(null, "", location.pathname + location.search);
219+ }
220+ function parseHash(hash) {
221+ const m = /^#L(\d+)(?:-L(\d+))?$/.exec(hash || "");
222+ if (!m) return null;
223+ let lo = parseInt(m[1], 10);
224+ let hi = m[2] ? parseInt(m[2], 10) : lo;
225+ if (hi < lo) { const t = lo; lo = hi; hi = t; }
226+ lo = Math.max(1, Math.min(lo, lineCount));
227+ hi = Math.max(1, Math.min(hi, lineCount));
228+ return [lo, hi];
229+ }
230+ function setHash(lo, hi) {
231+ const frag = lo === hi ? "L" + lo : "L" + lo + "-L" + hi;
232+ history.replaceState(null, "", "#" + frag);
233+ }
234+ function scrollToLine(n) {
235+ const y = codeTop + (n - 1) * lineH;
236+ if (y < panel.scrollTop || y > panel.scrollTop + panel.clientHeight) {
237+ panel.scrollTop = Math.max(0, y - panel.clientHeight / 2);
238+ }
239+ }
240+ function selectFromHash(scroll) {
241+ const r = parseHash(location.hash);
242+ if (!r) return false;
243+ anchor = r[0];
244+ applySel(r[0], r[1]);
245+ if (scroll) scrollToLine(r[0]);
246+ return true;
247+ }
248+ function lineFromEvent(e) {
249+ // y within the code content: pointer relative to the code pre's rendered
250+ // top, which already accounts for scroll since getBoundingClientRect is
251+ // viewport-relative and the pre moves as the panel scrolls.
252+ const rect = code.getBoundingClientRect();
253+ const y = e.clientY - rect.top - codeTop;
254+ let n = Math.floor(y / lineH) + 1;
255+ if (n < 1) n = 1;
256+ if (n > lineCount) n = lineCount;
257+ return n;
258+ }
259+ function onClick(e) {
260+ const inGutter = e.target === gutter;
261+ if (!inGutter && !e.shiftKey) return; // normal text interaction in code
262+ const n = lineFromEvent(e);
263+ if (!e.shiftKey && selLo === n && selHi === n) {
264+ deselect();
265+ return;
266+ }
267+ if (e.shiftKey && anchor !== null) {
268+ applySel(Math.min(anchor, n), Math.max(anchor, n));
269+ setHash(selLo, selHi);
270+ } else {
271+ anchor = n;
272+ applySel(n, n);
273+ setHash(n, n);
274+ }
275+ }
276+ gutter.addEventListener("click", onClick);
277+ code.addEventListener("click", onClick);
278+ document.addEventListener("keydown", function (e) {
279+ if (e.key === "Escape") deselect();
280+ });
281+ window.addEventListener("hashchange", function () {
282+ if (!selectFromHash(true)) deselect();
283+ });
284+ let rz = null;
285+ window.addEventListener("resize", function () {
286+ clearTimeout(rz);
287+ rz = setTimeout(measure, 100);
288+ });
289+ measure();
290+ selectFromHash(true);
291+ })();
292+ '''
39293 ++ txt
40294 (to-wain:format own)
41295 --
zod/seax/mar/html.hoonnew file+22
@@ -0,0 +1,22 @@
1+::
2+:::: /hoon/html/mar
3+ ::
4+/? 310
5+ ::
6+:::: compute
7+ ::
8+=, html
9+|_ htm=@t
10+++ grow :: convert to
11+ ^?
12+ |% ::
13+ ++ mime [/text/html (met 3 htm) htm] :: to %mime
14+ ++ hymn (need (de-xml htm)) :: to %hymn
15+ -- ::
16+++ grab ^?
17+ |% :: convert from
18+ ++ noun @t :: clam from %noun
19+ ++ mime |=([p=mite q=octs] q.q) :: retrieve form %mime
20+ --
21+++ grad %mime
22+--
zod/seax/mar/js.hoonnew file+25
@@ -0,0 +1,25 @@
1+::
2+:::: /hoon/js/mar
3+ ::
4+/? 310
5+::
6+=, eyre
7+|_ mud=@
8+++ grow
9+ |%
10+ ++ mime [/application/javascript (as-octs:mimes:html (@t mud))]
11+ ++ hymn :: convert to %hymn
12+ |^ html
13+ ++ script ;script
14+ ;- (trip (@t mud))
15+ ==
16+ ++ html ;html:(head:"{script}" body)
17+ --
18+ --
19+++ grab
20+ |% :: convert from
21+ ++ mime |=([p=mite q=octs] (@t q.q))
22+ ++ noun cord :: clam from %noun
23+ --
24+++ grad %mime
25+--
zod/seax/mar/png.hoonnew file+12
@@ -0,0 +1,12 @@
1+|_ dat=@
2+++ grow
3+ |%
4+ ++ mime [/image/png (as-octs:mimes:html dat)]
5+ --
6+++ grab
7+ |%
8+ ++ mime |=([p=mite q=octs] q.q)
9+ ++ noun @
10+ --
11+++ grad %mime
12+--
zod/seax/mar/txt-diff.hoonnew file+16
@@ -0,0 +1,16 @@
1+::
2+:::: /hoon/txt-diff/mar
3+ ::
4+/? 310
5+|_ txt-diff=(urge:clay cord)
6+::
7+++ grad %noun
8+++ grow
9+ |%
10+ ++ noun txt-diff
11+ --
12+++ grab :: convert from
13+ |%
14+ ++ noun (urge:clay cord) :: make from %noun
15+ --
16+--
zod/seax/mar/txt.hoon−1
@@ -18,7 +18,6 @@
1818 => v=.
1919 |%
2020 ++ mime => v [/text/plain (as-octs (of-wain txt))]
21− ++ elem => v ;pre: {(trip (of-wain txt))}
2221 --
2322++ grad
2423 |%
zod/seax/mar/woff2.hoonnew file+12
@@ -0,0 +1,12 @@
1+|_ dat=octs
2+++ grow
3+ |%
4+ ++ mime [/font/woff2 dat]
5+ --
6+++ grab
7+ |%
8+ ++ mime |=([=mite =octs] octs)
9+ ++ noun octs
10+ --
11+++ grad %mime
12+--
zod/seax/sur/cite.hoondeleted−57
@@ -1,57 +0,0 @@
1−/- g=groups
2−=< cite
3−|%
4−++ purse
5− |= =(pole knot)
6− ^- (unit cite)
7− ?. =(~.1 -.pole) ~
8− =. pole +.pole
9− ?+ pole ~
10− [%chan agent=@ ship=@ name=@ rest=*]
11− =/ ship (slaw %p ship.pole)
12− ?~ ship ~
13− `[%chan [agent.pole u.ship name.pole] rest.pole]
14− ::
15− [%desk ship=@ name=@ rest=*]
16− =/ ship (slaw %p ship.pole)
17− ?~ ship ~
18− `[%desk [u.ship name.pole] rest.pole]
19− ::
20− [%group ship=@ name=@ ~]
21− =/ ship (slaw %p ship.pole)
22− ?~ ship ~
23− `[%group u.ship name.pole]
24− ==
25−++ parse
26− |= =path
27− ^- cite
28− (need (purse path))
29−::
30−++ print
31− |= c=cite
32− |^ ^- path
33− :- (scot %ud 1)
34− ?- -.c
35− %chan chan/(welp (nest nest.c) wer.c)
36− %desk desk/(welp (flag flag.c) wer.c)
37− %group group/(flag flag.c)
38− %bait bait/:(welp (flag grp.c) (flag gra.c) wer.c)
39− ==
40− ++ flag
41− |= f=flag:g
42− ~[(scot %p p.f) q.f]
43− ++ nest
44− |= n=nest:g
45− [p.n (flag q.n)]
46− --
47−::
48−+$ cite
49− $% [%chan =nest:g wer=path]
50− [%group =flag:g]
51− [%desk =flag:g wer=path]
52− [%bait grp=flag:g gra=flag:g wer=path]
53− :: scry into groups when you receive a bait for a chat that doesn't exist yet
54− :: work out what app
55− ==
56−--
57−
zod/seax/sur/diary-0.hoondeleted−323
@@ -1,323 +0,0 @@
1−/- g=groups, c=cite, graph-store, e=epic
2−/- metadata-store
3−/+ lib-graph=graph-store
4−|%
5−++ okay `epic:e`0
6−++ mar
7− |%
8− ++ act `mark`(rap 3 %diary-action '-' (scot %ud okay) ~)
9− ++ upd `mark`(rap 3 %diary-update '-' (scot %ud okay) ~)
10− ++ log `mark`(rap 3 %diary-logs '-' (scot %ud okay) ~)
11− --
12−:: $flag: identifier for a diary channel
13−+$ flag (pair ship term)
14−:: $feel: either an emoji identifier like :diff or a URL for custom
15−+$ feel @ta
16−:: $view: the persisted display format for a diary
17−+$ view ?(%grid %list)
18−:: $sort: the persisted sort type for a diary
19−+$ sort ?(%alpha %time %arranged)
20−:: $shelf: my ship's diaries
21−+$ shelf (map flag diary)
22−:: $said: used for references
23−+$ said (pair flag outline)
24−:: $plan: index into diary state
25−:: p: Note being referred to
26−:: q: Quip being referred to, if any
27−::
28−+$ plan
29− (pair time (unit time))
30−::
31−:: $diary: written longform communication
32−::
33−:: net: an indicator of whether I'm a host or subscriber
34−:: log: the history of all modifications
35−:: perm: holds the diary's permissions
36−:: view: what format to display
37−:: sort: how to order posts
38−:: notes: the actual contents of the diary
39−:: remark: what is the last thing we've read
40−:: banter: comments organized by post
41−::
42−+$ diary
43− $: =net
44− =log
45− =perm
46− =view
47− =sort
48− =notes
49− =remark
50− ==
51−::
52−:: $notes: a set of time ordered diary posts
53−::
54−++ notes
55− =< rock
56− |%
57− +$ rock
58− ((mop time note) lte)
59− ++ on
60− ((^on time note) lte)
61− +$ diff
62− (pair time delta)
63− +$ delta
64− $% [%add p=essay]
65− [%edit p=essay]
66− [%del ~]
67− [%quips p=diff:quips]
68− [%add-feel p=ship q=feel]
69− [%del-feel p=ship]
70− ==
71− --
72−::
73−:: $quips: a set of time ordered note comments
74−::
75−++ quips
76− =< rock
77− |%
78− +$ rock
79− ((mop time quip) lte)
80− ++ on
81− ((^on time quip) lte)
82− +$ diff
83− (pair time delta)
84− +$ delta
85− $% [%add p=memo]
86− [%del ~]
87− [%add-feel p=ship q=feel]
88− [%del-feel p=ship]
89− ==
90− --
91−::
92−:: $outline: abridged $note
93−:: .quips: number of comments
94−::
95−+$ outline
96− [quips=@ud quippers=(set ship) essay]
97−::
98−++ outlines
99− =< outlines
100− |%
101− +$ outlines ((mop time outline) lte)
102− ++ on ((^on time outline) lte)
103− --
104−::
105−:: $note: a diary post
106−::
107−+$ note [seal essay]
108−:: $quip: a post comment
109−::
110−+$ quip [cork memo]
111−::
112−:: $seal: host-side data for a note
113−::
114−+$ seal
115− $: =time
116− =quips
117− feels=(map ship feel)
118− ==
119−::
120−:: $cork: host-side data for a quip
121−::
122−+$ cork
123− $: =time
124− feels=(map ship feel)
125− ==
126−:: $essay: the post data itself
127−::
128−:: title: the name of the post
129−:: image: a visual displayed as a header
130−:: content: the body of the post
131−:: author: the ship that wrote the post
132−:: sent: the client-side time the post was made
133−::
134−+$ essay
135− $: title=@t
136− image=@t
137− content=(list verse)
138− author=ship
139− sent=time
140− ==
141−+$ story (pair (list block) (list inline))
142−:: $memo: the comment data itself
143−::
144−:: content: the body of the comment
145−:: author: the ship that wrote the comment
146−:: sent: the client-side time the comment was made
147−::
148−+$ memo
149− $: content=story
150− author=ship
151− sent=time
152− ==
153−:: $verse: a chunk of post content
154−::
155−:: blocks stand on their own. inlines come in groups and get wrapped
156−:: into a paragraph
157−::
158−+$ verse
159− $% [%block p=block]
160− [%inline p=(list inline)]
161− ==
162−:: $listing: recursive type for infinitely nested <ul> or <ol>
163−+$ listing
164− $% [%list p=?(%ordered %unordered) q=(list listing) r=(list inline)]
165− [%item p=(list inline)]
166− ==
167−:: $block: post content that sits outside of the normal text
168−::
169−:: %image: a visual, we record dimensions for better rendering
170−:: %cite: an Urbit reference
171−:: %header: a traditional HTML heading, h1-h6
172−:: %listing: a traditional HTML list, ul and ol
173−:: %code: a block of code
174−::
175−+$ block
176− $% [%image src=cord height=@ud width=@ud alt=cord]
177− [%cite =cite:c]
178− [%header p=?(%h1 %h2 %h3 %h4 %h5 %h6) q=(list inline)]
179− [%listing p=listing]
180− [%rule ~]
181− [%code code=cord lang=cord]
182− ==
183−:: $inline: post content that flows within a paragraph
184−::
185−:: @t: plain text
186−:: %italics: italic text
187−:: %bold: bold text
188−:: %strike: strikethrough text
189−:: %inline-code: code formatting for small snippets
190−:: %blockquote: blockquote surrounded content
191−:: %block: link/reference to blocks
192−:: %code: code formatting for large snippets
193−:: %tag: tag gets special signifier
194−:: %link: link to a URL with a face
195−:: %break: line break
196−::
197−+$ inline
198− $@ @t
199− $% [%italics p=(list inline)]
200− [%bold p=(list inline)]
201− [%strike p=(list inline)]
202− [%blockquote p=(list inline)]
203− [%inline-code p=cord]
204− [%ship p=ship]
205− [%block p=@ud q=cord]
206− [%code p=cord]
207− [%tag p=cord]
208− [%link p=cord q=cord]
209− [%break ~]
210− ==
211−:: $log: a time ordered history of modifications to a diary
212−::
213−+$ log
214− ((mop time diff) lte)
215−++ log-on
216− ((on time diff) lte)
217−::
218−:: $action: the complete set of data required to modify a diary
219−::
220−+$ action
221− (pair flag:g update)
222−::
223−:: $update: a representation in time of a modification to a diary
224−::
225−+$ update
226− (pair time diff)
227−::
228−:: $diff: the full suite of modifications that can be made to a diary
229−::
230−+$ diff
231− $% [%notes p=diff:notes]
232− ::
233− [%add-sects p=(set sect:g)]
234− [%del-sects p=(set sect:g)]
235− ::
236− [%create p=perm q=notes]
237− [%view p=view]
238− [%sort p=sort]
239− ::
240− ==
241−::
242−:: $net: an indicator of whether I'm a host or subscriber
243−::
244−:: %pub: am publisher/host with fresh log
245−:: %sub: subscribed to the ship at saga
246−::
247−+$ net
248− $% [%sub p=ship load=_| =saga:e]
249− [%pub ~] :: TODO: permissions?
250− ==
251−::
252−:: $briefs: a map of diary unread information
253−::
254−:: brief: the last time a diary was read, how many posts since,
255−:: and the id of the last read note
256−::
257−++ briefs
258− =< briefs
259− |%
260− +$ briefs
261− (map flag brief)
262− +$ brief
263− [last=time count=@ud read-id=(unit time)]
264− +$ update
265− (pair flag brief)
266− --
267−:: $remark: a marker representing the last note I've read
268−::
269−+$ remark
270− [last-read=time watching=_| ~]
271−::
272−+$ remark-action
273− (pair flag remark-diff)
274−::
275−+$ remark-diff
276− $% [%read ~]
277− [%read-at p=time]
278− [?(%watch %unwatch) ~]
279− ==
280−::
281−:: $perm: represents the permissions for a diary channel and gives a
282−:: pointer back to the group it belongs to.
283−::
284−+$ perm
285− $: writers=(set sect:g)
286− group=flag:g
287− ==
288−:: $join: a group + channel flag to join a channel, group required for perms
289−::
290−+$ join
291− $: group=flag:g
292− chan=flag:g
293− ==
294−:: $leave: a flag to pass for a channel leave
295−::
296−+$ leave flag:g
297−::
298−:: $create: represents a request to create a channel
299−::
300−:: The name will be used as part of the flag which represents the
301−:: channel. $create is consumed by the diary agent first and then
302−:: passed to the groups agent to register the channel with the group.
303−::
304−:: Write permission is stored with the specific agent in the channel,
305−:: read permission is stored with the group's data.
306−::
307−+$ create
308− $: group=flag:g
309− name=term
310− title=cord
311− description=cord
312− readers=(set sect:g)
313− writers=(set sect:g)
314− ==
315−+$ import [writers=(set ship) =association:met =update-log:gra =graph:gra]
316−::
317−+$ imports (map flag import)
318−::
319−++ gra graph-store
320−++ orm-gra orm:lib-graph
321−++ orm-log-gra orm-log:lib-graph
322−++ met metadata-store
323−--
zod/seax/sur/diary.hoondeleted−335
@@ -1,335 +0,0 @@
1−/- g=groups, c=cite, graph-store, e=epic
2−/- zer=diary-0
3−/- metadata-store
4−/+ lib-graph=graph-store
5−|%
6−++ old
7− |%
8− ++ zero zer
9− --
10−::
11−++ okay `epic:e`2
12−++ mar
13− |%
14− ++ act `mark`(rap 3 %diary-action '-' (scot %ud okay) ~)
15− ++ upd `mark`(rap 3 %diary-update '-' (scot %ud okay) ~)
16− ++ log `mark`(rap 3 %diary-logs '-' (scot %ud okay) ~)
17− --
18−:: $flag: identifier for a diary channel
19−+$ flag (pair ship term)
20−:: $feel: either an emoji identifier like :diff or a URL for custom
21−+$ feel @ta
22−:: $view: the persisted display format for a diary
23−+$ view ?(%grid %list)
24−:: $sort: the persisted sort type for a diary
25−+$ sort ?(%alpha %time %arranged)
26−:: $arranged-notes: an array of noteIds
27−+$ arranged-notes (unit (list time))
28−:: $shelf: my ship's diaries
29−+$ shelf (map flag diary)
30−:: $said: used for references
31−+$ said (pair flag outline)
32−:: $plan: index into diary state
33−:: p: Note being referred to
34−:: q: Quip being referred to, if any
35−::
36−+$ plan
37− (pair time (unit time))
38−::
39−:: $diary: written longform communication
40−::
41−:: arranged-notes: a list of noteIds, used for manual sorting
42−:: net: an indicator of whether I'm a host or subscriber
43−:: log: the history of all modifications
44−:: perm: holds the diary's permissions
45−:: view: what format to display
46−:: sort: how to order posts
47−:: notes: the actual contents of the diary
48−:: remark: what is the last thing we've read
49−:: banter: comments organized by post
50−::
51−+$ diary
52− $: =arranged-notes
53− =net
54− =log
55− =perm
56− =view
57− =sort
58− =notes
59− =remark
60− ==
61−::
62−:: $notes: a set of time ordered diary posts
63−::
64−++ notes
65− =< rock
66− |%
67− +$ rock
68− ((mop time note) lte)
69− ++ on
70− ((^on time note) lte)
71− +$ diff
72− (pair time delta)
73− +$ delta
74− $% [%add p=essay]
75− [%edit p=essay]
76− [%del ~]
77− [%quips p=diff:quips]
78− [%add-feel p=ship q=feel]
79− [%del-feel p=ship]
80− ==
81− --
82−::
83−:: $quips: a set of time ordered note comments
84−::
85−++ quips
86− =< rock
87− |%
88− +$ rock
89− ((mop time quip) lte)
90− ++ on
91− ((^on time quip) lte)
92− +$ diff
93− (pair time delta)
94− +$ delta
95− $% [%add p=memo]
96− [%del ~]
97− [%add-feel p=ship q=feel]
98− [%del-feel p=ship]
99− ==
100− --
101−::
102−:: $outline: abridged $note
103−:: .quips: number of comments
104−::
105−+$ outline
106− [quips=@ud quippers=(set ship) essay]
107−::
108−++ outlines
109− =< outlines
110− |%
111− +$ outlines ((mop time outline) lte)
112− ++ on ((^on time outline) lte)
113− --
114−::
115−:: $note: a diary post
116−::
117−+$ note [seal essay]
118−:: $quip: a post comment
119−::
120−+$ quip [cork memo]
121−::
122−:: $seal: host-side data for a note
123−::
124−+$ seal
125− $: =time
126− =quips
127− feels=(map ship feel)
128− ==
129−::
130−:: $cork: host-side data for a quip
131−::
132−+$ cork
133− $: =time
134− feels=(map ship feel)
135− ==
136−:: $essay: the post data itself
137−::
138−:: title: the name of the post
139−:: image: a visual displayed as a header
140−:: content: the body of the post
141−:: author: the ship that wrote the post
142−:: sent: the client-side time the post was made
143−::
144−+$ essay
145− $: title=@t
146− image=@t
147− content=(list verse)
148− author=ship
149− sent=time
150− ==
151−+$ story (pair (list block) (list inline))
152−:: $memo: the comment data itself
153−::
154−:: content: the body of the comment
155−:: author: the ship that wrote the comment
156−:: sent: the client-side time the comment was made
157−::
158−+$ memo
159− $: content=story
160− author=ship
161− sent=time
162− ==
163−:: $verse: a chunk of post content
164−::
165−:: blocks stand on their own. inlines come in groups and get wrapped
166−:: into a paragraph
167−::
168−+$ verse
169− $% [%block p=block]
170− [%inline p=(list inline)]
171− ==
172−:: $listing: recursive type for infinitely nested <ul> or <ol>
173−+$ listing
174− $% [%list p=?(%ordered %unordered %tasklist) q=(list listing) r=(list inline)]
175− [%item p=(list inline)]
176− ==
177−:: $block: post content that sits outside of the normal text
178−::
179−:: %image: a visual, we record dimensions for better rendering
180−:: %cite: an Urbit reference
181−:: %header: a traditional HTML heading, h1-h6
182−:: %listing: a traditional HTML list, ul and ol
183−:: %code: a block of code
184−::
185−+$ block
186− $% [%image src=cord height=@ud width=@ud alt=cord]
187− [%cite =cite:c]
188− [%header p=?(%h1 %h2 %h3 %h4 %h5 %h6) q=(list inline)]
189− [%listing p=listing]
190− [%rule ~]
191− [%code code=cord lang=cord]
192− ==
193−:: $inline: post content that flows within a paragraph
194−::
195−:: @t: plain text
196−:: %italics: italic text
197−:: %bold: bold text
198−:: %strike: strikethrough text
199−:: %inline-code: code formatting for small snippets
200−:: %blockquote: blockquote surrounded content
201−:: %block: link/reference to blocks
202−:: %code: code formatting for large snippets
203−:: %tag: tag gets special signifier
204−:: %link: link to a URL with a face
205−:: %break: line break
206−::
207−+$ inline
208− $@ @t
209− $% [%italics p=(list inline)]
210− [%bold p=(list inline)]
211− [%strike p=(list inline)]
212− [%blockquote p=(list inline)]
213− [%inline-code p=cord]
214− [%ship p=ship]
215− [%block p=@ud q=cord]
216− [%code p=cord]
217− [%tag p=cord]
218− [%link p=cord q=cord]
219− [%task p=?(%.y %.n) q=(list inline)]
220− [%break ~]
221− ==
222−:: $log: a time ordered history of modifications to a diary
223−::
224−+$ log
225− ((mop time diff) lte)
226−++ log-on
227− ((on time diff) lte)
228−::
229−:: $action: the complete set of data required to modify a diary
230−::
231−+$ action
232− (pair flag:g update)
233−::
234−:: $update: a representation in time of a modification to a diary
235−::
236−+$ update
237− (pair time diff)
238−::
239−:: $diff: the full suite of modifications that can be made to a diary
240−::
241−+$ diff
242− $% [%notes p=diff:notes]
243− ::
244− [%add-sects p=(set sect:g)]
245− [%del-sects p=(set sect:g)]
246− ::
247− [%create p=perm q=notes]
248− [%view p=view]
249− [%sort p=sort]
250− [%arranged-notes p=arranged-notes]
251− ::
252− ==
253−::
254−:: $net: an indicator of whether I'm a host or subscriber
255−::
256−:: %pub: am publisher/host with fresh log
257−:: %sub: subscribed to the ship at saga
258−::
259−+$ net
260− $% [%sub p=ship load=_| =saga:e]
261− [%pub ~] :: TODO: permissions?
262− ==
263−::
264−:: $briefs: a map of diary unread information
265−::
266−:: brief: the last time a diary was read, how many posts since,
267−:: and the id of the last read note
268−::
269−++ briefs
270− =< briefs
271− |%
272− +$ briefs
273− (map flag brief)
274− +$ brief
275− [last=time count=@ud read-id=(unit time)]
276− +$ update
277− (pair flag brief)
278− --
279−:: $remark: a marker representing the last note I've read
280−::
281−+$ remark
282− [last-read=time watching=_| ~]
283−::
284−+$ remark-action
285− (pair flag remark-diff)
286−::
287−+$ remark-diff
288− $% [%read ~]
289− [%read-at p=time]
290− [?(%watch %unwatch) ~]
291− ==
292−::
293−:: $perm: represents the permissions for a diary channel and gives a
294−:: pointer back to the group it belongs to.
295−::
296−+$ perm
297− $: writers=(set sect:g)
298− group=flag:g
299− ==
300−:: $join: a group + channel flag to join a channel, group required for perms
301−::
302−+$ join
303− $: group=flag:g
304− chan=flag:g
305− ==
306−:: $leave: a flag to pass for a channel leave
307−::
308−+$ leave flag:g
309−::
310−:: $create: represents a request to create a channel
311−::
312−:: The name will be used as part of the flag which represents the
313−:: channel. $create is consumed by the diary agent first and then
314−:: passed to the groups agent to register the channel with the group.
315−::
316−:: Write permission is stored with the specific agent in the channel,
317−:: read permission is stored with the group's data.
318−::
319−+$ create
320− $: group=flag:g
321− name=term
322− title=cord
323− description=cord
324− readers=(set sect:g)
325− writers=(set sect:g)
326− ==
327−+$ import [writers=(set ship) =association:met =update-log:gra =graph:gra]
328−::
329−+$ imports (map flag import)
330−::
331−++ gra graph-store
332−++ orm-gra orm:lib-graph
333−++ orm-log-gra orm-log:lib-graph
334−++ met metadata-store
335−--
zod/seax/sur/docket.hoonnew file+82
@@ -0,0 +1,82 @@
1+|%
2+::
3++$ version
4+ [major=@ud minor=@ud patch=@ud]
5+::
6++$ glob (map path mime)
7+::
8++$ url cord
9+:: $glob-location: How to retrieve a glob
10+::
11++$ glob-reference
12+ [hash=@uvH location=glob-location]
13+::
14++$ glob-location
15+ $% [%http =url]
16+ [%ames =ship]
17+ ==
18+:: $href: Where a tile links to
19+::
20++$ href
21+ $% [%glob base=term =glob-reference]
22+ [%site =path]
23+ ==
24+:: $chad: State of a docket
25+::
26++$ chad
27+ $~ [%install ~]
28+ $% :: Done
29+ [%glob =glob]
30+ [%site ~]
31+ :: Waiting
32+ [%install ~]
33+ [%suspend glob=(unit glob)]
34+ :: Error
35+ [%hung err=cord]
36+ ==
37+::
38+:: $charge: A realized $docket
39+::
40++$ charge
41+ $: =docket
42+ =chad
43+ ==
44+::
45+:: $clause: A key and value, as part of a docket
46+::
47+:: Only used to parse $docket
48+::
49++$ clause
50+ $% [%title title=@t]
51+ [%info info=@t]
52+ [%color color=@ux]
53+ [%glob-http url=cord hash=@uvH]
54+ [%glob-ames =ship hash=@uvH]
55+ [%image =url]
56+ [%site =path]
57+ [%base base=term]
58+ [%version =version]
59+ [%website website=url]
60+ [%license license=cord]
61+ ==
62+::
63+:: $docket: A description of JS bundles for a desk
64+::
65++$ docket
66+ $: %1
67+ title=@t
68+ info=@t
69+ color=@ux
70+ =href
71+ image=(unit url)
72+ =version
73+ website=url
74+ license=cord
75+ ==
76+::
77++$ charge-update
78+ $% [%initial initial=(map desk charge)]
79+ [%add-charge =desk =charge]
80+ [%del-charge =desk]
81+ ==
82+--
zod/seax/sur/epic.hoondeleted−15
@@ -1,15 +0,0 @@
1−|%
2−:: $saga: version synchronisation state
3−:: %dex: publisher is ahead
4−:: %lev: we are ahead
5−:: %chi: full sync
6−::
7−+$ saga
8− $% [%dex ver=@ud]
9− [%lev ~]
10− [%chi ~]
11− ==
12−
13−+$ epic @ud
14−::
15−--
zod/seax/sur/graph-store.hoondeleted−272
@@ -1,272 +0,0 @@
1−/- *post
2−|%
3−+$ graph ((mop atom node) gth)
4−+$ marked-graph [p=graph q=(unit mark)]
5−::
6−+$ maybe-post (each post hash)
7−+$ node [post=maybe-post children=internal-graph]
8−+$ graphs (map resource marked-graph)
9−::
10−+$ tag-queries (jug term uid)
11−::
12−+$ update-log ((mop time logged-update) gth)
13−+$ update-logs (map resource update-log)
14−::
15−+$ internal-graph
16− $~ [%empty ~]
17− $% [%graph p=graph]
18− [%empty ~]
19− ==
20−::
21−+$ network
22− $: =graphs
23− =tag-queries
24− =update-logs
25− archive=graphs
26− ~
27− ==
28−::
29−+$ update [p=time q=action]
30−::
31−+$ logged-update [p=time q=logged-action]
32−
33−::
34−+$ logged-action
35− $% [%add-graph =resource =graph mark=(unit mark) overwrite=?]
36− [%add-nodes =resource nodes=(map index node)]
37− [%remove-posts =resource indices=(set index)]
38− [%add-signatures =uid =signatures]
39− [%remove-signatures =uid =signatures]
40− ==
41−::
42−+$ action
43− $% logged-action
44− [%remove-graph =resource]
45− ::
46− [%add-tag =term =uid]
47− [%remove-tag =term =uid]
48− ::
49− [%archive-graph =resource]
50− [%unarchive-graph =resource]
51− [%run-updates =resource =update-log]
52− ::
53− :: NOTE: cannot be sent as pokes
54− ::
55− [%keys =resources]
56− [%tags tags=(set term)]
57− [%tag-queries =tag-queries]
58− ==
59−::
60−+$ permissions
61− [admin=permission-level writer=permission-level reader=permission-level]
62−::
63−:: $permission-level: levels of permissions in increasing order
64−::
65−:: %no: May not add/remove node
66−:: %self: May only nodes beneath nodes that were added by
67−:: the same pilot, may remove nodes that the pilot 'owns'
68−:: %yes: May add a node or remove node
69−+$ permission-level
70− ?(%no %self %yes)
71−::
72−:: %graph-store types version 2
73−::
74−++ two
75− =< [. post-one]
76− =, post-one
77− |%
78− +$ maybe-post (each post hash)
79− ++ orm ((on atom node) gth)
80− ++ orm-log ((on time logged-update) gth)
81− ::
82− +$ graph ((mop atom node) gth)
83− +$ marked-graph [p=graph q=(unit mark)]
84− ::
85− +$ node [post=maybe-post children=internal-graph]
86− +$ graphs (map resource marked-graph)
87− ::
88− +$ tag-queries (jug term resource)
89− ::
90− +$ update-log ((mop time logged-update) gth)
91− +$ update-logs (map resource update-log)
92− ::
93− +$ internal-graph
94− $~ [%empty ~]
95− $% [%graph p=graph]
96− [%empty ~]
97− ==
98− ::
99− +$ network
100− $: =graphs
101− =tag-queries
102− =update-logs
103− archive=graphs
104− validators=(set mark)
105− ==
106− ::
107− +$ update [p=time q=action]
108− ::
109− +$ logged-update [p=time q=logged-action]
110− ::
111− +$ logged-action
112− $% [%add-graph =resource =graph mark=(unit mark) overwrite=?]
113− [%add-nodes =resource nodes=(map index node)]
114− [%remove-nodes =resource indices=(set index)]
115− [%add-signatures =uid =signatures]
116− [%remove-signatures =uid =signatures]
117− ==
118− ::
119− +$ action
120− $% logged-action
121− [%remove-graph =resource]
122− ::
123− [%add-tag =term =resource]
124− [%remove-tag =term =resource]
125− ::
126− [%archive-graph =resource]
127− [%unarchive-graph =resource]
128− [%run-updates =resource =update-log]
129− ::
130− :: NOTE: cannot be sent as pokes
131− ::
132− [%keys =resources]
133− [%tags tags=(set term)]
134− [%tag-queries =tag-queries]
135− ==
136− --
137−::
138−:: %graph-store types version 1
139−::
140−++ one
141− =< [. post-one]
142− =, post-one
143− |%
144− ++ orm ((on atom node) gth)
145− ++ orm-log ((on time logged-update) gth)
146− ::
147− +$ graph ((mop atom node) gth)
148− +$ marked-graph [p=graph q=(unit mark)]
149− ::
150− +$ node [=post children=internal-graph]
151− +$ graphs (map resource marked-graph)
152− ::
153− +$ tag-queries (jug term resource)
154− ::
155− +$ update-log ((mop time logged-update) gth)
156− +$ update-logs (map resource update-log)
157− ::
158− +$ internal-graph
159− $~ [%empty ~]
160− $% [%graph p=graph]
161− [%empty ~]
162− ==
163− ::
164− +$ network
165− $: =graphs
166− =tag-queries
167− =update-logs
168− archive=graphs
169− validators=(set mark)
170− ==
171− ::
172− +$ update [p=time q=action]
173− ::
174− +$ logged-update [p=time q=logged-action]
175− ::
176− +$ logged-action
177− $% [%add-graph =resource =graph mark=(unit mark) overwrite=?]
178− [%add-nodes =resource nodes=(map index node)]
179− [%remove-nodes =resource indices=(set index)]
180− [%add-signatures =uid =signatures]
181− [%remove-signatures =uid =signatures]
182− ==
183− ::
184− +$ action
185− $% logged-action
186− [%remove-graph =resource]
187− ::
188− [%add-tag =term =resource]
189− [%remove-tag =term =resource]
190− ::
191− [%archive-graph =resource]
192− [%unarchive-graph =resource]
193− [%run-updates =resource =update-log]
194− ::
195− :: NOTE: cannot be sent as pokes
196− ::
197− [%keys =resources]
198− [%tags tags=(set term)]
199− [%tag-queries =tag-queries]
200− ==
201− --
202−::
203−:: %graph-store types version 0
204−::
205−++ zero
206− =< [. post-zero]
207− =, post-zero
208− |%
209− ++ orm ((ordered-map atom node) gth)
210− ++ orm-log ((ordered-map time logged-update) gth)
211− ::
212− +$ graph ((mop atom node) gth)
213− +$ marked-graph [p=graph q=(unit mark)]
214− ::
215− +$ node [=post children=internal-graph]
216− +$ graphs (map resource marked-graph)
217− ::
218− +$ tag-queries (jug term resource)
219− ::
220− +$ update-log ((mop time logged-update) gth)
221− +$ update-logs (map resource update-log)
222− ::
223− ::
224− +$ internal-graph
225− $~ [%empty ~]
226− $% [%graph p=graph]
227− [%empty ~]
228− ==
229− ::
230− +$ network
231− $: =graphs
232− =tag-queries
233− =update-logs
234− archive=graphs
235− validators=(set mark)
236− ==
237− ::
238− +$ update
239− $% [%0 p=time q=update-0]
240− ==
241− ::
242− +$ logged-update
243− $% [%0 p=time q=logged-update-0]
244− ==
245− ::
246− +$ logged-update-0
247− $% [%add-graph =resource =graph mark=(unit mark) overwrite=?]
248− [%add-nodes =resource nodes=(map index node)]
249− [%remove-nodes =resource indices=(set index)]
250− [%add-signatures =uid =signatures]
251− [%remove-signatures =uid =signatures]
252− ==
253− ::
254− +$ update-0
255− $% logged-update-0
256− [%remove-graph =resource]
257− ::
258− [%add-tag =term =resource]
259− [%remove-tag =term =resource]
260− ::
261− [%archive-graph =resource]
262− [%unarchive-graph =resource]
263− [%run-updates =resource =update-log]
264− ::
265− :: NOTE: cannot be sent as pokes
266− ::
267− [%keys =resources]
268− [%tags tags=(set term)]
269− [%tag-queries =tag-queries]
270− ==
271− --
272−--
zod/seax/sur/group-store.hoondeleted−39
@@ -1,39 +0,0 @@
1−/- *group, *resource
2−^?
3−|%
4−::
5−:: $action: request to change group-store state
6−::
7−:: %add-group: add a group
8−:: %add-members: add members to a group
9−:: %remove-members: remove members from a group
10−:: %add-tag: add a tag to a set of ships
11−:: %remove-tag: remove a tag from a set of ships
12−:: %change-policy: change a group's policy
13−:: %remove-group: remove a group from the store
14−:: %expose: unset .hidden flag
15−::
16−+$ action
17− $% [%add-group =resource =policy hidden=?]
18− [%add-members =resource ships=(set ship)]
19− [%remove-members =resource ships=(set ship)]
20− [%add-tag =resource =tag ships=(set ship)]
21− [%remove-tag =resource =tag ships=(set ship)]
22− [%change-policy =resource =diff:policy]
23− [%remove-group =resource ~]
24− [%expose =resource ~]
25− ==
26−:: $update: a description of a processed state change
27−::
28−:: %initial: describe groups upon new subscription
29−::
30−+$ update
31− $% initial
32− action
33− ==
34−+$ initial
35− $% [%initial-group =resource =group]
36− [%initial =groups]
37− ==
38−--
39−
zod/seax/sur/group.hoondeleted−109
@@ -1,109 +0,0 @@
1−/- *resource
2−::
3−^?
4−|%
5−::
6−++ groups-state-one
7− |%
8− +$ groups (map resource group)
9− ::
10− +$ tag $@(group-tag [app=term tag=term])
11− ::
12− +$ tags (jug tag ship)
13− ::
14− +$ group
15− $: members=(set ship)
16− =tags
17− =policy
18− hidden=?
19− ==
20− --
21−:: $groups: a mapping from group-ids to groups
22−::
23−+$ groups (map resource group)
24−:: $group-tag: an identifier used by groups
25−::
26−:: These tags should have precise semantics, as they are shared across all
27−:: apps.
28−::
29−+$ group-tag ?(role-tag)
30−:: $tag: an identifier used to identify a subset of members
31−::
32−:: Tags may be used and recognised differently across apps.
33−:: for example, you could use tags like `%author`, `%bot`, `%flagged`...
34−::
35−+$ tag $@(group-tag [app=term =resource tag=term])
36−:: $role-tag: a kind of $group-tag that identifies a privileged user
37−::
38−:: These roles are
39−:: %admin: Administrator, can do everything except delete the group
40−:: %moderator: Moderator, can add/remove/ban users
41−:: %janitor: Has no special meaning inside group-store,
42−:: but may be given additional privileges in other apps.
43−::
44−+$ role-tag
45− ?(%admin %moderator %janitor)
46−:: $tags: a mapping from a $tag to the members it identifies
47−::
48−+$ tags (jug tag ship)
49−:: $group: description of a group of users
50−::
51−:: .members: members of the group
52−:: .tag-queries: a map of tags to subsets of members
53−:: .policy: permissions for the group
54−:: .hidden: is group unmanaged
55−+$ group
56− $: members=(set ship)
57− =tags
58− =policy
59− hidden=?
60− ==
61−:: $policy: access control for a group
62−::
63−++ policy
64− =< policy
65− |%
66− ::
67− +$ policy
68− $% invite
69− open
70− ==
71− :: $diff: change group policy
72− +$ diff
73− $% [%invite diff:invite]
74− [%open diff:open]
75− [%replace =policy]
76− ==
77− :: $invite: allow only invited ships
78− ++ invite
79− =< invite-policy
80− |%
81− ::
82− +$ invite-policy
83− [%invite pending=(set ship)]
84− :: $diff: add or remove invites
85− ::
86− +$ diff
87− $% [%add-invites invitees=(set ship)]
88− [%remove-invites invitees=(set ship)]
89− ==
90− --
91− :: $open: allow all unbanned ships of approriate rank
92− ::
93− ++ open
94− =< open-policy
95− |%
96− ::
97− +$ open-policy
98− [%open ban-ranks=(set rank:title) banned=(set ship)]
99− :: $diff: ban or allow ranks and ships
100− ::
101− +$ diff
102− $% [%allow-ranks ranks=(set rank:title)]
103− [%ban-ranks ranks=(set rank:title)]
104− [%ban-ships ships=(set ship)]
105− [%allow-ships ships=(set ship)]
106− ==
107− --
108− --
109−--
zod/seax/sur/groups.hoondeleted−364
@@ -1,364 +0,0 @@
1−/- meta, e=epic
2−/- old=group
3−/- grp=group-store
4−/- metadata-store
5−|%
6−++ okay `epic:e`2
7−++ mar
8− |%
9− ++ act `mark`(rap 3 %group-action '-' (scot %ud okay) ~)
10− ++ upd `mark`(rap 3 %group-update '-' (scot %ud okay) ~)
11− ++ log `mark`(rap 3 %group-log '-' (scot %ud okay) ~)
12− ++ int `mark`(rap 3 %group-init '-' (scot %ud okay) ~)
13− --
14−:: $flag: ID for a group
15−::
16−+$ flag (pair ship term)
17−::
18−:: $nest: ID for a channel, {app}/{ship}/{name}
19−::
20−+$ nest (pair dude:gall flag)
21−::
22−:: $sect: ID for cabal, similar to a role
23−::
24−+$ sect term
25−::
26−:: $zone: channel grouping
27−::
28−:: includes its own metadata for display and keeps the order of
29−:: channels within.
30−::
31−:: zone: the term that represents the ID of a zone
32−:: realm: the metadata representing the zone and the order of channels
33−:: delta: the set of actions that can be taken on a zone
34−:: %add: create a zone
35−:: %del: delete the zone
36−:: %edit: modify the zone metadata
37−:: %mov: reorders the zone in the group
38−:: %mov-nest: reorders a channel within the zone
39−::
40−++ zone
41− =< zone
42− |%
43− +$ zone @tas
44− +$ realm
45− $: met=data:meta
46− ord=(list nest)
47− ==
48− +$ diff (pair zone delta)
49− +$ delta
50− $% [%add meta=data:meta]
51− [%del ~]
52− [%edit meta=data:meta]
53− [%mov idx=@ud]
54− [%mov-nest =nest idx=@ud]
55− ==
56− --
57−::
58−:: $fleet: group members and their associated metadata
59−::
60−:: vessel: a user's set of sects or roles and the time that they joined
61−:: @da default represents an admin added member that has yet to join
62−::
63−++ fleet
64− =< fleet
65− |%
66− +$ fleet (map ship vessel)
67− +$ vessel
68− $: sects=(set sect)
69− joined=time
70− ==
71− +$ diff
72− $% [%add ~]
73− [%del ~]
74− [%add-sects sects=(set sect)]
75− [%del-sects sects=(set sect)]
76− ==
77− --
78−::
79−:: $channel: a medium for interaction
80−::
81−++ channel
82− =< channel
83− |%
84− +$ preview
85− $: =nest
86− meta=data:meta
87− group=^preview
88− ==
89− ::
90− +$ channels (map nest channel)
91− ::
92− :: $channel: a collection of metadata about a specific agent integration
93− ::
94− :: meta: title, description, image, cover
95− :: added: when the channel was created
96− :: zone: what zone or section to bucket in
97− :: join: should the channel be joined by new members
98− :: readers: what sects can see the channel, empty means anyone
99− ::
100− +$ channel
101− $: meta=data:meta
102− added=time
103− =zone
104− join=?
105− readers=(set sect)
106− ==
107− ::
108− :: $diff: represents the set of actions you can take on a channel
109− ::
110− :: add: create a channel
111− :: edit: edit a channel
112− :: del: delete a channel
113− :: add-sects: add sects to readers
114− :: del-sects: delete sects from readers
115− :: zone: change the zone of the channel
116− :: join: toggle default join
117− ::
118− +$ diff
119− $% [%add =channel]
120− [%edit =channel]
121− [%del ~]
122− ::
123− [%add-sects sects=(set sect)]
124− [%del-sects sects=(set sect)]
125− ::
126− [%zone =zone]
127− ::
128− [%join join=_|]
129− ==
130− --
131−::
132−:: $group: collection of people and the pathways in which they interact
133−::
134−:: group holds all data around members, permissions, channel
135−:: organization, and its own metadata to represent the group
136−::
137−+$ group
138− $: =fleet
139− cabals=(map sect cabal)
140− zones=(map zone realm:zone)
141− zone-ord=(list zone)
142− =bloc
143− =channels:channel
144− imported=(set nest)
145− =cordon
146− secret=?
147− meta=data:meta
148− ==
149−::
150−+$ group-ui [group saga=(unit saga:e)]
151−:: $cabal: metadata representing a $sect or role
152−::
153−++ cabal
154− =< cabal
155− |%
156− ::
157− +$ cabal
158− [meta=data:meta ~]
159− ::
160− +$ diff
161− $% [%add meta=data:meta]
162− [%edit meta=data:meta]
163− [%del ~]
164− ==
165− --
166−::
167−:: $cordon: group entry and visibility permissions
168−::
169−++ cordon
170− =< cordon
171− |%
172− ::
173− :: $open: a group with open entry, only bans are barred entry
174− ::
175− ++ open
176− |%
177− :: $ban: set of ships and ranks/classes that are not allowed entry
178− ::
179− :: bans can either be done at the individual ship level or by the
180− :: rank level (comet/moon/etc.)
181− ::
182− +$ ban [ships=(set ship) ranks=(set rank:title)]
183− +$ diff
184− $% [%add-ships p=(set ship)]
185− [%del-ships p=(set ship)]
186− ::
187− [%add-ranks p=(set rank:title)]
188− [%del-ranks p=(set rank:title)]
189− ==
190− --
191− ::
192− :: $shut: a group with closed entry, everyone barred entry
193− ::
194− :: a shut cordon means that the group is closed, but still visible.
195− :: people may request entry and either be accepted or denied or
196− :: they may be invited directly
197− ::
198− :: ask: represents those requesting entry
199− :: pending: represents those who've been invited
200− ::
201− ++ shut
202− |%
203− +$ state [pend=(set ship) ask=(set ship)]
204− +$ kind ?(%ask %pending)
205− +$ diff
206− $% [%add-ships p=kind q=(set ship)]
207− [%del-ships p=kind q=(set ship)]
208− ==
209− --
210− ::
211− :: $cordon: a set of metadata to represent the entry policy for a group
212− ::
213− :: open: a group with open entry, only bans barred entry
214− :: shut: a group with closed entry, everyone barred entry
215− :: afar: a custom entry policy defined by another agent
216− ::
217− +$ cordon
218− $% [%shut state:shut]
219− [%afar =flag =path desc=@t]
220− [%open =ban:open]
221− ==
222− ::
223− :: $diff: the actions you can take on a cordon
224− ::
225− +$ diff
226− $% [%shut p=diff:shut]
227− [%open p=diff:open]
228− [%swap p=cordon]
229− ==
230− --
231−::
232−:: $bloc: superuser sects
233−::
234−:: sects in the bloc set are allowed to make modifications to the group
235−:: and its various metadata and permissions
236−::
237−++ bloc
238− =< bloc
239− |%
240− +$ bloc (set sect)
241− +$ diff
242− $% [%add p=(set sect)]
243− [%del p=(set sect)]
244− ==
245− --
246−::
247−:: $diff: the general set of changes that can be made to a group
248−::
249−+$ diff
250− $% [%fleet p=(set ship) q=diff:fleet]
251− [%cabal p=sect q=diff:cabal]
252− [%channel p=nest q=diff:channel]
253− [%bloc p=diff:bloc]
254− [%cordon p=diff:cordon]
255− [%zone p=diff:zone]
256− [%meta p=data:meta]
257− [%secret p=?]
258− [%create p=group]
259− [%del ~]
260− ==
261−::
262−:: $action: the complete set of data required to edit a group
263−::
264−+$ action
265− (pair flag update)
266−::
267−:: $update: a representation in time of a modification of a group
268−::
269−+$ update
270− (pair time diff)
271−::
272−:: $create: a request to make a group
273−::
274−+$ create
275− $: name=term
276− title=cord
277− description=cord
278− image=cord
279− cover=cord
280− =cordon
281− members=(jug ship sect)
282− secret=?
283− ==
284−::
285−+$ init [=time =group]
286−::
287−:: $groups-ui: map for frontend to display groups
288−+$ groups-ui
289− (map flag group-ui)
290−+$ groups
291− (map flag group)
292−+$ net-groups
293− (map flag [net group])
294−::
295−:: $log: a time ordered map of all modifications to groups
296−::
297−+$ log
298− ((mop time diff) lte)
299−::
300−++ log-on
301− ((on time diff) lte)
302−::
303−:: $net: an indicator of whether I'm a host or subscriber
304−::
305−+$ net
306− $~ [%pub ~]
307− $% [%pub p=log]
308− [%sub p=time load=_| =saga:e]
309− ==
310−::
311−:: $join: a join request, can elect to join all channels
312−::
313−+$ join
314− $: =flag
315− join-all=?
316− ==
317−::
318−:: $knock: a request to enter a closed group
319−::
320−+$ knock flag
321−::
322−:: $progress: the state of a group join
323−::
324−+$ progress
325− ?(%knocking %adding %watching %done %error)
326−::
327−:: $claim: a mark for gangs to represent a join in progress
328−::
329−+$ claim
330− $: join-all=?
331− =progress
332− ==
333−::
334−:: $preview: the metadata and entry policy for a group
335−::
336−+$ preview
337− $: =flag
338− meta=data:meta
339− =cordon
340− =time
341− secret=?
342− ==
343−::
344−+$ previews (map flag preview)
345−::
346−:: $invite: a marker to show you've been invited to a group
347−::
348−+$ invite (pair flag ship)
349−::
350−:: $gang: view of foreign group
351−::
352−+$ gang
353− $: cam=(unit claim)
354− pev=(unit preview)
355− vit=(unit invite)
356− ==
357−::
358−+$ gangs (map flag gang)
359−++ met metadata-store
360−::
361−+$ import [self=association:met chan=(map flag =association:met) roles=(set flag) =group:old]
362−::
363−+$ imports (map flag import)
364−--
zod/seax/sur/hark-store.hoondeleted−159
@@ -1,159 +0,0 @@
1−^?
2−::
3−:: %hark-store: Notification, unreads store
4−::
5−:: Timeboxing & binning:
6−::
7−:: Unread notifications accumulate in $unreads. They are grouped by
8−:: their $bin. A notification may become read by either:
9−:: a) being read by a %read-count or %read-each or %read-note
10−:: b) being read by a %seen
11−::
12−:: If a) then we insert the corresponding bin into $reads at the
13−:: current timestamp
14−:: If b) then we empty $unreads and move all bins to $reads at the
15−:: current timestamp
16−::
17−:: Unread tracking:
18−:: Unread tracking has two 'modes' which may be used concurrently,
19−:: if necessary.
20−::
21−:: count:
22−:: This stores the unreads as a simple atom, describing the number
23−:: of unread items. May be increased with %unread-count and
24−:: set to zero with %read-count. Ideal for high-frequency linear
25−:: datastructures, e.g. chat
26−:: each:
27−:: This stores the unreads as a set of paths, describing the set of
28−:: unread items. Unreads may be added to the set with %unread-each
29−:: and removed with %read-each. Ideal for non-linear, low-frequency
30−:: datastructures, e.g. blogs
31−::
32−|%
33−:: $place: A location, under which landscape stores stats
34−::
35−:: .desk must match q.byk.bowl
36−:: Examples:
37−:: A chat:
38−:: [%landscape /~dopzod/urbit-help]
39−:: A note in a notebook:
40−:: [%landscape /~darrux-landes/feature-requests/12374893234232]
41−:: A group:
42−:: [%hark-group-hook /~bitbet-bolbel/urbit-community]
43−:: Comments on a link
44−:: [%landscape /~dabben-larbet/urbit-in-the-news/17014118450499614194868/2]
45−::
46−+$ place [=desk =path]
47−::
48−:: $bin: Identifier for grouping notifications
49−::
50−:: Examples
51−:: A mention in a chat:
52−:: [/mention %landscape /~dopzod/urbit-help]
53−:: New messages in a chat
54−:: [/message %landscape /~dopzod/urbit-help]
55−:: A new comment in a notebook:
56−:: [/comment %landscape /~darrux-landes/feature-requests/12374893234232/2]
57−::
58−+$ bin [=path =place]
59−::
60−:: $lid: Reference to a timebox
61−::
62−+$ lid
63− $% [%archive =time]
64− [%seen ~]
65− [%unseen ~]
66− ==
67−:: $content: Notification content
68−+$ content
69− $% [%ship =ship]
70− [%text =cord]
71− ==
72−::
73−:: $body: A notification body
74−::
75−+$ body
76− $: title=(list content)
77− content=(list content)
78− =time
79− binned=path
80− link=path
81− ==
82−::
83−+$ notification
84− [date=@da =bin body=(list body)]
85−:: $timebox: Group of notificatons
86−+$ timebox
87− (map bin notification)
88−:: $archive: Archived notifications, ordered by time
89−+$ archive
90− ((mop @da timebox) gth)
91−::
92−+$ action
93− $% :: hook actions
94− ::
95− :: %add-note: add a notification
96− [%add-note =bin =body]
97− ::
98− :: %del-place: Underlying resource disappeared, remove all
99− :: associated notifications
100− [%del-place =place]
101− :: %unread-count: Change unread count by .count
102− [%unread-count =place inc=? count=@ud]
103− :: %unread-each: Add .path to list of unreads for .place
104− [%unread-each =place =path]
105− :: %saw-place: Update last-updated for .place to now.bowl
106− [%saw-place =place time=(unit time)]
107− :: store actions
108− ::
109− :: %archive: archive single notification
110− :: if .time is ~, then archiving unread notification
111− :: else, archiving read notification
112− [%archive =lid =bin]
113− :: %read-count: set unread count to zero
114− [%read-count =place]
115− :: %read-each: remove path from unreads for .place
116− [%read-each =place =path]
117− :: %read-note: Read note at .bin
118− [%read-note =bin]
119− :: %archive-all: Archive all notifications
120− [%archive-all ~]
121− :: %opened: User opened notifications, reset timeboxing logic.
122− ::
123− [%opened ~]
124− ::
125− :: XX: previously in hark-store, now deprecated
126− :: the hooks responsible for creating notifications may offer pokes
127− :: similar to this
128− :: [%read-graph =resource]
129− :: [%read-group =resource]
130− :: [%remove-graph =resource]
131− ::
132− ==
133−:: .stats: Statistics for a .place
134−::
135−+$ stats
136− $: count=@ud
137− each=(set path)
138− last=@da
139− timebox=(unit @da)
140− ==
141−::
142−+$ update
143− $% action
144− :: %more: more updates
145− [%archived =time =lid =notification]
146− [%more more=(list update)]
147− :: %note-read: note has been read with timestamp
148− [%note-read =time =bin]
149− [%added =notification]
150− :: %timebox: description of timebox.
151− ::
152− [%timebox =lid =(list notification)]
153− :: %place-stats: description of .stats for a .place
154− [%place-stats =place =stats]
155− :: %place-stats: stats for all .places
156− [%all-stats places=(map place stats)]
157− ==
158−--
159−
zod/seax/sur/meta.hoondeleted−21
@@ -1,21 +0,0 @@
1−|%
2−:: $data: generic metadata for various entities
3−::
4−:: title: the pretty text representing what something is called
5−:: description: a longer text entry giving a detailed summary
6−:: image: an image URL or color string used as an icon/avatar
7−:: cover: an image URL or color string, used as a header
8−::
9−+$ data
10− $: title=cord
11− description=cord
12− image=cord
13− cover=cord
14− ==
15−+$ diff
16− $% [%title =cord]
17− [%description =cord]
18− [%image =cord]
19− [%cover =cord]
20− ==
21−--
zod/seax/sur/metadata-store.hoondeleted−138
@@ -1,138 +0,0 @@
1−/- *resource
2−^?
3−|%
4−::
5−+$ app-name term
6−+$ md-resource [=app-name =resource]
7−+$ association [group=resource =metadatum]
8−+$ associations (map md-resource association)
9−+$ group-preview
10− $: group=resource
11− channels=associations
12− members=@ud
13− channel-count=@ud
14− =metadatum
15− ==
16−::
17−+$ color @ux
18−+$ url @t
19−::
20−:: $vip-metadata: variation in permissions
21−::
22−:: This will be passed to the graph-permissions mark
23−:: conversion to allow for custom permissions.
24−::
25−:: %reader-comments: Allow readers to comment, regardless
26−:: of whether they can write. (notebook, collections)
27−:: %member-metadata: Allow members to add channels (groups)
28−:: %host-feed: Only host can post to group feed
29−:: %admin-feed: Only admins and host can post to group feed
30−:: %$: No variation
31−::
32−+$ vip-metadata
33− $? %reader-comments
34− %member-metadata
35− %host-feed
36− %admin-feed
37− %$
38− ==
39−::
40−+$ md-config
41− $~ [%empty ~]
42− $% [%group feed=(unit (unit md-resource))]
43− [%graph module=term]
44− [%empty ~]
45− ==
46−::
47−+$ edit-field
48− $% [%title title=cord]
49− [%description description=cord]
50− [%color color=@ux]
51− [%picture =url]
52− [%preview preview=?]
53− [%hidden hidden=?]
54− [%vip vip=vip-metadata]
55− ==
56−::
57−+$ metadatum
58− $: title=cord
59− description=cord
60− =color
61− date-created=time
62− creator=ship
63− config=md-config
64− picture=url
65− preview=?
66− hidden=?
67− vip=vip-metadata
68− ==
69−::
70−+$ action
71− $% [%add group=resource resource=md-resource =metadatum]
72− [%remove group=resource resource=md-resource]
73− [%edit group=resource resource=md-resource =edit-field]
74− [%initial-group group=resource =associations]
75− ==
76−::
77−+$ hook-update
78− $% [%req-preview group=resource]
79− [%preview group-preview]
80− ==
81−::
82−+$ update
83− $% action
84− [%associations =associations]
85− $: %updated-metadata
86− group=resource
87− resource=md-resource
88− before=metadatum
89− =metadatum
90− ==
91− ==
92−:: historical
93−++ one
94− |%
95− ::
96− +$ action
97− $~ [%remove *resource *md-resource]
98− $< %edit ^action
99− ::
100− +$ update
101− $~ [%remove *resource *md-resource]
102− $< %edit ^update
103− ::
104− --
105−++ zero
106− |%
107− ::
108− +$ association [group=resource =metadatum]
109− ::
110− +$ associations (map md-resource association)
111− ::
112− +$ metadatum
113− $: title=cord
114− description=cord
115− =color
116− date-created=time
117− creator=ship
118− module=term
119− picture=url
120− preview=?
121− vip=vip-metadata
122− ==
123− ::
124− +$ update
125− $% [%add group=resource resource=md-resource =metadatum]
126− [%remove group=resource resource=md-resource]
127− [%initial-group group=resource =associations]
128− [%associations =associations]
129− $: %updated-metadata
130− group=resource
131− resource=md-resource
132− before=metadatum
133− =metadatum
134− ==
135− ==
136− ::
137− --
138−--
zod/seax/sur/notes.hoondeleted−74
@@ -1,74 +0,0 @@
1−|%
2−+$ diary
3− $: *
4− *
5− *
6− *
7− *
8− =notes
9− *
10− ==
11−+$ seal
12− $: =time
13− * :: =quips
14− * :: feels=(map ship feel)
15− ==
16−+$ note [seal essay]
17−+$ verse
18− $% [%block p=block]
19− [%inline p=(list inline)]
20− ==
21−+$ listing
22− $% [%list p=?(%ordered %unordered) q=(list listing) r=(list inline)]
23− [%item p=(list inline)]
24− ==
25−+$ block
26− $% [%image src=cord height=@ud width=@ud alt=cord]
27− [%cite *] :: =cite:c]
28− [%header p=?(%h1 %h2 %h3 %h4 %h5 %h6) q=(list inline)]
29− [%listing p=listing]
30− [%rule ~]
31− [%code code=cord lang=cord]
32− ==
33−+$ inline
34− $@ @t
35− $% [%italics p=(list inline)]
36− [%bold p=(list inline)]
37− [%strike p=(list inline)]
38− [%blockquote p=(list inline)]
39− [%inline-code p=cord]
40− [%ship p=ship]
41− [%block p=@ud q=cord]
42− [%code p=cord]
43− [%tag p=cord]
44− [%link p=cord q=cord]
45− [%break ~]
46− ==
47−+$ essay
48− $: title=@t
49− image=@t
50− content=(list verse)
51− author=ship
52− sent=time
53− ==
54−++ notes
55− =< rock
56− |%
57− +$ rock
58− ((mop time note) lte)
59− ++ on
60− ((^on time note) lte)
61− +$ diff
62− (pair time delta)
63− +$ delta
64− $% [%add p=essay]
65− [%edit p=essay]
66− [%del ~]
67− [%quips *] :: p=diff:quips]
68− [%add-feel p=ship *] :: q=feel]
69− [%del-feel p=ship]
70− ==
71− --
72−+$ shelf (map flag diary)
73−+$ flag (pair ship term)
74−--
zod/seax/sur/post.hoondeleted−91
@@ -1,91 +0,0 @@
1−/- *resource
2−|%
3−+$ index (list atom)
4−+$ uid [=resource =index]
5−::
6−:: +sham (half sha-256) hash of +validated-portion
7−+$ hash @ux
8−::
9−+$ signature [p=@ux q=ship r=life]
10−+$ signatures (set signature)
11−+$ post
12− $: author=ship
13− =index
14− time-sent=time
15− contents=(list content)
16− hash=(unit hash)
17− =signatures
18− ==
19−::
20−+$ indexed-post [a=atom p=post]
21−::
22−+$ validated-portion
23− $: parent-hash=(unit hash)
24− author=ship
25− time-sent=time
26− contents=(list content)
27− ==
28−::
29−+$ reference
30− $% [%graph group=resource =uid]
31− [%group group=resource]
32− [%app =ship =desk =path]
33− ==
34−::
35−+$ content
36− $% [%text text=cord]
37− [%mention =ship]
38− [%url url=cord]
39− [%code expression=cord output=(list tank)]
40− [%reference =reference]
41− ==
42−::
43−++ post-one
44− |%
45− ::
46− +$ indexed-post [a=atom p=post]
47− ::
48− +$ post
49− $: author=ship
50− =index
51− time-sent=time
52− contents=(list content)
53− hash=(unit hash)
54− =signatures
55− ==
56− ::
57− +$ content
58− $% [%text text=cord]
59− [%mention =ship]
60− [%url url=cord]
61− [%code expression=cord output=(list tank)]
62− [%reference =reference]
63− ==
64− ::
65− +$ reference
66− $% [%graph group=resource =uid]
67− [%group group=resource]
68− ==
69− --
70−::
71−++ post-zero
72− |%
73− ::
74− +$ content
75− $% [%text text=cord]
76− [%mention =ship]
77− [%url url=cord]
78− [%code expression=cord output=(list tank)]
79− [%reference =uid]
80− ==
81− ::
82− +$ post
83− $: author=ship
84− =index
85− time-sent=time
86− contents=(list content)
87− hash=(unit hash)
88− =signatures
89− ==
90− --
91−--
zod/seax/sur/pull-hook.hoondeleted−11
@@ -1,11 +0,0 @@
1−/- *resource
2−|%
3−+$ action
4− $% [%add =ship =resource]
5− [%remove =resource]
6− ==
7−::
8−+$ update
9− $% [%tracking tracking=(map resource ship)]
10− ==
11−--
zod/seax/sur/resource.hoondeleted−10
@@ -1,10 +0,0 @@
1−^?
2−|%
3−+$ resource [=entity name=term]
4−+$ resources (set resource)
5−::
6−+$ entity
7− $@ ship
8− $% !!
9− ==
10−--
zod/seax/sur/seax.hoon+10−1
@@ -7,8 +7,17 @@
77++ engine
88 $_ ^|
99 |%
10− ++ url |~ tape *tape
10+ ++ request |~ tape *request:http
1111 ++ results |~ mime-data:iris *(unit (list search-result))
1212 --
1313+$ engines (map name=term [=engine weight=@rs])
14+:: +get: a GET request to url with the query appended
15+::
16+:: The runtime unescapes the query string once before sending the
17+:: request, so the query is escaped twice to stay escaped on the wire.
18+::
19+++ get
20+ |= [url=tape query=tape]
21+ ^- request:http
22+ [%'GET' (crip (weld url (en-urlt:html (en-urlt:html query)))) ~ ~]
1423--
zod/seax/sur/spider.hoondeleted−27
@@ -1,27 +0,0 @@
1−/+ libstrand=strand
2−=, strand=strand:libstrand
3−|%
4−+$ thread $-(vase shed:khan)
5−+$ input [=tid =cage]
6−+$ tid tid:strand
7−+$ bowl bowl:strand
8−+$ http-error
9− $? %bad-request :: 400
10− %forbidden :: 403
11− %nonexistent :: 404
12− %offline :: 504
13− ==
14−+$ start-args
15− $: parent=(unit tid)
16− use=(unit tid)
17− =beak
18− file=term
19− =vase
20− ==
21−+$ inline-args
22− $: parent=(unit tid)
23− use=(unit tid)
24− =beak
25− =shed:khan
26− ==
27−--
zod/seax/sys.kelvin+1−1
@@ -1 +1 @@
1−[%zuse 413]
1+[%zuse 408]