on master help sign in
Merge pull request #336 from urbit/rob-edits

Concatenates child rune-pages into parent pages

commitce44911718ec46ee3d20516d85789ea7309c3283 authorAnthony Arroyo <anthony@tlon.io> dateThu 17 Jan 2019, 15:46 (8 years ago) parent7e2b043c8df462
178 files changed+17654−17704
getting-started.udon+107−25 introduction/contributing.udon+5−3 learn/arvo/arvo-internals/admin.udon−20 learn/arvo/arvo-internals/ames.udon+1987−1 learn/arvo/arvo-internals/ames/commentary.udon−1991 learn/arvo/arvo-internals/clay.udon+2611−1 learn/arvo/arvo-internals/clay/architecture.udon−424 learn/arvo/arvo-internals/clay/commentary.udon−2196 learn/arvo/arvo-internals/eyre.udon+717−1 learn/arvo/arvo-internals/eyre/commentary.udon−274 learn/arvo/arvo-internals/eyre/specification.udon−444 learn/arvo/arvo-internals/filesystem.udon+2−3 learn/arvo/arvo-internals/ford.udon+470−3 learn/arvo/arvo-internals/ford/runes.udon−473 learn/arvo/arvo-internals/gall.udon+2344−1 learn/arvo/arvo-internals/gall/api.udon−509 learn/arvo/arvo-internals/gall/generators.udon−172 learn/arvo/arvo-internals/gall/http.udon−215 learn/arvo/arvo-internals/gall/marks.udon−128 learn/arvo/arvo-internals/gall/network.udon−353 learn/arvo/arvo-internals/gall/security-driver.udon−281 learn/arvo/arvo-internals/gall/state.udon−123 learn/arvo/arvo-internals/gall/subscriptions.udon−332 learn/arvo/arvo-internals/gall/web-apps.udon−254 learn/arvo/arvo-internals/hall.udon+1354−4 learn/arvo/arvo-internals/hall/architecture.udon−527 learn/arvo/arvo-internals/hall/interface.udon−391 learn/arvo/arvo-internals/hall/new-gall.udon−250 learn/arvo/arvo-internals/hall/new-gall/example.udon−97 learn/arvo/arvo-internals/hall/new-gall/spec.udon−163 learn/arvo/arvo-internals/udon.udon+297−7 learn/arvo/arvo-internals/udon/blog.udon−109 learn/arvo/arvo-internals/udon/comments.udon−49 learn/arvo/arvo-internals/udon/static.udon−142 learn/arvo/nock/implementations.udon+2116−6 learn/arvo/nock/implementations/c.udon−212 learn/arvo/nock/implementations/clojure.udon−125 learn/arvo/nock/implementations/csharp.udon−478 learn/arvo/nock/implementations/groovy.udon−206 learn/arvo/nock/implementations/haskell.udon−63 learn/arvo/nock/implementations/hoon.udon−55 learn/arvo/nock/implementations/javascript.udon−365 learn/arvo/nock/implementations/python.udon−95 learn/arvo/nock/implementations/ruby.udon−139 learn/arvo/nock/implementations/scala.udon−88 learn/arvo/nock/implementations/scheme.udon−128 learn/arvo/nock/implementations/swift.udon−366 learn/arvo/style.udon+489 learn/arvo/vere/jetting.udon+6−11 reference/glossary.udon+33−33 reference/hoon-expressions/rune/bar.udon+664−1 reference/hoon-expressions/rune/bar/cab.udon−96 reference/hoon-expressions/rune/bar/cen.udon−66 reference/hoon-expressions/rune/bar/col.udon−54 reference/hoon-expressions/rune/bar/dot.udon−74 reference/hoon-expressions/rune/bar/hep.udon−62 reference/hoon-expressions/rune/bar/ket.udon−65 reference/hoon-expressions/rune/bar/sig.udon−45 reference/hoon-expressions/rune/bar/tar.udon−72 reference/hoon-expressions/rune/bar/tis.udon−66 reference/hoon-expressions/rune/bar/vat.udon−39 reference/hoon-expressions/rune/bar/wut.udon−48 reference/hoon-expressions/rune/bus.udon+397−1 reference/hoon-expressions/rune/bus/base.udon−23 reference/hoon-expressions/rune/bus/cab.udon−42 reference/hoon-expressions/rune/bus/cen.udon−37 reference/hoon-expressions/rune/bus/col.udon−40 reference/hoon-expressions/rune/bus/hep.udon−34 reference/hoon-expressions/rune/bus/ket.udon−40 reference/hoon-expressions/rune/bus/sig.udon−69 reference/hoon-expressions/rune/bus/tis.udon−41 reference/hoon-expressions/rune/bus/vat.udon−43 reference/hoon-expressions/rune/bus/wut.udon−48 reference/hoon-expressions/rune/cen.udon+495−1 reference/hoon-expressions/rune/cen/cab.udon−69 reference/hoon-expressions/rune/cen/col.udon−60 reference/hoon-expressions/rune/cen/dot.udon−47 reference/hoon-expressions/rune/cen/hep.udon−55 reference/hoon-expressions/rune/cen/ket.udon−41 reference/hoon-expressions/rune/cen/lus.udon−43 reference/hoon-expressions/rune/cen/sig.udon−58 reference/hoon-expressions/rune/cen/tar.udon−69 reference/hoon-expressions/rune/cen/tis.udon−73 reference/hoon-expressions/rune/col.udon+263−1 reference/hoon-expressions/rune/col/cab.udon−27 reference/hoon-expressions/rune/col/col.udon−25 reference/hoon-expressions/rune/col/hep.udon−54 reference/hoon-expressions/rune/col/ket.udon−33 reference/hoon-expressions/rune/col/lus.udon−32 reference/hoon-expressions/rune/col/sig.udon−50 reference/hoon-expressions/rune/col/tar.udon−56 reference/hoon-expressions/rune/constants.udon+197−1 reference/hoon-expressions/rune/constants/cold.udon−41 reference/hoon-expressions/rune/constants/path.udon−35 reference/hoon-expressions/rune/constants/text.udon−54 reference/hoon-expressions/rune/constants/warm.udon−76 reference/hoon-expressions/rune/dot.udon+233−1 reference/hoon-expressions/rune/dot/ket.udon−80 reference/hoon-expressions/rune/dot/lus.udon−36 reference/hoon-expressions/rune/dot/tar.udon−49 reference/hoon-expressions/rune/dot/tis.udon−50 reference/hoon-expressions/rune/dot/wut.udon−28 reference/hoon-expressions/rune/ket.udon+414−3 reference/hoon-expressions/rune/ket/bar.udon−42 reference/hoon-expressions/rune/ket/col.udon−42 reference/hoon-expressions/rune/ket/dot.udon−47 reference/hoon-expressions/rune/ket/hep.udon−50 reference/hoon-expressions/rune/ket/lus.udon−25 reference/hoon-expressions/rune/ket/pad.udon−59 reference/hoon-expressions/rune/ket/sig.udon−28 reference/hoon-expressions/rune/ket/tar.udon−57 reference/hoon-expressions/rune/ket/tis.udon−42 reference/hoon-expressions/rune/ket/wut.udon−41 reference/hoon-expressions/rune/lus.udon+178−1 reference/hoon-expressions/rune/lus/bar.udon−54 reference/hoon-expressions/rune/lus/bus.udon−44 reference/hoon-expressions/rune/lus/lus.udon−41 reference/hoon-expressions/rune/lus/tar.udon−47 reference/hoon-expressions/rune/mic.udon+393−2 reference/hoon-expressions/rune/mic/col.udon−56 reference/hoon-expressions/rune/mic/lus.udon−65 reference/hoon-expressions/rune/mic/mic.udon−48 reference/hoon-expressions/rune/mic/net.udon−23 reference/hoon-expressions/rune/mic/sig.udon−104 reference/hoon-expressions/rune/mic/tar.udon−58 reference/hoon-expressions/rune/mic/tis.udon−53 reference/hoon-expressions/rune/sig.udon+488−1 reference/hoon-expressions/rune/sig/ban.udon−41 reference/hoon-expressions/rune/sig/bar.udon−35 reference/hoon-expressions/rune/sig/bus.udon−29 reference/hoon-expressions/rune/sig/cab.udon−35 reference/hoon-expressions/rune/sig/cen.udon−95 reference/hoon-expressions/rune/sig/led.udon−35 reference/hoon-expressions/rune/sig/lus.udon−46 reference/hoon-expressions/rune/sig/net.udon−33 reference/hoon-expressions/rune/sig/pad.udon−41 reference/hoon-expressions/rune/sig/tis.udon−38 reference/hoon-expressions/rune/sig/wut.udon−44 reference/hoon-expressions/rune/sig/zap.udon−38 reference/hoon-expressions/rune/terminators.udon+77−1 reference/hoon-expressions/rune/terminators/hephep.udon−35 reference/hoon-expressions/rune/terminators/tistis.udon−47 reference/hoon-expressions/rune/tis.udon+520−1 reference/hoon-expressions/rune/tis/ban.udon−28 reference/hoon-expressions/rune/tis/bar.udon−37 reference/hoon-expressions/rune/tis/col.udon−35 reference/hoon-expressions/rune/tis/com.udon−41 reference/hoon-expressions/rune/tis/dot.udon−42 reference/hoon-expressions/rune/tis/hep.udon−35 reference/hoon-expressions/rune/tis/ket.udon−46 reference/hoon-expressions/rune/tis/led.udon−43 reference/hoon-expressions/rune/tis/lus.udon−37 reference/hoon-expressions/rune/tis/mic.udon−35 reference/hoon-expressions/rune/tis/net.udon−55 reference/hoon-expressions/rune/tis/sig.udon−41 reference/hoon-expressions/rune/tis/tar.udon−39 reference/hoon-expressions/rune/tis/wut.udon−41 reference/hoon-expressions/rune/wut.udon+578−5 reference/hoon-expressions/rune/wut/ban.udon−44 reference/hoon-expressions/rune/wut/bar.udon−45 reference/hoon-expressions/rune/wut/col.udon−54 reference/hoon-expressions/rune/wut/dot.udon−43 reference/hoon-expressions/rune/wut/hep.udon−68 reference/hoon-expressions/rune/wut/ket.udon−39 reference/hoon-expressions/rune/wut/led.udon−44 reference/hoon-expressions/rune/wut/lus.udon−63 reference/hoon-expressions/rune/wut/pad.udon−45 reference/hoon-expressions/rune/wut/sig.udon−33 reference/hoon-expressions/rune/wut/tis.udon−42 reference/hoon-expressions/rune/wut/vat.udon−38 reference/hoon-expressions/rune/wut/zap.udon−40 reference/hoon-expressions/rune/zap.udon+219−1 reference/hoon-expressions/rune/zap/ban.udon−36 reference/hoon-expressions/rune/zap/col.udon−38 reference/hoon-expressions/rune/zap/dot.udon−50 reference/hoon-expressions/rune/zap/tis.udon−47 reference/hoon-expressions/rune/zap/wut.udon−31 reference/hoon-expressions/rune/zap/zap.udon−29
getting-started.udon+107−25
@@ -61,8 +61,9 @@ It can be run in Firefox on all platforms, and also in Chrome if you're using
6161a Mac.
6262
6363Importantly, Bridge also allows you to generate a keyfile that
64−you will need to boot your ship on the Arvo network for the first time. Once
65−you boot a ship with a keyfile, you can restart it later without the keyfile.
64+
65+you will need to boot your ship on the Arvo network for the first time. Once you boot a ship
66+with a keyfile, you can restart it later without the keyfile.
6667
6768*Note* Bridge allows you to make _writes_ to the blockchain, but we ask you to confirm
6869anything that will incur a transaction cost. If you plan to do anything heavy-duty, make
@@ -138,7 +139,7 @@ But first, some terminology:
138139- `arvo`: the deterministic OS that lives in a directory whose name matches your Azimuth point, ie `~famreb-todmec` lives in `/famreb-todmec`
139140
140141Arvo runs nicely on a Unix-like operating system -- Ubuntu,
141−Fedora, macOS, and FreeBSD. If you're using Windows, you'll need
142+Fedora, macOS, and FreeBSD, for example. If you're using Windows, you'll need
142143to get one of the aforementioned systems. Don't worry: most of them are free.
143144
144145We have different installation instructions for different platforms. To install
@@ -152,6 +153,29 @@ with the line below:
152153Urbit: a personal server operating function
153154```
154155
156+### Dependencies
157+
158+Urbit depends on:
159+
160+
161+```
162+C compiler (gcc or clang)
163+curses
164+git
165+gmp
166+libcurl
167+libsigsegv
168+libuv
169+meson
170+ninja
171+openssl
172+pkg-config
173+python2
174+zlib
175+```
176+
177+### Instructions
178+
155179#### MacOS
156180
157181We recommend using the Homebrew package manager to run Arvo on MacOS.
@@ -160,7 +184,7 @@ We recommend using the Homebrew package manager to run Arvo on MacOS.
160184# Bash
161185
162186brew update
163−brew install autoconf automake cmake gcc git gmp libsigsegv libtool meson ninja pkg-config python2 openssl re2c
187+brew install gcc git gmp libsigsegv libtool meson ninja pkg-config python2 openssl
164188git clone https://github.com/urbit/urbit
165189cd urbit
166190./scripts/bootstrap
@@ -175,7 +199,7 @@ urbit
175199# Bash
176200
177201sudo apt-get update
178−sudo apt-get install autoconf automake cmake exuberant-ctags g++ git libcurl4-gnutls-dev libgmp3-dev libncurses5-dev libsigsegv-dev libssl-dev libtool make openssl pkg-config python python3 python3-pip ragel re2c zlib1g-dev
202+sudo apt-get install g++ git libcurl4-gnutls-dev libgmp3-dev libncurses5-dev libsigsegv-dev libssl-dev make openssl pkg-config python python3 python3-pip zlib1g-dev
179203sudo -H pip3 install --upgrade pip
180204sudo -H pip3 install meson==0.29
181205
@@ -185,12 +209,11 @@ sudo -H pip3 install meson==0.29
185209#
186210git clone git://github.com/ninja-build/ninja.git
187211pushd ninja
188− git checkout release
189− ./configure.py --bootstrap
190− sudo cp ./ninja /usr/local/bin
212+ git checkout release
213+ ./configure.py --bootstrap
214+ sudo cp ./ninja /usr/local/bin
191215popd
192216
193−
194217git clone https://github.com/urbit/urbit
195218cd urbit
196219./scripts/bootstrap
@@ -209,15 +232,15 @@ sudo yum install autoconf automake cmake ctags gcc gcc-c++ git gmp-devel libcurl
209232
210233# meson requires python 3.5; RHEL supplies wrong version
211234pushd /usr/src
212− sudo wget https://www.python.org/ftp/python/3.5.5/Python-3.5.5.tgz
213− sudo tar xzf Python-3.5.5.tgz
214− cd Python-3.5.5
215− sudo ./configure --enable--optimizations
216− sudo make altinstall
217− which python3.5
218− cd /usr/local/bin
219− sudo ln -s python3.5 python3
220− hash python3
235+ sudo wget https://www.python.org/ftp/python/3.5.5/Python-3.5.5.tgz
236+ sudo tar xzf Python-3.5.5.tgz
237+ cd Python-3.5.5
238+ sudo ./configure --enable--optimizations
239+ sudo make altinstall
240+ which python3.5
241+ cd /usr/local/bin
242+ sudo ln -s python3.5 python3
243+ hash python3
221244popd
222245
223246curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
@@ -245,7 +268,7 @@ urbit
245268# Bash
246269
247270sudo pacman -Syu
248−sudo pacman -S autoconf automake cmake curl gcc git gmp libsigsegv libtool ncurses ninja openssl python ragel re2c
271+sudo pacman -S curl gcc git gmp libsigsegv ncurses ninja openssl python
249272curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
250273sudo python3 get-pip.py
251274git clone https://github.com/urbit/urbit
@@ -256,11 +279,71 @@ sudo ninja -C ./build/ meson-install
256279urbit
257280```
258281
259−If you just want to use a fake ship for development purposes, you can now use
282+##### FreeBSD
283+
284+```
285+# Bash or Sh
286+
287+pkg upgrade
288+sudo pkg install curl gcc git gmake gmp libsigsegv python python3 ncurses openssl gmp
289+curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
290+sudo python3 get-pip.py
291+sudo -H pip install --upgrade pip
292+sudo -H pip install meson
293+sudo pkg install ninja
294+git clone https://github.com/urbit/urbit
295+cd urbit
296+sh ./scripts/bootstrap
297+sh ./scripts/build
298+sudo ninja -C ./build/ meson-install
299+urbit
300+```
301+
302+##### Amazon Web Services
303+
304+```
305+# Bash
306+
307+sudo yum update
308+sudo yum install gcc gcc-c++ git gmp-devel libcurl-devel libsigsegv-devel ncurses-devel openssl openssl-devel pkgconfig python2 python3 python3-pip wget git
309+sudo env "PATH=$PATH" pip3 install --upgrade pip
310+sudo env "PATH=$PATH" pip3 install meson
311+
312+
313+# we need libsigsegv
314+#
315+
316+wget http://dl.fedoraproject.org/pub/fedora/linux/releases/25/Everything/x86_64/os/Packages/l/libsigsegv-2.10-10.fc24.x86_64.rpm
317+wget http://dl.fedoraproject.org/pub/fedora/linux/releases/25/Everything/x86_64/os/Packages/l/libsigsegv-devel-2.10-10.fc24.x86_64.rpm
318+sudo yum localinstall libsigsegv-2.10-10.fc24.x86_64.rpm
319+sudo yum localinstall libsigsegv-devel-2.10-10.fc24.x86_64.rpm
320+
321+git clone git://github.com/ninja-build/ninja.git
322+pushd ninja
323+ git checkout release
324+ ./configure.py --bootstrap
325+ sudo cp ./ninja /usr/local/bin
326+popd
327+
328+
329+git clone https://github.com/urbit/urbit
330+cd urbit
331+./scripts/bootstrap
332+./scripts/build
333+sudo env "PATH=$PATH" ninja -C ./build/ install
334+
335+urbit
336+```
337+
338+### Using a Fake Ship
339+
340+Perhaps you want to boot a ship without an identity. We recommend doing that
341+for development purposes, or if you just want to play around with an
342+un-networked ship without getting a point. You can now use
260343the command of the scheme below to boot a fake `~zod`.
261344
262345```
263−urbit -F zod -A /path/to/arvo -s -c zod
346+urbit -F zod
264347```
265348
266349If you want to get on the Arvo network with your point, then continue to the
@@ -302,15 +385,14 @@ keyfile:
302385urbit -w ~sample-planet -k path/to/my-planet.key
303386```
304387
305−if you'd prefer to copy your key in you can run
388+Or, if you'd prefer to copy your key in, you can run:
306389
307390```
308391urbit -w ~sample-planet -G rAnDoMkEy
309392```
310393
311−
312−This will create a directory called `sample-planet/` and begin building your
313−ship. It may take a few minutes.
394+Either command will create a directory called `sample-planet/` and begin
395+building your ship. It may take a few minutes.
314396
315397When your ship is finished booting, you will see the `~sample-planet:dojo>`
316398prompt. At that point, you should permanently erase your keyfile from your
introduction/contributing.udon+5−3
@@ -15,6 +15,8 @@ If you're interested in contributing, but don't know where to start, feel free t
1515
1616Our official guide to contributing can be found
1717[here](https://github.com/urbit/urbit/blob/master/CONTRIBUTING.md),
18−which is most useful for large and low-level changes. For a good example of
19−preferred Hoon coding style, see
20−[ford.hoon](https://github.com/urbit/arvo/blob/master/sys/vane/ford.hoon).
18+which is most useful for large and low-level changes.
19+
20+Before contributing code, you should familiarize yourself with the
21+[Hoon style guide](/docs/learn/arvo/style). For a good example of preferred Hoon
22+coding style, see [ford.hoon](https://github.com/urbit/arvo/blob/master/sys/vane/ford.hoon).
learn/arvo/arvo-internals/admin.udon−20
@@ -179,23 +179,3 @@ Urbit network.
179179
180180When this happens, back up any files you'd like to save, shut down your
181181urbit and recreate it (as if you were starting for the first time).
182−
183−## Creating SSL certificates
184−
185−It is possible to create SSL certificates so that you serve files through your
186−ship's webserver using https. To do that you, would need a machine that has
187−OpenSSL installed. In order to create a new private key and a self-signed
188−certificate for your localhost, valid for a year, you can issue the following
189−commands:
190−
191−```
192−$ openssl req -x509 -sha256 -newkey rsa:4096 -keyout private.pem -out certificate.pem -subj '/CN=localhost' -days 365
193−$ mkdir -p your-urbit/.urb/tls
194−$ mv private.pem certificate.pem your-urbit/.urb/tls
195−```
196−
197−These certificates would have to be manually trusted by your browser, and it's
198−advisable that they are used only for your localhost.
199−For public-facing webservers, it would be better to create certificates for your
200−fully qualified domain name using a trusted certificate authority like Let's
201−Encrypt.
learn/arvo/arvo-internals/ames.udon+1987−1
@@ -27,4 +27,1990 @@ routing is handled entirely in `%ames`. Finally, the actual `%ames`
2727protocol itself, including how to route incoming packets to the correct
2828vane or app, is defined in `%ames`.
2929
30−;list;
30+;=
31+ ;h2
32+ ;div(id "commentary"): Commentary
33+ ==
34+==
35+
36+`%ames` is our networking protocol.
37+
38+First we give commentary on the code, the algorithms involved, and the
39+protocol. We trace through the code touched when a packet is sent,
40+received, acknowledged, and that acknowledgment applied. This is fairly
41+comprehensive, and contains many implementation details, but if you
42+understand this, then you understand `%ames`.
43+
44+If you've scrolled down this page, you may be intimidated by the amount
45+of Hoon code, especially if you are new to the language. Don't be afraid
46+of it, you don't have to read any of it if you don't want to -- every
47+interesting action the code takes is explained in plain English. In
48+fact, if you are new to the language, this may be a good learning
49+opportunity. Even if you don't understand every line of Hoon code,
50+you'll hopefully be able to follow most lines. By the time you've worked
51+through this, you'll have seen many common patterns and best practices.
52+Hoon, much more than other languages, is best learned by reading and
53+understanding large quantities of existing code. In this way, it is
54+similar to learning a natural language. All of this code is in
55+`arvo/ames.hoon`.
56+
57+After the commentary, we have reference documentation for all the data
58+structures that are specific to `%ames`. If you see a data structure or
59+a variable used that you don't recognize, search for it in the code, and
60+it's very likely defined in one of these data structures. We recommend
61+that another tab is kept open for easy access to the data structure
62+reference documentation. The code for these is split between
63+`arvo/ames.hoon` and `arvo/zuse.hoon`.
64+
65+The Lifecycle of a Packet (or, How a Packet Becomes Law)
66+
67+---
68+
69+Here, we will trace a packet as it makes its way through ames. There are
70+actually two pathways through ames: the legacy path through `%want`, and
71+the modern way, entered through `%wont`, with full end-to-end
72+acknowledgments. Here we will only trace the modern way, though much of
73+the path is the same for both.
74+
75+When an app (or a vane) wishes to send a packet to another ship, it must
76+send a `%wont` card:
77+
78+```
79+ [%wont p=sock q=path r=*] :: e2e send message
80+```
81+
82+This card takes three arguments. The `p` is a `sock`, that is, a pair of
83+two ships, the first of which is the sender and the second is the
84+receiver. But wait, you ask, why do I get to decide who is the sender?
85+Can I fake like I'm someone else? The reason is that there are
86+potentially multiple ships on the same pier, and the kernel can send a
87+message from any of them. If you attempt to send a message from a ship
88+not on your pier, then ames will refuse to send it. If you hack around
89+in your own copy of ames to go ahead and send it anyway, then the other
90+ship will reject it because your key is bad. Only send messages from
91+yourself.
92+
93+The `q` is a path, representing the place on the other side that you
94+want to receive your message. It is approximately equivalent to a port
95+number. Messages on the same path are guaranteed to arrive in the same
96+order as they were sent. No such guarantees are made across paths.
97+
98+The `r` is the actual data that you are sending. As the type implies,
99+this can be an arbitrary noun, and it will be transferred to the
100+receiver exactly as-is, in a well-typed way. Of course, this is data
101+that is sent over the wire, so be careful not to send anything too
102+massive unless you're willing to wait.
103+
104+But enough about the interface. Grepping in ames.hoon for `%wont`, we
105+find that it appears in exactly two places: at its definition in
106+`++kiss`, and in `++knob`, where it is handled. We see that we go
107+directly into `++wise:am`.
108+
109+```
110+ ++ wise :: wise:am
111+ |= [soq=sock hen=duct cha=path val=* ete=?] :: send a statement
112+ ^- [p=(list boon) q=fort]
113+ zork:zank:(wool:(ho:(um p.soq) q.soq) hen cha val ete)
114+```
115+
116+The inputs to this gate are exactly the sort of thing you'd expect. In
117+particular, everything in the `%wont` gate is here plus the calling duct
118+so that we know where to send the acknowledgment and `ete` to determine
119+if we're going to do the modern end-to-end acknowledgments.
120+
121+The actual line of code looks intimidating, but it's really not all that
122+bad. Working from the inside out, the call to `++um` sets up our
123+domestic server, and the call to `++ho` sets up our knowledge about the
124+neighbor we're sending to. From the outside, `++zork` and `++zank` just
125+apply the changes made to our `++um` and `++am` cores, respectively. If
126+you're familiar with the common idiom of `++abet`, that's all this is.
127+The code predates the widespread usage of that name.
128+
129+The interesting part, then, is in `++wool:ho:um:am`. Let's look at the
130+code.
131+
132+```
133+ ++ wool :: wool:ho:um:am
134+ |= [hen=duct cha=path val=* ete=?] :: send a statement
135+ ^+ +>
136+ =+ ^= rol ^- rill
137+ =+ rol=(~(get by ryl.bah) cha)
138+ ?~(rol *rill u.rol)
139+ =+ sex=sed.rol
140+ :: ~& [%tx [our her] cha sex]
141+ =. ryl.bah
142+ %+ ~(put by ryl.bah) cha
143+ rol(sed +(sed.rol), san (~(put by san.rol) sex hen))
144+ =+ cov=[p=p:sen:gus q=clon:diz]
145+ %+ wind [cha sex]
146+ ?: ete
147+ [%bund q.cov cha sex val]
148+ [%bond q.cov cha sex val]
149+```
150+
151+This is slightly more complicated, but it's still not all that bad. Our
152+inputs, at least, are fairly obvious.
153+
154+If you glance at the code for a second, you'll see that
155+`++wind:ho:um:am` seems to be able to send a message, or `++meal`, given
156+a `++soup`. This gate, then, just sets up the things we need to for
157+`++wind` to do its job.
158+
159+We first get `rol`, which is a `++rill`, that is, a particular outbound
160+stream. This stream is specific to the path on which we're sending. If
161+the path hasn't been used before, then we create it. We let `sex` be the
162+number of messages we've already sent on this path.
163+
164+Then, we update the outbound stream by incrementing the number of
165+messages sent and placing an entry in `san.rol` that associates the
166+message number with the `duct` that sent the message. This allows us to
167+give the acknowledgment to the one who sent the message.
168+
169+We let `cov` be the current life of our crypto and our neighbor's
170+crypto. At the moment, we only need our neighbor's life, which we put
171+into the meal.
172+
173+Finally, we call `++wind:ho:um:am` with the `++soup` of the path and
174+message number and the `++meal` of the payload itself. For end-to-end
175+acknowledged messages, we use `%bund`.
176+
177+```
178+ [%bund p=life q=path r=@ud s=*] :: e2e message
179+```
180+
181+Looking at how we create the `%bund`, we can easily see what each field
182+is for.
183+
184+Following the trail a little further, we go to `++wind:ho:um:am`.
185+
186+```
187+ ++ wind :: wind:ho:um:am
188+ |= [gom=soup ham=meal]
189+ :: ~& [%wind her gom]
190+ ^+ +>
191+ =^ wyv diz (zuul:diz now ham)
192+ =^ feh puz (whap:puz now gom wyv)
193+ (busk xong:diz feh)
194+```
195+
196+`++wind` does three things: it (1) encodes the message into a list of
197+possibly-encrypted packets, (2) puts the message into the packet pump,
198+and (3) sends any packets that are ready to be sent. Yes, our nice
199+little linear run of each gate calling exactly one other interesting
200+gate is over. We'll go in order here.
201+
202+`++zuul:lax:as:go` is the what converts a `++meal` into a list of
203+actual, 1KB packets.
204+
205+```
206+ ++ zuul :: zuul:lax:as:go
207+ |= [now=@da ham=meal] :: encode message
208+ ^- [p=(list rock) q=_+>]
209+ =< weft
210+ ++ wasp :: null security
211+ ++ weft :: fragment message
212+ ++ wisp :: generate message
213+```
214+
215+For organizational purposes, `++zuul` constructs an internal core with
216+three arms. `++wasp` encodes the meal into an atom with no encryption.
217+`++wisp` encodes a meal with possible encryption (else it simply calls
218+`++wasp`). `++weft` takes the result of `++wisp` and splits it into
219+actual packets.
220+
221+```
222+ ++ wasp :: null security
223+ ^-([p=skin q=@] [%none (jam ham)])
224+```
225+
226+This simply jams the meal, wrapping it with the `skin` of `%none`,
227+meaning no encryption.
228+
229+Since `++wisp` is a little long, we'll go through it line-by-line.
230+
231+```
232+ ++ wisp :: generate message
233+ ^- [[p=skin q=@] q=_..wisp]
234+```
235+
236+`++wisp` produces a pair of a `skin` and an atom, which is the meal
237+encoded as a single atom and possibly encrypted.
238+
239+```
240+ ?: =(%carp -.ham)
241+ [wasp ..wisp]
242+```
243+
244+If the meal that we're encoding is a `%carp`, then we don't encrypt it.
245+A `%carp` meal is a partial meal, used when a message is more than 1KB.
246+Since the entire message is already encrypted, we don't need to encrypt
247+each packet individually again.
248+
249+```
250+ ?: !=(~ yed.caq.dur)
251+ ?> ?=(^ yed.caq.dur)
252+ :_ ..wisp
253+ :- %fast
254+ %^ cat 7
255+ p.u.yed.caq.dur
256+ (en:r:cluy q.u.yed.caq.dur (jam ham))
257+```
258+
259+If we have a symmetric key set up with this neighbor, then we simply use
260+it. The skin `%fast` is used to indicate a symmetric key.
261+
262+```
263+ ?: &(=(~ lew.wod.dur) |(=(%back -.ham) =(%buck -.ham)))
264+ [wasp ..wisp]
265+```
266+
267+If we do not yet have our neighbor's will, then there is no way that we
268+can seal the message so that only they may read it. If what we're
269+sending is an acknowledgment, then we go ahead and just send it in the
270+clear.
271+
272+```
273+ =^ tuy +>.$
274+ ?:(=(~ lew.wod.dur) [*code +>.$] (griz now))
275+```
276+
277+If we don't have our neighbor's will, then we "encrypt" with a key of 0.
278+If we do have their will, then we generate a new symmetric key that we
279+will propose.
280+
281+```
282+ :_ ..wisp
283+ =+ yig=sen
284+ =+ bil=law.saf :: XX send whole will
285+ =+ hom=(jam ham)
286+```
287+
288+`yig` will be the life and engine for our current crypto. `bil` is our
289+will. `hom` is the meal encoded as a single atom.
290+
291+```
292+ ?: =(~ lew.wod.dur)
293+ :- %open
294+ %^ jam
295+ [~ `life`p.yig]
296+ bil
297+ (sign:as:q.yig tuy hom)
298+```
299+
300+If we do not have our neighbor's will, then we send our current life
301+along with our will and the message. The message itself is "signed" with
302+a key of 0.
303+
304+```
305+ :- %full
306+ =+ cay=cluy
307+ %^ jam
308+ [`life`p.cay `life`p.yig]
309+ bil
310+ (seal:as:q.yig pub:ex:r.cay tuy hom)
311+ -- :: --zuul:lax:as:go
312+```
313+
314+If we do have our neighbor's will, then we send our perception of their
315+current life, our current life, our will, and the message. The message
316+is sealed with their public key so that only they can read our message.
317+
318+Once we have the message encoded as an atom, `++weft` goes to work.
319+
320+```
321+ ++ weft :: fragment message
322+ ^- [p=(list rock) q=_+>.$]
323+ =^ gim ..weft wisp
324+ :_ +>.$
325+ ^- (list rock)
326+```
327+
328+We're going to produce a list of the packets to send. First, we use the
329+aforementioned `++wisp` to get the message as an atom.
330+
331+```
332+ =+ wit=(met 13 q.gim)
333+ ?< =(0 wit)
334+```
335+
336+`wit` is the number of 1KB (2\^13 bit) blocks in the message. We assert
337+that there is at least one block.
338+
339+```
340+ ?: =(1 wit)
341+ =+ yup=(spit [our her] p.gim q.gim)
342+ [yup ~]
343+```
344+
345+If there is exactly one block, then we just call `++spit` to turn the
346+message into a packet. We'll explain what `++spit` does momentarily.
347+
348+```
349+ =+ ruv=(rip 13 q.gim)
350+ =+ gom=(shaf %thug q.gim)
351+ =+ inx=0
352+```
353+
354+If there is more than one block, then we rip it into blocks in `ruv`.
355+`gom` is a hash of the message, used as an id. `inx` is the number of
356+packets we've already made.
357+
358+```
359+ |- ^- (list rock)
360+ ?~ ruv ~
361+ =+ ^= vie
362+ %+ spit
363+ [our her]
364+ wasp(ham [%carp (ksin p.gim) inx wit gom i.ruv])
365+ :- vie
366+ $(ruv t.ruv, inx +(inx))
367+```
368+
369+Here we package each block into a packet with `++spit` and produce the
370+list of packets.
371+
372+```
373+ ++ spit :: cake to packet
374+ |= kec=cake ^- @
375+ =+ wim=(met 3 p.p.kec)
376+ =+ dum=(met 3 q.p.kec)
377+ =+ yax=?:((lte wim 2) 0 ?:((lte wim 4) 1 ?:((lte wim 8) 2 3)))
378+ =+ qax=?:((lte dum 2) 0 ?:((lte dum 4) 1 ?:((lte dum 8) 2 3)))
379+ =+ wix=(bex +(yax))
380+ =+ vix=(bex +(qax))
381+ =+ bod=:(mix p.p.kec (lsh 3 wix q.p.kec) (lsh 3 (add wix vix) r.kec))
382+ =+ tay=(ksin q.kec)
383+ %+ mix
384+ %+ can 0
385+ :~ [3 1]
386+ [20 (mug bod)]
387+ [2 yax]
388+ [2 qax]
389+ [5 tay]
390+ ==
391+ (lsh 5 1 bod)
392+```
393+
394+This is how we turn a message into a real packet. This has the
395+definition of the packet format.
396+
397+`wim` is the length of the sending ship, and `dum` is the length of the
398+receiving ship. There are only five possibilities for each of those,
399+corresponding to carriers, cruisers, destroyers, yachts, and submarines.
400+These are encoded in `yax` and `qax` as 0, 0, 1, 2, and 3, respectively.
401+Thus, `wix` and `vix` are the number of bytes that must be reserved for
402+the ship names in a packet.
403+
404+Next, we construct `bod` by simply concatenating the sending ship, the
405+receiving ship, and the body of the message. Then, we get the encryption
406+mechanism from `++skin`, which may be a 0, 1, 2, or 3, and put it in
407+`tay`.
408+
409+Next, we concatenate together, bit by bit, some final metadata. We use
410+three bits for our protocol number, which is incremented modulo eight
411+when there is a continuity breach or the protocol changes. We use the
412+final twenty bits of a hash of the body (which, we suppose, makes it a
413+twenty bit hash) for error-checking. We use two bits to tell how much
414+room is used in the body for the sending ship, and another two bits for
415+the receiving ship. Finally, we use five bits to store the encryption
416+type. Note that since there are only two bits worth of encryption types,
417+there are three unused bits here. This adds up to 32 bits of header
418+data. Finally, we concatenate this onto the front of the packet. Thus,
419+we can summarize the packet header format as follows.
420+
421+```
422+ 0 1 2 3
423+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
424+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
425+ |Proto| Hash of Body |yax|qax| Crypto |
426+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
427+```
428+
429+After this, there are `yax` bits of the sender name, `qax` bits of the
430+receiver name, and up to 8192 bits of data. Thus, the maximum size of a
431+packet is achieved in a message between two submarines with 8192 bits of
432+data. This will require 32+128+128+8192 = 8480 bits, or 1060 bytes.
433+
434+This concludes our discussion of `++zuul:lax:as:go`. If you recall from
435+`++wind:ho:um:am`, the list of packets from `++zuul` is passed into
436+`++whap:pu` to update the packet pump and get any packets that can be
437+sent immediately.
438+
439+```
440+ ++ whap :: whap:pu
441+ |= [now=@da gom=soup wyv=(list rock)] :: send a message
442+ ^- [(list rock) _+>]
443+ =. pyz (~(put by pyz) gom (lent wyv))
444+ =. +>
445+ |- ^+ +>.^$
446+ ?~ wyv +>.^$
447+ %= $
448+ wyv t.wyv
449+ nus +(nus)
450+ diq (~(put by diq) (shaf %flap i.wyv) nus)
451+ puq (~(put to puq) [nus `soul`[gom 0 | ~2000.1.1 i.wyv]])
452+ ==
453+ (harv now)
454+```
455+
456+First, we put into `pyz` the id for this message and the number of its
457+packets that have not yet been acknowledged, which is of course the
458+total number of packets since we haven't even sent the packets.
459+
460+For every packet, we change three things in the state (`++shed`) of our
461+packet pump: (1) we increment `nus`, the number of packets sent; (2) we
462+put the packet number into `diq` keyed by a hash of the packet; and (3)
463+we put the packet into the packet queue, with the basic metadata of its
464+id `gom`, 0 transmissions, not live yet, last sent in the year 2000, and
465+the packet itself.
466+
467+Finally, we harvest the packet pump.
468+
469+```
470+ ++ harv :: harv:pu
471+ |= now=@da :: harvest queue
472+ ^- [(list rock) _+>]
473+ ?: =(~ puq) [~ +>(rtn ~)]
474+ ?. (gth caw nif) [~ +>]
475+ =+ wid=(sub caw nif)
476+ =| rub=(list rock)
477+ =< abet =< apse
478+ |%
479+```
480+
481+`++harv` contains a core for most of its work. The meat is in `++apse`.
482+First, though, it sets itself up. If there aren't any packets in the
483+queue, then we simply do nothing except set `rtn`, our next timeout, to
484+nil because we don't have any packets that may need to be retransmitted.
485+If we have more live (that is, sent and unacknowledged) packets than our
486+window size, then we don't do anything.
487+
488+Otherwise, we let `wid` be the width of our remaining packet window, and
489+we initialize `rub` to nil. `rub` will be the list of packets that are
490+ready to be sent. We then call `++apse` and pass the result to `++abet`.
491+`++apse` decides which packets are ready to be sent.
492+
493+```
494+ ++ apse
495+ ^+ .
496+ ?~ puq .
497+ ?: =(0 wid) .
498+ => rigt =< left
499+ ?> ?=(^ puq)
500+ ?: =(0 wid) .
501+ ?. =(| liv.q.n.puq) .
502+ :: ~& [%harv nux.q.n.puq p.n.puq]
503+ %_ .
504+ wid (dec wid)
505+ rub [pac.q.n.puq rub]
506+ nif +(nif)
507+ liv.q.n.puq &
508+ nux.q.n.puq +(nux.q.n.puq)
509+ lys.q.n.puq now
510+ ==
511+```
512+
513+If there are no remaining packets to send, or if we've filled the packet
514+window, do nothing. We call `++rigt` and `++left` to process the left
515+and right branches of the packet queue.
516+
517+Now we assert that the queue is not empty, and we again check that we
518+haven't filled the packet window. We will operate on the head of the
519+queue. If the packet is live, then do nothing. Otherwise, we go ahead
520+and send it.
521+
522+To send, we (1) decrement `wid`, our packet window width; (2) cons the
523+packet onto the `rub`, which will be returned as the list of packets to
524+send; (3) increment `nif`, the number of live packets; (4) set the
525+packet to be live; (5) increment the number of transmissions of the
526+packet; and (6) set the last sent time of the packet to now.
527+
528+```
529+ ++ left
530+ ?> ?=(^ puq)
531+ ^+(. =+(lef=apse(puq l.puq) lef(puq [n.puq puq.lef r.puq])))
532+ ++ rigt
533+ ?> ?=(^ puq)
534+ ^+(. =+(rig=apse(puq r.puq) rig(puq [n.puq l.puq puq.rig])))
535+```
536+
537+These do exactly what you would expect: they traverse the packet queue
538+so that `++apse` gets called recursively through it.
539+
540+Finally, `++abet` gets called, which resolves the changes.
541+
542+```
543+ ++ abet
544+ ?~ rub [~ +>.$]
545+ [(flop rub) +>.$(rtn [~ (add rto now)])]
546+```
547+
548+This returns the packets that we wish to send, and it updates the
549+timeout so that we know when to try resending unacknowledged packets.
550+
551+This concludes our discussion of `++whap:pu`. To finish
552+`++wind:ho:um:am`, we just need to delve into `++busk:ho:um:am`. But
553+wait, in the call to `++busk`, the first argument is `xong:diz`. What is
554+this? This, my dear reader, is one more detour, this time into
555+`++xong:lax:as:go`.
556+
557+```
558+ ++ xong :: xong:lax:as:go
559+ ^- (list ship) :: route unto
560+ =+ [fro=xen too=xeno]
561+ =+ ^= oot ^- (list ship)
562+ =| oot=(list ship)
563+ |- ^+ oot
564+ ?~ too ~
565+ ?: (lien fro |=(a=ship =(a i.too))) ~
566+ [i.too $(too t.too)]
567+ :: ~& [%xong-to [our her] (weld oot ?>(?=(^ fro) t.fro))]
568+ (weld oot ?>(?=(^ fro) t.fro))
569+```
570+
571+This gets the list of intermediate ships needed to get a packet from us
572+to our neighbor. First, we get `fro` and `too`, the "canons" of ourself
573+and our neighbor, respectively.
574+
575+What is this "canon", you ask? A canon is simply a ship plus its
576+"ancestors", as defined by `++sein`. For example, the canon of
577+`~hoclur-bicrel` is:
578+
579+```
580+ ~hoclur-bicrel/try=> (saxo ~hoclur-bicrel)
581+ ~[~hoclur-bicrel ~tasruc ~tug]
582+```
583+
584+If we follow the algorithm in `++xong`, we see that we are simply
585+creating a list of ships that form a path from our neighbor to ourself.
586+Essentially, we look through the canon of our neighbor until we find
587+something in our own cannon -- a common ancestor. Or, if we are from
588+different carriers, then there is no common ancestor. We then weld this
589+onto the tail of our own canon. In the end, this is simply a list of
590+possible ships to try to route via to get to our neighbor, ordered by
591+preferability (that is, closeness to our neighbor). We will end up
592+trying, in order, to find a lane to these.
593+
594+Now, we can finally get to `++busk:ho:um:am`.
595+
596+```
597+ ++ busk :: busk:ho:um:am
598+ |= [waz=(list ship) pax=(list rock)] :: send packets
599+ %_ +>
600+ bin
601+ |- ^+ bin
602+ ?~ pax bin
603+ $(pax t.pax, bin (weld (flop (wist:diz now waz ~ i.pax)) bin))
604+ ==
605+```
606+
607+Thankfully, `++busk` is fairly simple. We go through the list of packets
608+and convert them to `++boon`s with `++wist:lax:as:go`. These boons are
609+placed into `bin`, and they end up getting processed by `++clop` (this
610+happens in `++knob`).
611+
612+```
613+ ++ wist :: wist:lax:as:go
614+ |= $: now=@da :: route via
615+ waz=(list ,@p)
616+ ryn=(unit lane)
617+ pac=rock
618+ ==
619+ ^- (list boon)
620+ ?: =(our her) [[%ouzo *lane pac] ~]
621+ ?~ waz ~
622+ =+ dyr=?:(=(her i.waz) dur (gur i.waz))
623+ ?. ?& !=(our i.waz)
624+ ?=(^ lun.wod.dyr)
625+ ==
626+ $(waz t.waz)
627+ :_ ?: ?=(%ix -.u.lun.wod.dyr)
628+ $(waz t.waz)
629+ ~
630+ :+ %ouzo u.lun.wod.dyr
631+ ?: &(=(i.waz her) =(~ ryn)) pac
632+ =+ mal=(jam `meal`[%fore her ryn pac])
633+ %- spit
634+ ^- cake
635+ :* [our i.waz]
636+ ?~ yed.caq.dyr [%none mal]
637+ :- %fast
638+ %^ cat 7
639+ p.u.yed.caq.dyr
640+ (en:crua q.u.yed.caq.dyr mal)
641+ ==
642+```
643+
644+This takes a sample of the current time, the list of ships that we just
645+generated, a lane if we already know it, and the packet itself.
646+
647+First, if we are sending a message to ourself, then we simply create a
648+`%ouzo` boon with a bunted lane. Otherwise, if there are no routing
649+candidates, there is nothing we can do, so we return nil.
650+
651+Next, we get the `dore` of the first routing candidate. If we're looking
652+at the neighbor to whom we're trying to send the message, then we simply
653+use the `dore` that we already have. Otherwise, we get a default `dore`.
654+
655+If we're the first routing candidate, or if we have don't have a lane to
656+this candidate, then we skip this candidate and move on to the next one.
657+
658+If we have only a provisional ip address, then we try to send on it, but
659+we also try to send on later routing candidates as well. Otherwise, we
660+only send on this one candidate.
661+
662+Finally, we create the actual `%ouzo` boon. The lane is the one from our
663+`dore`. If we're sending it directly to our intended recipient, and we
664+haven't been told to use a specific lane, then we just send the packet
665+directly. Otherwise, we wrap it in a little `%fore` meal, telling the
666+intermediary to whom we wish it to be sent. If we have already set up a
667+symmetric key with the intermediary, then we encrypt it with that.
668+Otherwise, we send it in the clear.
669+
670+Now, if you recall, we have traced all the way through from the
671+beginning when, in `++knob`, the `%wont` card was handled by a call to
672+`++wise`. There is only one more step before the packet is finally sent.
673+Looking in `++knob`, we see that the resultant list of boons is passed
674+into `++clop`, which will execute the correct actions and return a list
675+of moves. In `++clop`, we see the handling of each specific boon. The
676+one we are interested in is `%ouzo`, since that is the only one we have
677+sent thus far.
678+
679+```
680+ %ouzo
681+ :: ~& [%send now p.bon `@p`(mug (shaf %flap q.bon))]
682+ :_ fox
683+ [[gad.fox [%give %send p.bon q.bon]] ~]
684+```
685+
686+Very simply, we give a `%send` gift along the special duct that goes
687+straight into the bowels of unix. This is the last stop before we drop
688+into vere, and later libuv. And then... the world.
689+
690+The packet, after its creation, embarks on a journey across physical
691+time and space into the great unknown. Hurtling through fiber-optic
692+cables at hundreds of thousands of kilometers per second, it finally
693+arrives at our neighbor's network adapter. The adapter tells unix, unix
694+tells libuv, libuv tells vere, and vere sends a `%hear` kiss to ames.
695+And now we reenter the kernel.
696+
697+The `%hear` kiss goes straight to `++knob`, just as did the `%wont` kiss
698+earlier.
699+
700+```
701+ %hear
702+ (~(gnaw am [now fox]) %good p.kyz q.kyz)
703+```
704+
705+Here, though, we call `++gnaw:am` to process the packet. The arguments
706+to `++gnaw` are the same as those to the `%hear` kiss: the lane on which
707+the packet was received and the packet itself. The other argument is
708+just `%good`, which is a `++cape` saying that we expect the packet to
709+succeed. If a formal error occurs, then since we have a transactional
710+event system, the `%hear` event will never be considered to have
711+actually happened, and unix will send a `%hole` kiss so that we may send
712+a negative acknowledgment.
713+
714+```
715+ ++ gnaw :: gnaw:am
716+ |= [kay=cape ryn=lane pac=rock] :: process packet
717+ ^- [p=(list boon) q=fort]
718+ ?. =(2 (end 0 3 pac)) [~ fox]
719+ =+ kec=(bite pac)
720+ ?: (goop p.p.kec) [~ fox]
721+ ?. (~(has by urb.ton.fox) q.p.kec)
722+ [~ fox]
723+ =< zork
724+ =< zank
725+ %- ~(chew la:(ho:(um q.p.kec) p.p.kec) kay ryn %none (shaf %flap pac))
726+ [q.kec r.kec]
727+```
728+
729+First, we check the protocol number. If it is not correct, then we
730+simply ignore the packet entirely. Otherwise, we parse the packet with
731+`++bite`, which converts a packet atom into a `cake`, that is, a triple
732+of the `sock` (pair of sender and receiver), the `skin` (encryption
733+type), and the data.
734+
735+```
736+ ++ bite :: packet to cake
737+ |= pac=rock ^- cake
738+ =+ [mag=(end 5 1 pac) bod=(rsh 5 1 pac)]
739+ =+ :* vez=(end 0 3 mag) :: protocol version
740+ chk=(cut 0 [3 20] mag) :: checksum
741+ wix=(bex +((cut 0 [23 2] mag))) :: width of receiver
742+ vix=(bex +((cut 0 [25 2] mag))) :: width of sender
743+ tay=(cut 0 [27 5] mag) :: message type
744+ ==
745+ ?> =(2 vez)
746+ ?> =(chk (end 0 20 (mug bod)))
747+ :+ [(end 3 wix bod) (cut 3 [wix vix] bod)]
748+ (kins tay)
749+ (rsh 3 (add wix vix) bod)
750+```
751+
752+This is exactly the inverse of `++spit`. Note that here we check both
753+the protocol number and the hash, crashing on error. Remember that a
754+crash will result in a negative acknowledgment being sent.
755+
756+Continuing in `++gnaw`, we see that if the intended recipient is not on
757+our pier, then we drop the packet.
758+
759+If we've gotten this far, then we wish to process the packet. Recall
760+that `++ho` and `++um` set up the domestic server and foreign client
761+cores, respectively, and that `++zork` and `++zank` resolve any changes
762+to these cores.
763+
764+The new stuff here, then, is the `++la` core and the `++chew` arm. The
765+`++la` sets up a core for this particular packet, containing the current
766+success/failure `cape`, the lane it was sent on, the encryption type,
767+and a hash of the packet, used as an id.
768+
769+`++chew` is called with the encryption type and the message itself. It
770+contains a little helper core inside of it, which starts immediately
771+with `++apse`.
772+
773+```
774+ ++ apse
775+ ^+ +>.$
776+ =+ oub=bust:puz
777+ =+ neg==(~ yed.caq.dur.diz)
778+ =. +>.$ east
779+ =+ eng==(~ yed.caq.dur.diz)
780+ =+ bou=bust:puz
781+ =. bin
782+ ?. &(oub !bou) bin
783+ :_(bin [%wine [our her] " is ok"])
784+ =. bin
785+ ?. &(neg !eng) bin
786+ :_(bin [%wine [our her] " is your neighbor"])
787+ +>.$
788+```
789+
790+First, we let `oub` be true if our neighbor hasn't been responding to us
791+for more than sixteen seconds. Let `neg` be true if we haven't yet
792+proposed a symmetric key, meaning that we haven't yet corresponded with
793+this ship, so they are not our neighbor. Next, we run `++east`, which
794+we'll go into in just a minute.
795+
796+We now do the same two checks and store the results in `eng` and `bou`.
797+If our neighbor has, like the prodigal son, returned after an extended
798+absense, then we send a `%wine` boon as the proverbial fatted calf,
799+which is simply printed out to the console. Likewise, if we are meeting
800+one with whom we have never had the pleasure of acquainting ourselves,
801+we send a message to the console to that effect.
802+
803+We skipped over `++east`, which contains the meat of the processing. It
804+first decrypts the message, then calls `++chow:la:ho:um:am` with the
805+resultant meal. We'll go through each of the four cases in turn, but
806+first since each one calls `++bilk:pu`, we'll take a brief detour.
807+
808+```
809+ ++ bilk :: bilk:pu
810+ |= now=@da :: inbound packet
811+ ^+ +>
812+ =+ trt=(mul 2 rtt)
813+ %= +>.$
814+ rue [~ now]
815+ rto trt
816+ rtn ?~(puq ~ [~ (add now trt)])
817+ ==
818+```
819+
820+This updates the timing information in our packet pump. `rue`, the last
821+time we have heard from this neighbor, is set to now. `rto`, the
822+retransmit timeout is set to twice the current ping time, and if there
823+is anything in the packet queue, then we reset the next timeout, since
824+we've just heard a message.
825+
826+Back to `++east`.
827+
828+```
829+ %none
830+ =. puz (bilk:puz now)
831+ (chow ((hard meal) (cue msg)))
832+```
833+
834+The simplest case is when the encryption type is `%none`. We first call
835+`++bilk` to update the packet pump, then we cue (unjam) the message into
836+a meal. We hard cast it into a meal -- if the cast fails, then we do
837+want to crash since someone is sending us malformed data. Finally, we
838+send the result to `++chow` for interpretation and handling.
839+
840+```
841+ %fast
842+ =+ [mag=`hand`(end 7 1 msg) bod=(rsh 7 1 msg)]
843+ =+ dey=(kuch:diz mag)
844+ ?~ dey
845+ ~& [%bad-key her mag]
846+ +>.$ :: ignore unknown key
847+ =. puz (bilk:puz now)
848+ =^ key diz u.dey
849+ (chow(aut sin) ((hard meal) (cue (dy:q:sen:gus key bod))))
850+```
851+
852+For symmetric encryption, we first get the `hand`, which is the hash of
853+the symmetric key. We pass it to `++kuch:lax:as:go`, which returns the
854+key if we either have used it before or we have proposed it. If we have
855+proposed it, then we change its status from proposed to real. If
856+`++kuch` fails, then we drop the packet and print out a `%bad-key`
857+message.
858+
859+Otherwise, we call `++bilk` as before to update the packet pump and pass
860+into `++chow` the decrypted data.
861+
862+```
863+ %full
864+ =+ mex=((hard ,[p=[p=life q=life] q=will r=@]) (cue msg))
865+ =. diz (deng:diz q.mex)
866+ =+ wug=cluy:diz
867+ ?> =(q.p.mex p.wug)
868+ =+ gey=(sev:gus p.p.mex)
869+ =+ mes=(need (tear:as:q.gey pub:ex:r.wug r.mex))
870+ =. diz (wasc:diz p.mes)
871+ =. puz (bilk:puz now)
872+ (west(msg q.mes))
873+```
874+
875+For sealed asymmetric encryption, we first take off the the layer of
876+data that gives us the life and will of our neighbor, and we apply try
877+to extend their former will with the new data. `++deng` will fail if
878+this is impossible.
879+
880+Next, we get our most current understanding of our neighbor's crypto,
881+and we verify that it's the same life as what they're sending. Then, we
882+get our own crypto from `++sev` and decrypt the message with the public
883+key from our neighbor's crypto. We register the proposed symmetric key,
884+update the packet pump, and call `++west`, which simply casts the
885+message to a meal and calls `++chow`, reporting any error.
886+
887+```
888+ %open
889+ =+ mex=((hard ,[p=[~ q=life] q=will r=@]) (cue msg))
890+ =. diz (deng:diz q.mex)
891+ =+ wug=cluy:diz
892+ ?> =(q.p.mex p.wug)
893+ =+ mes=(need (sure:as:r.wug *code r.mex))
894+ =. puz (bilk:puz now)
895+ (west(msg mes))
896+```
897+
898+Finally, for signed asymmetric encryption, we, as before, take off the
899+layer of data that gives us the life and will of our neighbor. This
900+time, of course, we do not get our own crypto -- only that of our
901+neighbor.
902+
903+The rest you have seen. We call `++deng` to extend the will, we verify
904+that their crypto life is what we think it ought to be, we "decrypt" the
905+data, we update the packet pump, and we call `++west` to call `++chow`.
906+
907+```
908+ ++ chow :: chow:la:ho:um:am
909+ |= fud=meal :: interpret meal
910+ ^+ +>
911+ =. diz ?:(=(%none aut) diz (wast:diz ryn))
912+ (dine fud)
913+```
914+
915+Here, if the message was encrypted at all, then we call
916+`++wast:lax:as:go`, which simply updates the lane (route) to our
917+neighbor (unless we're given a provisional route). This ensures that we
918+always have the most direct possible path to them.
919+
920+We've been handling this meal for so long, we've almost forgotten what
921+we want to do with it. The telos is of any meal to be dined on. We will
922+choose out the cases here that are important to our current
923+investigation.
924+
925+```
926+ %fore
927+ =+ ^= lyn ^- lane
928+ ?~ q.fud ryn
929+ ?. ?=(%if -.u.q.fud) u.q.fud
930+ [%ix +.u.q.fud]
931+ :: u.q.fud
932+ ?: =(our p.fud)
933+ (emit %mead lyn r.fud)
934+ =+ zid=(myx:gus p.fud)
935+ (emir (wist:zid now xong:zid [~ lyn] r.fud))
936+```
937+
938+Forwarding is the simplest case, since we've seen all the arms before,
939+except perhaps `++emit` and `++emir`, which simply take a boon or list
940+of boons respectively and queue them up to be handled when the core
941+resolves. If we're told to forward a packet to ourselves, then we emit a
942+`%mead` boon which simply sends another `%hear` kiss to ourselves with
943+the data. Otherwise, we try to find a route to the recipient, as before.
944+
945+```
946+ %carp
947+ =+ zol=(~(get by olz.weg) s.fud)
948+ ?^ zol cock(kay u.zol)
949+ =^ neb nys.weg
950+ =+ neb=(~(get by nys.weg) s.fud)
951+ ?^ neb [u.neb nys.weg]
952+ =+ neb=`bait`[(kins p.fud) 0 r.fud ~]
953+ [neb (~(put by nys.weg) s.fud neb)]
954+ ?> (lth q.fud p.r.neb)
955+ ?> =((kins p.fud) p.neb)
956+ ?> =(r.fud p.r.neb)
957+ =+ doy=`(unit ,@)`(~(get by q.r.neb) q.fud)
958+ ?^ doy cock
959+ => ^+ . %= .
960+ q.r.neb (~(put by q.r.neb) q.fud t.fud)
961+ q.neb +(q.neb)
962+ ==
963+ :: ~& [%carp q.fud s.fud q.neb p.r.neb]
964+ ?: =(q.neb p.r.neb)
965+ =: nys.weg (~(del by nys.weg) s.fud)
966+ olz.weg (~(put by olz.weg) s.fud kay)
967+ ==
968+ (golf p.neb r.neb)
969+ =. +>.$ cock
970+ +>.$(nys.weg (~(put by nys.weg) s.fud neb))
971+```
972+
973+Here, we have received a partial message, and we're just assembling the
974+individual packets into a message. Most of this code is fairly
975+algorithmic, so we'll just hit the high points. In the beginning, we
976+check if we've already received this message, and if so, we resend the
977+acknowledgment. Remember, "always ack a dupe, never ack an ack".
978+
979+In `nys.weg` we keep track of an incoming set of partial packets,
980+indexed by the `flap` hash that comes with every packet. We check to see
981+if we have already received this partial message, and if so we
982+acknowledge it. Otherwise, we put it in `nys.weg` unless this is the
983+last message, in which case we ack the last partial message, move the
984+complete message into `olz.weg`, and call `++golf`, which assembles the
985+message and calls `++chew`, to start the dance again with the complete
986+message.
987+
988+```
989+ %bund
990+ :: ~& [%bund q.fud r.fud]
991+ ?> =(p:sen:gus p.fud)
992+ (deer q.fud r.fud ?-(kay %dead ~, %good [~ s.fud]))
993+```
994+
995+What if we're just receiving a regular old, garden variety message? We
996+call `++deer` with the data from the message. If we already know that
997+the message processing will fail (that is, if we got a `%hole` card from
998+unix rather than a `%hear` card), then we don't even send the data at
999+all. Remember, if a packet fails to process, it's as if it never even
1000+arrived, except that we send a negative acknowledgment.
1001+
1002+```
1003+ ++ deer :: deer:la:ho:um:am
1004+ |= [cha=path num=@ud dut=(unit)] :: interpret message
1005+ ^+ +>
1006+ =+ rum=(fall (~(get by raz.bah) cha) *race)
1007+ %= +>.$
1008+ +>
1009+ ?. (gte num did.rum) :: always ack a dup
1010+ (cook (~(get by bum.rum) num) cha ~ ryn dam)
1011+ ?: dod.rum
1012+ (coat cha rum(mis (~(put by mis.rum) num [kay ryn dam dut])))
1013+ %= +>.+>.$
1014+ raz.bah
1015+ %+ ~(put by raz.bah) cha
1016+ rum(mis (~(put by mis.rum) num [kay ryn dam dut]))
1017+ ==
1018+ ==
1019+```
1020+
1021+First, we get the race for this particular triple of sender, receiver,
1022+and path, creating it if it doesn't exist. If we've already acked the
1023+message, then we resend the ack. Note that `did.rum` is the number of
1024+packets we acknowledged, positively or negatively while `bum.rum` is a
1025+map of message numbers to negative acknowledgments. Thus, if a message
1026+number is less than `did.rum`, then if it's in `bum.rum` then it was
1027+negatively acknowledged, otherwise it's postively acknowledged. Thus, we
1028+are constant in space with the number of successful messages and linear
1029+in the number of failed messages. We'll document `++cook` later on, but
1030+suffice it to say that it sends an acknowledgment. It is to end-to-end
1031+acknowledgments what `++cock` is to packet-level acknowledgments.
1032+
1033+If we are still processing a message (that is, `dod.rum` is false), then
1034+we simply put this message in the map of misordered packets to be
1035+processed when their time comes. "Processing a message" in this case
1036+means that we've received the message and notified the correct
1037+application, but we're still waiting for the application-level
1038+acknowledgment.
1039+
1040+Otherwise, we're ready for a packet, so we process it.
1041+
1042+```
1043+ ++ coat :: coat:ho:um:am
1044+ |= [cha=path rum=race] :: update input race
1045+ ^+ +>
1046+ =+ cun=(~(get by mis.rum) did.rum)
1047+ ?~ cun
1048+ +>.$(raz.bah (~(put by raz.bah) cha rum))
1049+ ?. =(%good p.u.cun) +>.$
1050+ ?> ?=(^ s.u.cun)
1051+ %= +>.$
1052+ raz.bah (~(put by raz.bah) cha rum(dod |))
1053+ bin
1054+ :_ bin
1055+ :^ %mulk
1056+ [our her]
1057+ `soap`[[p:sen:gus clon:diz] cha did.rum]
1058+ u.s.u.cun
1059+ ==
1060+```
1061+
1062+First, we grab the message we want to process and store it in `cun`. If
1063+it's a good packet, then we change `dod.rum` to false, meaning that
1064+we're in the middle of processing a packet and should not start
1065+processing another one. We also put a `%mulk` boon into the queue so
1066+that, when it all resolves, we send a mesage to the intended recipient
1067+application. The boon contains the sender, the receiver, the identity of
1068+the message, and the message itself.
1069+
1070+This bubbles up all the way back to `++knob`, where we were handling the
1071+`%hear` card. Following the logic in `++knob`, we can see that the boons
1072+get sent into `++clop` to be turned into actual arvo-level moves. We've
1073+been here before, if you recall, when we handled the `%cake` boon to
1074+send a message. Now, we're handling the `%mulk` boon, which is
1075+unfortunately slightly more complicated.
1076+
1077+```
1078+ %mulk
1079+ :: ~& [%mulk p.bon q.bon]
1080+ ?> ?=([@ @ *] q.q.bon)
1081+ ?> ?=(%q i.q.q.bon)
1082+ ?+ i.t.q.q.bon
1083+ ~& %mulk-bad
1084+ :_ fox
1085+ :~ :- (claw p.p.bon)
1086+ [%sick %wart p.bon i.t.q.q.bon t.t.q.q.bon r.bon]
1087+ ==
1088+ %ge :: %gall request
1089+ ?> ?=([@ ~] t.t.q.q.bon)
1090+ =+ app=`term`(need ((sand %tas) i.t.t.q.q.bon))
1091+ =+ ^= pax
1092+ :+ (scot %p p.p.bon)
1093+ (scot %p q.p.bon)
1094+ q.q.bon
1095+ :_ fox [hen %pass pax %g %rote p.bon app r.bon]~
1096+ %gh :: %gall response
1097+ ?> ?=([@ ~] t.t.q.q.bon)
1098+ =+ app=`term`(need ((sand %tas) i.t.t.q.q.bon))
1099+ =+ ^= pax
1100+ :+ (scot %p p.p.bon)
1101+ (scot %p q.p.bon)
1102+ q.q.bon
1103+ :_ fox [hen %pass pax %g %roth p.bon app r.bon]~
1104+ ==
1105+```
1106+
1107+We're dispatching messages based on the prefix of their path. Since only
1108+`%gall` apps use end-to-end acknowledgments at the moment, every path
1109+must have at least two elements, and the first one must be `%q`. Beyond
1110+that, we handle the `/q/ge` and `/q/gh` cases for gall requests and
1111+responses, respectively.
1112+
1113+In both cases, we require the next term in the path to be the name of
1114+the intended recipient `%gall` app. Thus, a message to `/q/ge/talk` for
1115+example, will send a message to the talk app.
1116+
1117+We then send a message to the app itself. The message is either a
1118+`%rote` or a `%roth` for a request and a response, respectively. The
1119+content is the `rook` or `roon` that was sent (stored in `r.bon`), but
1120+we don't actually handle that at all here. That's completely a
1121+`%gall`-level thing. We're just the messenger.
1122+
1123+Notice the path we send this over. We encode the sender, the receiver,
1124+and the path over which it was sent. This fully specifies the `race` so
1125+that when the app gives us the acknowledgment we know where to send it.
1126+
1127+We now have another interlude. We have entrusted our precious data, so
1128+carefully guarded and guided from the app on that far-away ship, to our
1129+local app. It has the ability to do whatever it pleases with it. It may
1130+take a significant amount of time to process. When the message has been
1131+handled by this app, though, it must produce an acknowledgment. Our
1132+final task is to deliver this acknowledgment to the sending app.
1133+
1134+We should describe here what exactly these oft-mentioned acknowledgments
1135+actually consist of. There are two kinds of acknowledgments: positive
1136+and negative. A positive acknowledgment contains no data other than its
1137+existence. A negative acknowledgment may optionally include a reason for
1138+said negativity. Formally, a negative acknowledgment is an `ares`, which
1139+is a unit pair of a term and a list of tanks. If this is null, this is
1140+simply a failure with no associated information. If the pair exists, the
1141+term is a short error code that is usually both human and computer
1142+readable. For example, if you try to send a message to a valid `%gall`
1143+app that doesn't have any `++poke` to handle it, then `%gall` will give
1144+a negative acknowledgment with error term `%poke-find-fail`. The list of
1145+tanks is a human-readable description of the error. This often contains
1146+a stack trace. At any rate, all this information is returned to the
1147+sending app on the other end of the wire.
1148+
1149+After this brief interlude, our story resumes in `++knap`, where we
1150+receive responses. In particular, a `%mean` indicates a negative
1151+acknowledgment while a `%nice` indicates a positive acknowledgment.
1152+
1153+```
1154+ ?(%mean %nice)
1155+ ?> ?=([@ @ @ *] tea)
1156+ =+ soq=[(slav %p i.tea) (slav %p i.t.tea)]
1157+ =+ pax=t.t.tea
1158+ =+ ^= fuy
1159+ =< zork =< zank
1160+ %^ ~(rack am [now fox]) soq pax
1161+ ?-(+<.sih %mean `p.+.sih, %nice ~)
1162+ => %_(. fox q.fuy)
1163+ =| out=(list move)
1164+ |- ^- [p=(list move) q=_+>.^$]
1165+ ?~ p.fuy
1166+ [(flop out) +>.^$]
1167+ =^ toe fox (clop now hen i.p.fuy)
1168+ $(p.fuy t.p.fuy, out (weld (flop toe) out))
1169+```
1170+
1171+Recall the format of the path we sent the message on, and you'll
1172+understand why `soq` and `pax` are the sender/receiver pair and path on
1173+which the message was sent. The rest of this is structured much like
1174+`++knob`, so we call `++rack:am` and send the resulting boons to
1175+`++clop`. Business as usual.
1176+
1177+```
1178+ ++ rack :: rack:am
1179+ |= [soq=sock cha=path cop=coop] :: e2e ack
1180+ =+ oh=(ho:(um p.soq) q.soq)
1181+ =. oh (cook:oh cop cha ~)
1182+ (cans:oh cha)
1183+```
1184+
1185+First, we set up `++um` and `++ho`, as we've done twice before, for our
1186+domestic and foreign servers, respectively. The other two things are
1187+new, though. Well, `++cook` is not actually new, but we delayed the
1188+explanation saying only that it sends an acknowledgment. The time has
1189+come.
1190+
1191+```
1192+ ++ cook :: cook:ho:um:am
1193+ |= [cop=coop cha=path ram=(unit ,[ryn=lane dam=flap])]
1194+ ^+ +> :: acknowledgment
1195+ =+ rum=(need (~(get by raz.bah) cha))
1196+ =+ lat=(~(get by mis.rum) did.rum)
1197+ ?: &(?=(~ lat) ?=(~ ram)) ~&(%ack-late-or-redundant +>.$)
1198+ =+ ^- [ryn=lane dam=flap]
1199+ ?^ ram [ryn.u.ram dam.u.ram]
1200+ ?< ?=(~ lat)
1201+ [q r]:u.lat
1202+ =. raz.bah
1203+ ?^ ram raz.bah
1204+ %+ ~(put by raz.bah) cha
1205+ rum(dod &, bum ?~(cop bum.rum (~(put by bum.rum) did.rum u.cop)))
1206+ =^ roc diz (zuul:diz now [%buck cop dam ~s0])
1207+ (busk(diz (wast:diz ryn)) xong:diz roc)
1208+```
1209+
1210+If we are acknowledging a message that we have already acked, the `ram`
1211+will contain the new lane and flap to send the duplicate ack to. This
1212+happens if we call `++cook` in `++deer`, but it doesn't happen from
1213+`++rack`. If there is no message waiting to be acknowledged and we're
1214+not given an explicit lane and flap (that is, we're not sending a
1215+duplicate ack), then the app must have sent us multiple acknowledgments.
1216+We do the only sensible thing we can do and drop all acknowledgments
1217+after the first, printing a message. This is, in fact, an error, so it
1218+could be argued that we ought to crash. Whatever you do, don't depend on
1219+this not crashing.
1220+
1221+First, we grab the race specified by the given path, and we get the most
1222+recent in-order message, which must be the one which is being
1223+acknowledged.
1224+
1225+Then, we decide which lane/flap to respond on/to. Basically, in the
1226+usual case we respond on the lane through which the initial message was
1227+sent, which is stored along with the other packet information in
1228+`mis.rum`, since it has to be remembered across calls to ames. However,
1229+if we receive a duplicate message, then we must respond to the new
1230+message. It's quite possible the reason the other acknowledgment didn't
1231+get returned was that the lane between the ships was broken.
1232+
1233+At any rate, we update the race by saying that we've finished processing
1234+this packet (unless we're sending a duplicate ack) and, if we're sending
1235+a negative acknowledgment, putting the negative ack into `bum.rum` so
1236+that we can resend it if necessary.
1237+
1238+We encode our new message, updating the packet pump, with `++zuul`, as
1239+before, and we send it off with `++busk`, routed via `++wast` to one of
1240+the ships in `++xong`. Of course, in practice, we don't even look at the
1241+ships in `++xong` because we already have a lane directly to our
1242+neighbor (the one over which they sent their message to us).
1243+
1244+We glossed over the actual message we're sending back. We're sending a
1245+`%buck` meal, which is an acknowledgment. The `cop` specifies whether
1246+this is a positive or a negative ack, `dam` specifies the message we're
1247+acknowledging, and the `~s0` is a placeholder for the processing time
1248+required. This time is neither calculated (though it is hopefully
1249+obvious how to do so) nor used at present, but this information may be
1250+used in the future for improved congestion control. Since the round-trip
1251+time for an end-to-end acknowledged packet includes the processing time
1252+on the other end, most common congestion control algorithms will stumble
1253+when some messages take much longer to process than others. As noted,
1254+though, this is simply an opportunity for improvement -- our congestion
1255+control algorithms are relatively naive at the moment.
1256+
1257+Recall that `++busk` calls `++wist` to put the actual `%ouzo` boon in
1258+the queue, which gets handled by `++clop` to actually send the message.
1259+This is the same pipeline as sending any other message, so we'll refer
1260+you to the explanation above if you've forgotten it.
1261+
1262+The last thing we need to do on this ship is move on to the next packet
1263+in the queue if there is one. If you recall, in `++rack` after the call
1264+to `++cook` there was a call to `++cans:ho:um:am`.
1265+
1266+```
1267+ ++ cans :: cans:ho:um:am
1268+ |= cha=path
1269+ =+ rum=(need (~(get by raz.bah) cha))
1270+ =. rum
1271+ %= rum
1272+ did +(did.rum)
1273+ mis (~(del by mis.rum) did.rum)
1274+ ==
1275+ (coat cha rum)
1276+```
1277+
1278+This is very simple. We increment the number of packets that we've
1279+acknowledged on this race and we delete the packet that we just
1280+acknowledged from the set of misordered packets.
1281+
1282+Then, we call `++coat` again to process the next packet if we've already
1283+received it. And that's it for this.
1284+
1285+The acknowledgment now travels the same path that its forebearer, the
1286+original message, once tread, but this time not into the great unknown.
1287+The weary traveler is seeking out its familial roots, finding the app
1288+from whom sprung forth the original message way back in paragraph three.
1289+When it arrives at the network adapter of its ancestors, the adapter
1290+tells unix, unix tells libuv, libuv tells vere, and vere sends a `%hear`
1291+kiss to ames. Once more into the kernel.
1292+
1293+The `%hear` kiss is handled in `++knob` as before, leading to `++gnaw`,
1294+going over to `++chew`, `++apse`, `++chow`, and eventualy to `++dine`.
1295+We've seen most of the cases in `++dine`, but we haven't yet looked at
1296+the handling of this `%buck` meal.
1297+
1298+```
1299+ %buck
1300+ =. +> ?.(=(%full aut) +> cock) :: finish key exch
1301+ +>(..la (tock p.fud q.fud r.fud))
1302+```
1303+
1304+We send a packet level acknowledgment if we're finishing a key exchange,
1305+else we call `++tock` to process the acknowledgment.
1306+
1307+This will get a little involved, so if you don't much care about how
1308+exactly an acknowledgment happens, just know that the result gets gifted
1309+as a `%woot` card back to the app who sent it. For those brave souls who
1310+wish to see this thing through to the end, it's once more into the
1311+breach.
1312+
1313+```
1314+ ++ tock :: tock:ho:um:am
1315+ |= [cop=coop fap=flap cot=@dr] :: e2e ack by hash
1316+ ^+ +>
1317+ =^ yoh puz (bick:puz now fap)
1318+ =. +>.$
1319+ ?~ p.yoh +>.$
1320+ =^ hud +>.$
1321+ (done p.u.p.yoh q.u.p.yoh)
1322+ ?~ hud +>.$
1323+ %= +>.$
1324+ bin
1325+ :_ bin
1326+ `boon`[%cake [our her] [[p:sen:gus clon:diz] u.p.yoh] cop u.hud]
1327+ ==
1328+ (busk xong:diz q.yoh)
1329+```
1330+
1331+We're going to work through this one a little backwards since it's
1332+mostly fairly simple except the call to `++bick:pu`. In fact, we'll just
1333+skip `++bick` for the moment and finish the rest.
1334+
1335+If `++bick` succesfully acks the message, then we call `++done`.
1336+
1337+```
1338+ ++ done :: done:ho:um:am
1339+ |= [cha=path num=@ud] :: complete outgoing
1340+ ^- [(unit duct) _+>]
1341+ =+ rol=(need (~(get by ryl.bah) cha))
1342+ =+ rix=(~(get by san.rol) num)
1343+ ?~ rix [~ +>.$]
1344+ :- rix
1345+ %_ +>.$
1346+ ryl.bah
1347+ (~(put by ryl.bah) cha rol(san (~(del by san.rol) num)))
1348+ ==
1349+```
1350+
1351+This very simply gets the rill (the outgoing counterpart to a race, if
1352+you recall), pulls out of the map of outstanding messages the duct over
1353+which the original message was sent, and produces this duct while
1354+deleting that entry from the map of outstanding messages.
1355+
1356+Going back to `++tock`, we now have the duct we need to return the
1357+result over. We do the very sensible thing and put a `%cake` boon in the
1358+queue to be processed later by `++clop`.
1359+
1360+In `q.yoh` we have a list of messages that may need to be sent, which we
1361+pass to `++busk` to send, as usual. When an acknowledgment arrives, that
1362+may trigger other messages immediately. This often happens when sending
1363+more messages than the width of the logical window since for congestion
1364+control reasons another message cannot be sent until some of the earlier
1365+ones have been acknowledged.
1366+
1367+We'll look at the processing of the `%cake` boon in `++clop` before we
1368+get back to talking about `++bick`.
1369+
1370+```
1371+ %cake
1372+ :_ fox
1373+ :~ [s.bon %give %woot q.p.bon r.bon]
1374+ ==
1375+```
1376+
1377+We very simply give, along the duct we found above, a `%woot` card with
1378+the ship who sent us the ack and the ack itself. This allows the
1379+application to decide what to do about the result. In case of a failure,
1380+we usually either resend the message or display it to the user.
1381+Sometimes, we recognize the error term and handle it internally. In any
1382+case, the decision of how to handle the acknowledgment is entirely up to
1383+the application. Our job is done.
1384+
1385+Well, except that we skipped `++bick:pu`. Let's go back to that.
1386+
1387+```
1388+ ++ bick :: bick:pu
1389+ |= [now=@da fap=flap] :: ack by hash
1390+ ^- [[p=(unit soup) q=(list rock)] _+>]
1391+ =+ sun=(~(get by diq) fap)
1392+ ?~ sun
1393+ [[~ ~] +>.$]
1394+ =. diq (~(del by diq) fap)
1395+ =^ gub +>.$ (bock now u.sun)
1396+ =^ yop +>.$ (harv now)
1397+ [[gub yop] +>.$]
1398+```
1399+
1400+If you recall, in `++whap:pu` we created the packet pump's
1401+representation of the message, which included putting the message into
1402+`diq`, which maps from packet hashes to packet sequence numbers. Thus,
1403+`u.sun` is the sequence number of this particular message.
1404+
1405+We delete this message from `diq` since we have now received an ack for
1406+it. We call `++bock` to perform the ack by sequence number. We call
1407+`++harv` to harvest the packet queue, sending any messages that are now
1408+able to be sent.
1409+
1410+In `++bock`, there are three arms we haven't seen before: `++bine`,
1411+`+wept`, and `++beet`. We'll describe each of these before we get to
1412+`++bock`. `++bine` looks scariest.
1413+
1414+```
1415+ ++ bine :: bine:pu
1416+ |= [now=@da num=@ud] :: apply ack
1417+ ^- [(unit soup) _+>]
1418+ ?~ puq !!
1419+ ?. =(num p.n.puq)
1420+ ?: (gth num p.n.puq)
1421+ =+ lef=$(puq l.puq)
1422+ [-.lef +.lef(puq [n.puq puq.lef r.puq])]
1423+ =+ rig=$(puq r.puq)
1424+ [-.rig +.rig(puq [n.puq l.puq puq.rig])]
1425+ =: rtt ?. &(liv.q.n.puq =(1 nux.q.n.puq)) rtt
1426+ =+ gap=(sub now lys.q.n.puq)
1427+ :: ~& [%bock-trip num (div gap (div ~s1 1.000))]
1428+ (div (add (mul 2 rtt) gap) 3)
1429+ nif (sub nif !liv.q.n.puq)
1430+ ==
1431+ =+ lez=(dec (need (~(get by pyz) gom.q.n.puq)))
1432+ =^ gub pyz
1433+ ?: =(0 lez)
1434+ [[~ gom.q.n.puq] (~(del by pyz) gom.q.n.puq)]
1435+ [~ (~(put by pyz) gom.q.n.puq lez)]
1436+ :- gub
1437+ +>.$(puq ~(nap to puq))
1438+```
1439+
1440+The first few lines are simply looking through the packet queue until we
1441+find the correct packet to ack. This is basic queue manipulation that
1442+operates directly on the treap structure of the queue. If you understand
1443+treap queues, the logic is easy to follow. Otherwise, just trust us that
1444+by the time we get to the `=:`, the packet with sequence number `num` is
1445+on the top of the packet queue (that is, at `n.puq`).
1446+
1447+We first update the round-trip time. If the packet is either not alive
1448+or had to be transmitted more than once, then we don't have any reliable
1449+way of calculating the round-trip time since we're unsure of exactly
1450+which transmission was acknowledged. Otherwise, the round-trip time is
1451+the difference between now and when the packet was last sent. We set
1452+`rtt` by a little weighted average where the previous smoothed RTT is
1453+weighted twice as much as the RTT of the current packet. Thus,
1454+`(2*rtt+gap)/3`. This gives us a nice smooth RTT that is somewhat
1455+resilient to outlier data while still being responsive to our
1456+ever-changing world.
1457+
1458+If the packet wasn't already dead, then we decrement the number of live
1459+packets, which may allow more packets to be sent.
1460+
1461+We decrement the number of unacknowledged packets in our `pyz` for this
1462+particular message. If you recall, this was set in `++whap` to the
1463+number of packets required to send a message.
1464+
1465+If that was the last packet in the messge that needed to be acked, then
1466+we delete the messgae reference from `pyz` and produce the id of the
1467+message. Otherwise, we simply update `pyz` with the new number of
1468+unacked messages. In either case, we remove the packet from the packet
1469+queue.
1470+
1471+```
1472+ ++ wept :: wept:pu
1473+ |= [fip=@ud lap=@ud] :: fip thru lap-1
1474+ =< abet =< apse
1475+ |%
1476+ ++ abet +>.$
1477+ ++ apse
1478+ ^+ .
1479+ ?~ puq .
1480+ ?: (lth p.n.puq fip) ?~(l.puq . left)
1481+ ?: (gte p.n.puq lap) ?~(r.puq . rigt)
1482+ => rigt =< left
1483+ ?> ?=(^ puq)
1484+ ?.(liv.q.n.puq . .(nif (dec nif), liv.q.n.puq |))
1485+ ::
1486+ ++ left
1487+ ?> ?=(^ puq)
1488+ ^+(. =+(lef=apse(puq l.puq) lef(puq [n.puq puq.lef r.puq])))
1489+ ++ rigt
1490+ ?> ?=(^ puq)
1491+ ^+(. =+(rig=apse(puq r.puq) rig(puq [n.puq l.puq puq.rig])))
1492+ --
1493+```
1494+
1495+The algorithm is a simple case of traversing the packet queue.
1496+Essentialy, we mark as dead all packets in the queue between `fip` and
1497+`(dec lap)`. We also update `nif`, the number of live packets. Lest you
1498+mourn too much the passing of these packets, know that they shall soon
1499+rise again. Recall that in `++bick` after the call to `++bock` we call
1500+`++harv`. This will resend the packets that have just been labeled dead.
1501+
1502+```
1503+ ++ beet :: beet:pu
1504+ ^+ . :: advance unacked
1505+ =- +(nep ?~(foh nus u.foh))
1506+ ^= foh
1507+ |- ^- (unit ,@ud)
1508+ ?~ puq ~
1509+ ?: (lte p.n.puq nep) $(puq l.puq)
1510+ =+ rig=$(puq r.puq)
1511+ ?^(rig rig [~ p.n.puq])
1512+```
1513+
1514+Here we search for the next expected packet number. Basically, we search
1515+the queue for the leftmost packet whose number is greater than the
1516+current `nep`. If we don't find any such packet, we just use the total
1517+number of packets sent.
1518+
1519+We can now dive into `++bock`, our last arm.
1520+
1521+```
1522+ ++ bock :: bock:pu
1523+ |= [now=@da num=@ud] :: ack by sequence
1524+ ^- [(unit soup) _+>]
1525+ =^ gym +> (bine now num)
1526+ :- gym
1527+ ?: (gth num nep)
1528+ =+ cam=(max 2 (div caw 2))
1529+ :: ~& [%bock-hole num nep cam]
1530+ beet:(wept(nep num, cag cam, caw cam) nep num)
1531+ =. caw ?: (lth caw cag) +(caw)
1532+ (add caw !=(0 (mod (mug now) caw)))
1533+ ?: =(num nep)
1534+ :: ~& [%bock-fine num nif caw cag]
1535+ beet
1536+ :: ~& [%bock-fill num nif caw cag]
1537+ +>.$
1538+```
1539+
1540+First, we call `++bine` to apply the ack to the packet pump information.
1541+We produce `gym`, which, if it exists, is the id of the packet that was
1542+acked. If we received an ack for a packet later than the one we
1543+expected, then we halve the logical packet window and kill all the
1544+earlier packets so that they may be resent.
1545+
1546+Otherwise, we possibly increase the congestion window. If the window is
1547+less than the congestion threshold, then we increment the size of the
1548+window. Otherwise, we only increment one out of every `caw` times.
1549+
1550+If we received an ack for the packet we expected, then we simply advance
1551+`nep` with `++beet`. If we received an ack for a packet earlier than we
1552+expected, we do nothing.
1553+
1554+It may be hard to believe, but we are, in fact, done. The message has
1555+been sent, received, acknowledged, and the acknowledgment has been
1556+returned to the original sender. We hope it's clear that, while the
1557+process has been somewhat involved, the algorithms are not all that
1558+complicated. If you've read this far, you know `%ames`. The only other
1559+code involves initialization, timeouts, and the like.
1560+
1561+Below, we give detailed reference documentation for the data models
1562+involved.
1563+
1564+## Data Models
1565+
1566+### `++fort`, formal state
1567+
1568+```
1569+ ++ fort :: formal state
1570+ $: %0 :: version
1571+ gad=duct :: client interface
1572+ hop=@da :: network boot date
1573+ ton=town :: security
1574+ zac=(map ship corn) :: flows by server
1575+ == ::
1576+```
1577+
1578+This is the state of our vane. Anything that must be remembered between
1579+calls to ames must be stored in this state.
1580+
1581+`%0` is the version of the ames state model itself. If the data model
1582+`++fort` changes, then this number needs to be incremented, and an
1583+adapter must be written to upgrade the old state into the new state.
1584+Note that this is the version number of the model itself, not the
1585+contents. When the data changes, there is of course no need to change
1586+this.
1587+
1588+`gad` is a `duct` over which we send `%send` cards to unix. This card is
1589+initialized when unix sends a `%barn` card as vere starts up. Vere
1590+treats this duct specially -- don't send anything weird over it.
1591+
1592+`hop` is the network boot date. This is set when the `%kick` card is
1593+sent by vere on start up.
1594+
1595+`ton` is a `++town`, where we store all of our security/encryption
1596+state. Note that this is shared across all ships on a pier.
1597+
1598+`zac` is a map of ships to `++corn`. This stores all the per-ship state.
1599+The keys to this map are the ships on the current pier.
1600+
1601+### `++town`, all security state
1602+
1603+```
1604+ ++ town :: all security state
1605+ $: lit=@ud :: imperial modulus
1606+ any=@ :: entropy
1607+ urb=(map ship sufi) :: all keys and routes
1608+ fak=? ::
1609+ == ::
1610+```
1611+
1612+This is the security state of our pier.
1613+
1614+`lit` is unused.
1615+
1616+`any` is 256 bits of entropy. This entropy is used and updated in
1617+exactly two places: when we send a `%junk` card, and when we generate a
1618+new symmetric key in `++griz:lax:as:go`. When it is updated, it is
1619+updated by a SHA-256 hash of the current time and the old value of the
1620+entropy.
1621+
1622+`urb` is a map of ships to `++sufi`. This is where we store all the
1623+per-ship state for the pier. The keys to this map are the ships on the
1624+current pier.
1625+
1626+`fak` is true if we are on a fake network. This disables certain
1627+security checks so that anyone may run a fake `~zod`. This is used only
1628+for development. To use, run vere with the `-F` option.
1629+
1630+### `++sufi`, domestic host
1631+
1632+```
1633+ ++ sufi :: domestic host
1634+ $: hoy=(list ship) :: hierarchy
1635+ val=wund :: private keys
1636+ law=will :: server will
1637+ seh=(map hand ,[p=ship q=@da]) :: key cache
1638+ hoc=(map ship dore) :: neighborhood
1639+ == ::
1640+```
1641+
1642+This is the security state of a domestic server.
1643+
1644+`hoy` is a list of the ships directly above us in the hierarchy of
1645+ships. For example, for `~hoclur-bicrel`, this would be `~tasruc` and
1646+`~tug`. See `++sein`.
1647+
1648+`val` is a list of our private keys.
1649+
1650+`law` is our certificate, which is a list of the XXX
1651+
1652+`seh`
1653+
1654+`hoc` is a map of ships to `++dore`. The stores all the security
1655+informatoin about foreign ships. The keys to this map are the neighbors
1656+(ships we have been in contact with) of this domestic server.
1657+
1658+### `++wund`, private keys
1659+
1660+```
1661+ ++ wund (list ,[p=life q=ring r=acru]) :: mace in action
1662+```
1663+
1664+This is a list of our own private keys, indexed by life. The key itself
1665+is the `++ring`, and the `++acru` is the encryption engine. We generate
1666+the `++acru` from the private key by calling `++weur`. Thus, we can at
1667+any time regenerate our `++wund` from a `++mace`. The current crypto is
1668+at the head of the list and can be accessed with `++sen:as:go`.
1669+
1670+### `++ring`, private key
1671+
1672+```
1673+ ++ ring ,@ :: private key
1674+```
1675+
1676+This is a private key. The first byte is reserved to identify the type
1677+of cryptography. Lower-case means public key, upper-case means public
1678+key, and the letter identifies which `++acru` to use.
1679+
1680+### `++pass`, public key
1681+
1682+```
1683+ ++ pass ,@ :: public key
1684+```
1685+
1686+This is a public key. The first byte is reserved to identify the type of
1687+cryptography. Lower-case means public key, upper-case means public key,
1688+and the letter identifies which `++acru` to use.
1689+
1690+### `++mace`, private secrets
1691+
1692+```
1693+ ++ mace (list ,[p=life q=ring]) :: private secrets
1694+```
1695+
1696+This is a list of the our private keys, indexed by life. From this we
1697+can generate a `++wund` for actual use.
1698+
1699+### `++skin`, encoding stem
1700+
1701+```
1702+ ++ skin ?(%none %open %fast %full) :: encoding stem
1703+```
1704+
1705+This defines the type of encryption used for each message. `%none`
1706+refers to messages sent in the clear, `%open` refers to signed messages,
1707+`%full` refers to sealed messages, and `%fast` refers to symmetrically
1708+encrypted messages. See `++acru` for details.
1709+
1710+### `++acru`, asymmetric cryptosuite
1711+
1712+```
1713+ ++ acru :: asym cryptosuite
1714+ $_ ^? |% :: opaque object
1715+ ++ as ^? :: asym ops
1716+ |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a
1717+ ++ sign |=([a=@ b=@] _@) :: certify as us
1718+ ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us
1719+ ++ tear |= [a=pass b=@] :: accept from a
1720+ *(unit ,[p=@ q=@]) ::
1721+ -- ::
1722+ ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft
1723+ ++ dy |+([a=@ b=@] _@) :: symmetric de, hard
1724+ ++ en |+([a=@ b=@] _@) :: symmetric en
1725+ ++ ex ^? :: export
1726+ |% ++ fig _@uvH :: fingerprint
1727+ ++ pac _@uvG :: default passcode
1728+ ++ pub *pass :: public key
1729+ ++ sec *ring :: private key
1730+ --
1731+ ++ nu ^? :: reconstructors
1732+ |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed]
1733+ ++ nol |=(a=@ ^?(..nu)) :: from naked ring
1734+ ++ com |=(a=@ ^?(..nu)) :: from naked pass
1735+ --
1736+ --
1737+```
1738+
1739+This is an opaque interface for a general asymmetric cryptosuite. Any
1740+form of asymmetric cryptography can be dropped in to be used instead of
1741+the default. Right now, there are two cryptosuites, `++crua`, which is
1742+your standard RSA, and `++crub`, which is elliptic curve crypto but is
1743+mostly stubbed out at the moment.
1744+
1745+#### `++as:acru`, asymmetric operations
1746+
1747+```
1748+ ++ as ^? :: asym ops
1749+ |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a
1750+ ++ sign |=([a=@ b=@] _@) :: certify as us
1751+ ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us
1752+ ++ tear |= [a=pass b=@] :: accept from a
1753+ *(unit ,[p=@ q=@]) ::
1754+ -- ::
1755+```
1756+
1757+This is the core that defines the standard asymmetric cryptography
1758+operations.
1759+
1760+`++seal:as:acru` allows us to send a message encrypted with someone's
1761+public key so that only they may read it. If Alice seals a message with
1762+Bob's public key, then she can be sure that Bob is the only one who can
1763+read it. This is associated with the `++skin` `%full`.
1764+
1765+`++sign:as:acru` allows us to sign a message with our private key so
1766+that others can verify that we sent the message. If Alice signs a
1767+message with her private key, then Bob can verify with her public key
1768+that it was indeed Alice who sent it. This is associated with the
1769+`++skin` `%open`.
1770+
1771+`++sure:as:acru` is the dual to `++sign:as:acru`. It allows us to verify
1772+that a message we have received is indeed from the claimed sender. If
1773+Alice sends a message with her private key, then Bob can use this arm to
1774+verify that it was indeed Alice who sent it. This is associated with the
1775+`++skin` `%open`.
1776+
1777+`++tear:as:acru` is the dual to `++seal:as:acru`. It allows us to read a
1778+message that we can be sure is only read by us. If Alice seals a message
1779+with Bob's public key, then Bob can use this arm to read it. This is
1780+associated with the `++skin` `%full`.
1781+
1782+#### `++de:acru`, `++dy:acru`, and `++en:acru`, symmetric encryption/decryption
1783+
1784+```
1785+ ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft
1786+ ++ dy |+([a=@ b=@] _@) :: symmetric de, hard
1787+ ++ en |+([a=@ b=@] _@) :: symmetric en
1788+```
1789+
1790+Symmetric encryption is associated with the `++skin` `%fast`.
1791+
1792+`++de:acru` decrypts a message with a symmetric key, returning `~` on
1793+failure and `[~ u=data]` on success.
1794+
1795+`++dy:acru` decrypts a message with a symmetric key, crashing on
1796+failure. This should almost always be defined as, and should always be
1797+semantically equivalent to, `(need (de a b))`.
1798+
1799+`++en:acru` encrypts a message with a symmetric key.
1800+
1801+#### `++ex:acru`, exporting data
1802+
1803+```
1804+ ++ ex ^? :: export
1805+ |% ++ fig _@uvH :: fingerprint
1806+ ++ pac _@uvG :: default passcode
1807+ ++ pub *pass :: public key
1808+ ++ sec *ring :: private key
1809+ --
1810+```
1811+
1812+`++fig:ex:acru` is our fingerprint, usually a hash of our public key.
1813+This is used, for example, in `++zeno`, where every carrier owner's
1814+fingerprint is stored so that we can ensure that carriers are indeed
1815+owned by their owners
1816+
1817+`++pac:ex:acru` is our default passcode, which is unused at present.
1818+
1819+`++pub:ex:acru` is the `++pass` form of our public key.
1820+
1821+`++sec:ex:acru` is the `++ring` form of our private key.
1822+
1823+#### `++nu:acru`, reconstructors
1824+
1825+```
1826+ ++ nu ^? :: reconstructors
1827+ |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed]
1828+ ++ nol |=(a=@ ^?(..nu)) :: from naked ring
1829+ ++ com |=(a=@ ^?(..nu)) :: from naked pass
1830+ --
1831+```
1832+
1833+These arms allow us to reconstruct a `++acru` from basic data.
1834+
1835+`++pit:nu:acru` constructs a `++acru` from the width of our intended key
1836+and seed entropy. This is usually used in the initial construction of
1837+the `++acru`.
1838+
1839+`++nol:nu:acru` constructs a `++acru` from a "naked ring", meaning a
1840+`++ring` without the initial byte identifying the type of crypto. There
1841+is often a helper arm that that wraps this; see `++weur` for `++crua`
1842+and `++wear` for `++crub`.
1843+
1844+`++com:nu:acru` constructs a `++acru` from a "naked pass", meaning a
1845+`++ring` without the initial byte identifying the type of crypto. There
1846+is often a helper arm that that wraps this; see `++haul` for `++crua`
1847+and `++hail` for `++crub`.
1848+
1849+### `++will`, certificate
1850+
1851+```
1852+ ++ will (list deed) :: certificate
1853+```
1854+
1855+This is a list of deeds associated with the current ship. There should
1856+be an item in this list for every ship from this point up in the
1857+hierarchy times the number of lives that each ship has had. For example,
1858+\~hoclur-bicrel may have a will with three items: one for itself, one
1859+for \~tasruc (who issued \~hoclur-bicrel's deed) and one for \~tug (who
1860+issued \~tasruc's deed).
1861+
1862+### `++deed`, identity
1863+
1864+```
1865+ ++ deed ,[p=@ q=step r=?] :: sig, stage, fake?
1866+```
1867+
1868+`p` is the signature of a particular deed, which is a signed copy of
1869+`q`.
1870+
1871+`q` is the stage in the identity.
1872+
1873+`r` is true if we're working on a fake network, where we don't check
1874+that the carrier fingerprints are correct. This allows us to create fake
1875+networks for development without interfering with the real network.
1876+
1877+### `++step`, identity stage
1878+
1879+```
1880+ ++ step ,[p=bray q=gens r=pass] :: identity stage
1881+```
1882+
1883+This is a single stage in our identity. Thus, this is specific to a
1884+single life in a single ship. Everything in here may change between
1885+lives.
1886+
1887+`p`
1888+
1889+`q`
1890+
1891+`r` is the public key for this stage in the identity.
1892+
1893+### `++bray`
1894+
1895+```
1896+ ++ bray ,[p=life q=(unit life) r=ship s=@da] :: our parent us now
1897+```
1898+
1899+XXX
1900+
1901+### `++gens`, general identity
1902+
1903+```
1904+ ++ gens ,[p=lang q=gcos] :: general identity
1905+```
1906+
1907+`p` is the IETF language code for the preferred language of this
1908+identity. This is unused at the moment, but in the future text should be
1909+localized based on this.
1910+
1911+`q` is the description of the ship.
1912+
1913+### `++gcos`, identity description
1914+
1915+```
1916+ ++ gcos :: id description
1917+ $% [%czar ~] :: 8-bit ship
1918+ [%duke p=what] :: 32-bit ship
1919+ [%earl p=@t] :: 64-bit ship
1920+ [%king p=@t] :: 16-bit ship
1921+ [%pawn p=(unit ,@t)] :: 128-bit ship
1922+ == ::
1923+```
1924+
1925+This is the description of the identity of a ship. Most types of
1926+identity have a `@t` field, which is their human-readable name. The
1927+identity of a `%duke` is more involved.
1928+
1929+A `%czar`, a carrier, is a ship with an 8-bit address. Thus, there are
1930+only 256 carriers. These are at the top of the namespace hierarchy, and
1931+the fingerprint of each carrier is stored in `++zeno`. These are the
1932+"senators" of Urbit.
1933+
1934+A `%king`, a cruiser, is a ship with a 16-bit address. Thus, there are
1935+65,536 cruisers. Each carrier may issue 256 cruisers. These are the
1936+infrastructure of Urbit.
1937+
1938+A `%duke`, a destroyer, is a ship with a 32-bit address. Thus, there are
1939+4,294,967,296 destroyers. Each cruiser may issue 65,536 cruisers. These
1940+are the individuals of Urbit.
1941+
1942+A `%earl`, a yacht, is a ship with a 64-bit address. Thus, there are
1943+18,446,744,073,709,551,616 yachts. Each destroyer may issue
1944+4,294,967,296 yachts. These are the devices of Urbit.
1945+
1946+A `%pawn`, a submarine, is a ship with a 128-bit address. Thus, there
1947+are a lot of submarines. The chance of random name collision is
1948+negligible, so submarines are not issued by any ship. They must simply
1949+assert their presence, and they are all considered children of \~zod.
1950+This is the underworld of Urbit, where anonymity reigns supreme.
1951+
1952+### `++what`, logical destroyer identity
1953+
1954+```
1955+ ++ what :: logical identity
1956+ $% [%anon ~] :: anonymous
1957+ [%lady p=whom] :: female person ()
1958+ [%lord p=whom] :: male person []
1959+ [%punk p=sect q=@t] :: opaque handle ""
1960+ == ::
1961+```
1962+
1963+This is the logical identity of a destroyer.
1964+
1965+A `%anon` is a completely anonymous destroyer. The difference between
1966+this and a submarine is that a submarine is ephemeral while a `%anon`
1967+destroyer is not. Thus, we may not know who \~hoclur-bicrel is, but we
1968+do know that it's always the same person.
1969+
1970+A `%lady` is a female person. The name used here should be a real name.
1971+
1972+A `%lord` is a male person. The name used here should be a real name.
1973+
1974+A `%punk` is a person who is identified only by a handle.
1975+
1976+### `++whom`, real person
1977+
1978+```
1979+ ++ whom ,[p=@ud q=govt r=sect s=name] :: year/govt/id
1980+```
1981+
1982+Ths is the information associated with a real person. It is mostly
1983+information that could be observed with the briefest of interactions.
1984+
1985+`p` is the birth year.
1986+
1987+`q` is the location of a user, usually of the form "country/zip".
1988+
1989+`r` is the sect of the user.
1990+
1991+`s` is the real name of the person.
1992+
1993+### `++govt`
1994+
1995+```
1996+ ++ govt path :: country/postcode
1997+```
1998+
1999+This is the location of the user, usually of the form "country/zip".
2000+
2001+### `++sect`
2002+
2003+```
2004+ ++ sect ?(%black %blue %red %orange %white) :: banner
2005+```
2006+
2007+XXX
2008+
2009+### `++name`
2010+
2011+```
2012+ ++ name ,[p=@t q=(unit ,@t) r=(unit ,@t) s=@t] :: first mid/nick last
2013+```
2014+
2015+This is the given name, possible middle name/initial, possible nickname,
2016+and surname of a user.
learn/arvo/arvo-internals/ames/commentary.udondeleted−1991
@@ -1,1991 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− sort/'1'
4− title/'Ames commentary'
5− ==
6−;>
7−
8−
9−# Ames commentary
10−
11−`%ames` is our networking protocol.
12−
13−First we give commentary on the code, the algorithms involved, and the
14−protocol. We trace through the code touched when a packet is sent,
15−received, acknowledged, and that acknowledgment applied. This is fairly
16−comprehensive, and contains many implementation details, but if you
17−understand this, then you understand `%ames`.
18−
19−If you've scrolled down this page, you may be intimidated by the amount
20−of Hoon code, especially if you are new to the language. Don't be afraid
21−of it, you don't have to read any of it if you don't want to -- every
22−interesting action the code takes is explained in plain English. In
23−fact, if you are new to the language, this may be a good learning
24−opportunity. Even if you don't understand every line of Hoon code,
25−you'll hopefully be able to follow most lines. By the time you've worked
26−through this, you'll have seen many common patterns and best practices.
27−Hoon, much more than other languages, is best learned by reading and
28−understanding large quantities of existing code. In this way, it is
29−similar to learning a natural language. All of this code is in
30−`arvo/ames.hoon`.
31−
32−After the commentary, we have reference documentation for all the data
33−structures that are specific to `%ames`. If you see a data structure or
34−a variable used that you don't recognize, search for it in the code, and
35−it's very likely defined in one of these data structures. We recommend
36−that another tab is kept open for easy access to the data structure
37−reference documentation. The code for these is split between
38−`arvo/ames.hoon` and `arvo/zuse.hoon`.
39−
40−The Lifecycle of a Packet (or, How a Packet Becomes Law)
41−--------------------------------------------------------
42−
43−Here, we will trace a packet as it makes its way through ames. There are
44−actually two pathways through ames: the legacy path through `%want`, and
45−the modern way, entered through `%wont`, with full end-to-end
46−acknowledgments. Here we will only trace the modern way, though much of
47−the path is the same for both.
48−
49−When an app (or a vane) wishes to send a packet to another ship, it must
50−send a `%wont` card:
51−
52−```
53− [%wont p=sock q=path r=*] :: e2e send message
54−```
55−
56−This card takes three arguments. The `p` is a `sock`, that is, a pair of
57−two ships, the first of which is the sender and the second is the
58−receiver. But wait, you ask, why do I get to decide who is the sender?
59−Can I fake like I'm someone else? The reason is that there are
60−potentially multiple ships on the same pier, and the kernel can send a
61−message from any of them. If you attempt to send a message from a ship
62−not on your pier, then ames will refuse to send it. If you hack around
63−in your own copy of ames to go ahead and send it anyway, then the other
64−ship will reject it because your key is bad. Only send messages from
65−yourself.
66−
67−The `q` is a path, representing the place on the other side that you
68−want to receive your message. It is approximately equivalent to a port
69−number. Messages on the same path are guaranteed to arrive in the same
70−order as they were sent. No such guarantees are made across paths.
71−
72−The `r` is the actual data that you are sending. As the type implies,
73−this can be an arbitrary noun, and it will be transferred to the
74−receiver exactly as-is, in a well-typed way. Of course, this is data
75−that is sent over the wire, so be careful not to send anything too
76−massive unless you're willing to wait.
77−
78−But enough about the interface. Grepping in ames.hoon for `%wont`, we
79−find that it appears in exactly two places: at its definition in
80−`++kiss`, and in `++knob`, where it is handled. We see that we go
81−directly into `++wise:am`.
82−
83−```
84− ++ wise :: wise:am
85− |= [soq=sock hen=duct cha=path val=* ete=?] :: send a statement
86− ^- [p=(list boon) q=fort]
87− zork:zank:(wool:(ho:(um p.soq) q.soq) hen cha val ete)
88−```
89−
90−The inputs to this gate are exactly the sort of thing you'd expect. In
91−particular, everything in the `%wont` gate is here plus the calling duct
92−so that we know where to send the acknowledgment and `ete` to determine
93−if we're going to do the modern end-to-end acknowledgments.
94−
95−The actual line of code looks intimidating, but it's really not all that
96−bad. Working from the inside out, the call to `++um` sets up our
97−domestic server, and the call to `++ho` sets up our knowledge about the
98−neighbor we're sending to. From the outside, `++zork` and `++zank` just
99−apply the changes made to our `++um` and `++am` cores, respectively. If
100−you're familiar with the common idiom of `++abet`, that's all this is.
101−The code predates the widespread usage of that name.
102−
103−The interesting part, then, is in `++wool:ho:um:am`. Let's look at the
104−code.
105−
106−```
107− ++ wool :: wool:ho:um:am
108− |= [hen=duct cha=path val=* ete=?] :: send a statement
109− ^+ +>
110− =+ ^= rol ^- rill
111− =+ rol=(~(get by ryl.bah) cha)
112− ?~(rol *rill u.rol)
113− =+ sex=sed.rol
114− :: ~& [%tx [our her] cha sex]
115− =. ryl.bah
116− %+ ~(put by ryl.bah) cha
117− rol(sed +(sed.rol), san (~(put by san.rol) sex hen))
118− =+ cov=[p=p:sen:gus q=clon:diz]
119− %+ wind [cha sex]
120− ?: ete
121− [%bund q.cov cha sex val]
122− [%bond q.cov cha sex val]
123−```
124−
125−This is slightly more complicated, but it's still not all that bad. Our
126−inputs, at least, are fairly obvious.
127−
128−If you glance at the code for a second, you'll see that
129−`++wind:ho:um:am` seems to be able to send a message, or `++meal`, given
130−a `++soup`. This gate, then, just sets up the things we need to for
131−`++wind` to do its job.
132−
133−We first get `rol`, which is a `++rill`, that is, a particular outbound
134−stream. This stream is specific to the path on which we're sending. If
135−the path hasn't been used before, then we create it. We let `sex` be the
136−number of messages we've already sent on this path.
137−
138−Then, we update the outbound stream by incrementing the number of
139−messages sent and placing an entry in `san.rol` that associates the
140−message number with the `duct` that sent the message. This allows us to
141−give the acknowledgment to the one who sent the message.
142−
143−We let `cov` be the current life of our crypto and our neighbor's
144−crypto. At the moment, we only need our neighbor's life, which we put
145−into the meal.
146−
147−Finally, we call `++wind:ho:um:am` with the `++soup` of the path and
148−message number and the `++meal` of the payload itself. For end-to-end
149−acknowledged messages, we use `%bund`.
150−
151−```
152− [%bund p=life q=path r=@ud s=*] :: e2e message
153−```
154−
155−Looking at how we create the `%bund`, we can easily see what each field
156−is for.
157−
158−Following the trail a little further, we go to `++wind:ho:um:am`.
159−
160−```
161− ++ wind :: wind:ho:um:am
162− |= [gom=soup ham=meal]
163− :: ~& [%wind her gom]
164− ^+ +>
165− =^ wyv diz (zuul:diz now ham)
166− =^ feh puz (whap:puz now gom wyv)
167− (busk xong:diz feh)
168−```
169−
170−`++wind` does three things: it (1) encodes the message into a list of
171−possibly-encrypted packets, (2) puts the message into the packet pump,
172−and (3) sends any packets that are ready to be sent. Yes, our nice
173−little linear run of each gate calling exactly one other interesting
174−gate is over. We'll go in order here.
175−
176−`++zuul:lax:as:go` is the what converts a `++meal` into a list of
177−actual, 1KB packets.
178−
179−```
180− ++ zuul :: zuul:lax:as:go
181− |= [now=@da ham=meal] :: encode message
182− ^- [p=(list rock) q=_+>]
183− =< weft
184− ++ wasp :: null security
185− ++ weft :: fragment message
186− ++ wisp :: generate message
187−```
188−
189−For organizational purposes, `++zuul` constructs an internal core with
190−three arms. `++wasp` encodes the meal into an atom with no encryption.
191−`++wisp` encodes a meal with possible encryption (else it simply calls
192−`++wasp`). `++weft` takes the result of `++wisp` and splits it into
193−actual packets.
194−
195−```
196− ++ wasp :: null security
197− ^-([p=skin q=@] [%none (jam ham)])
198−```
199−
200−This simply jams the meal, wrapping it with the `skin` of `%none`,
201−meaning no encryption.
202−
203−Since `++wisp` is a little long, we'll go through it line-by-line.
204−
205−```
206− ++ wisp :: generate message
207− ^- [[p=skin q=@] q=_..wisp]
208−```
209−
210−`++wisp` produces a pair of a `skin` and an atom, which is the meal
211−encoded as a single atom and possibly encrypted.
212−
213−```
214− ?: =(%carp -.ham)
215− [wasp ..wisp]
216−```
217−
218−If the meal that we're encoding is a `%carp`, then we don't encrypt it.
219−A `%carp` meal is a partial meal, used when a message is more than 1KB.
220−Since the entire message is already encrypted, we don't need to encrypt
221−each packet individually again.
222−
223−```
224− ?: !=(~ yed.caq.dur)
225− ?> ?=(^ yed.caq.dur)
226− :_ ..wisp
227− :- %fast
228− %^ cat 7
229− p.u.yed.caq.dur
230− (en:r:cluy q.u.yed.caq.dur (jam ham))
231−```
232−
233−If we have a symmetric key set up with this neighbor, then we simply use
234−it. The skin `%fast` is used to indicate a symmetric key.
235−
236−```
237− ?: &(=(~ lew.wod.dur) |(=(%back -.ham) =(%buck -.ham)))
238− [wasp ..wisp]
239−```
240−
241−If we do not yet have our neighbor's will, then there is no way that we
242−can seal the message so that only they may read it. If what we're
243−sending is an acknowledgment, then we go ahead and just send it in the
244−clear.
245−
246−```
247− =^ tuy +>.$
248− ?:(=(~ lew.wod.dur) [*code +>.$] (griz now))
249−```
250−
251−If we don't have our neighbor's will, then we "encrypt" with a key of 0.
252−If we do have their will, then we generate a new symmetric key that we
253−will propose.
254−
255−```
256− :_ ..wisp
257− =+ yig=sen
258− =+ bil=law.saf :: XX send whole will
259− =+ hom=(jam ham)
260−```
261−
262−`yig` will be the life and engine for our current crypto. `bil` is our
263−will. `hom` is the meal encoded as a single atom.
264−
265−```
266− ?: =(~ lew.wod.dur)
267− :- %open
268− %^ jam
269− [~ `life`p.yig]
270− bil
271− (sign:as:q.yig tuy hom)
272−```
273−
274−If we do not have our neighbor's will, then we send our current life
275−along with our will and the message. The message itself is "signed" with
276−a key of 0.
277−
278−```
279− :- %full
280− =+ cay=cluy
281− %^ jam
282− [`life`p.cay `life`p.yig]
283− bil
284− (seal:as:q.yig pub:ex:r.cay tuy hom)
285− -- :: --zuul:lax:as:go
286−```
287−
288−If we do have our neighbor's will, then we send our perception of their
289−current life, our current life, our will, and the message. The message
290−is sealed with their public key so that only they can read our message.
291−
292−Once we have the message encoded as an atom, `++weft` goes to work.
293−
294−```
295− ++ weft :: fragment message
296− ^- [p=(list rock) q=_+>.$]
297− =^ gim ..weft wisp
298− :_ +>.$
299− ^- (list rock)
300−```
301−
302−We're going to produce a list of the packets to send. First, we use the
303−aforementioned `++wisp` to get the message as an atom.
304−
305−```
306− =+ wit=(met 13 q.gim)
307− ?< =(0 wit)
308−```
309−
310−`wit` is the number of 1KB (2\^13 bit) blocks in the message. We assert
311−that there is at least one block.
312−
313−```
314− ?: =(1 wit)
315− =+ yup=(spit [our her] p.gim q.gim)
316− [yup ~]
317−```
318−
319−If there is exactly one block, then we just call `++spit` to turn the
320−message into a packet. We'll explain what `++spit` does momentarily.
321−
322−```
323− =+ ruv=(rip 13 q.gim)
324− =+ gom=(shaf %thug q.gim)
325− =+ inx=0
326−```
327−
328−If there is more than one block, then we rip it into blocks in `ruv`.
329−`gom` is a hash of the message, used as an id. `inx` is the number of
330−packets we've already made.
331−
332−```
333− |- ^- (list rock)
334− ?~ ruv ~
335− =+ ^= vie
336− %+ spit
337− [our her]
338− wasp(ham [%carp (ksin p.gim) inx wit gom i.ruv])
339− :- vie
340− $(ruv t.ruv, inx +(inx))
341−```
342−
343−Here we package each block into a packet with `++spit` and produce the
344−list of packets.
345−
346−```
347− ++ spit :: cake to packet
348− |= kec=cake ^- @
349− =+ wim=(met 3 p.p.kec)
350− =+ dum=(met 3 q.p.kec)
351− =+ yax=?:((lte wim 2) 0 ?:((lte wim 4) 1 ?:((lte wim 8) 2 3)))
352− =+ qax=?:((lte dum 2) 0 ?:((lte dum 4) 1 ?:((lte dum 8) 2 3)))
353− =+ wix=(bex +(yax))
354− =+ vix=(bex +(qax))
355− =+ bod=:(mix p.p.kec (lsh 3 wix q.p.kec) (lsh 3 (add wix vix) r.kec))
356− =+ tay=(ksin q.kec)
357− %+ mix
358− %+ can 0
359− :~ [3 1]
360− [20 (mug bod)]
361− [2 yax]
362− [2 qax]
363− [5 tay]
364− ==
365− (lsh 5 1 bod)
366−```
367−
368−This is how we turn a message into a real packet. This has the
369−definition of the packet format.
370−
371−`wim` is the length of the sending ship, and `dum` is the length of the
372−receiving ship. There are only five possibilities for each of those,
373−corresponding to carriers, cruisers, destroyers, yachts, and submarines.
374−These are encoded in `yax` and `qax` as 0, 0, 1, 2, and 3, respectively.
375−Thus, `wix` and `vix` are the number of bytes that must be reserved for
376−the ship names in a packet.
377−
378−Next, we construct `bod` by simply concatenating the sending ship, the
379−receiving ship, and the body of the message. Then, we get the encryption
380−mechanism from `++skin`, which may be a 0, 1, 2, or 3, and put it in
381−`tay`.
382−
383−Next, we concatenate together, bit by bit, some final metadata. We use
384−three bits for our protocol number, which is incremented modulo eight
385−when there is a continuity breach or the protocol changes. We use the
386−final twenty bits of a hash of the body (which, we suppose, makes it a
387−twenty bit hash) for error-checking. We use two bits to tell how much
388−room is used in the body for the sending ship, and another two bits for
389−the receiving ship. Finally, we use five bits to store the encryption
390−type. Note that since there are only two bits worth of encryption types,
391−there are three unused bits here. This adds up to 32 bits of header
392−data. Finally, we concatenate this onto the front of the packet. Thus,
393−we can summarize the packet header format as follows.
394−
395−```
396− 0 1 2 3
397− 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
398− +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
399− |Proto| Hash of Body |yax|qax| Crypto |
400− +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
401−```
402−
403−After this, there are `yax` bits of the sender name, `qax` bits of the
404−receiver name, and up to 8192 bits of data. Thus, the maximum size of a
405−packet is achieved in a message between two submarines with 8192 bits of
406−data. This will require 32+128+128+8192 = 8480 bits, or 1060 bytes.
407−
408−This concludes our discussion of `++zuul:lax:as:go`. If you recall from
409−`++wind:ho:um:am`, the list of packets from `++zuul` is passed into
410−`++whap:pu` to update the packet pump and get any packets that can be
411−sent immediately.
412−
413−```
414− ++ whap :: whap:pu
415− |= [now=@da gom=soup wyv=(list rock)] :: send a message
416− ^- [(list rock) _+>]
417− =. pyz (~(put by pyz) gom (lent wyv))
418− =. +>
419− |- ^+ +>.^$
420− ?~ wyv +>.^$
421− %= $
422− wyv t.wyv
423− nus +(nus)
424− diq (~(put by diq) (shaf %flap i.wyv) nus)
425− puq (~(put to puq) [nus `soul`[gom 0 | ~2000.1.1 i.wyv]])
426− ==
427− (harv now)
428−```
429−
430−First, we put into `pyz` the id for this message and the number of its
431−packets that have not yet been acknowledged, which is of course the
432−total number of packets since we haven't even sent the packets.
433−
434−For every packet, we change three things in the state (`++shed`) of our
435−packet pump: (1) we increment `nus`, the number of packets sent; (2) we
436−put the packet number into `diq` keyed by a hash of the packet; and (3)
437−we put the packet into the packet queue, with the basic metadata of its
438−id `gom`, 0 transmissions, not live yet, last sent in the year 2000, and
439−the packet itself.
440−
441−Finally, we harvest the packet pump.
442−
443−```
444− ++ harv :: harv:pu
445− |= now=@da :: harvest queue
446− ^- [(list rock) _+>]
447− ?: =(~ puq) [~ +>(rtn ~)]
448− ?. (gth caw nif) [~ +>]
449− =+ wid=(sub caw nif)
450− =| rub=(list rock)
451− =< abet =< apse
452− |%
453−```
454−
455−`++harv` contains a core for most of its work. The meat is in `++apse`.
456−First, though, it sets itself up. If there aren't any packets in the
457−queue, then we simply do nothing except set `rtn`, our next timeout, to
458−nil because we don't have any packets that may need to be retransmitted.
459−If we have more live (that is, sent and unacknowledged) packets than our
460−window size, then we don't do anything.
461−
462−Otherwise, we let `wid` be the width of our remaining packet window, and
463−we initialize `rub` to nil. `rub` will be the list of packets that are
464−ready to be sent. We then call `++apse` and pass the result to `++abet`.
465−`++apse` decides which packets are ready to be sent.
466−
467−```
468− ++ apse
469− ^+ .
470− ?~ puq .
471− ?: =(0 wid) .
472− => rigt =< left
473− ?> ?=(^ puq)
474− ?: =(0 wid) .
475− ?. =(| liv.q.n.puq) .
476− :: ~& [%harv nux.q.n.puq p.n.puq]
477− %_ .
478− wid (dec wid)
479− rub [pac.q.n.puq rub]
480− nif +(nif)
481− liv.q.n.puq &
482− nux.q.n.puq +(nux.q.n.puq)
483− lys.q.n.puq now
484− ==
485−```
486−
487−If there are no remaining packets to send, or if we've filled the packet
488−window, do nothing. We call `++rigt` and `++left` to process the left
489−and right branches of the packet queue.
490−
491−Now we assert that the queue is not empty, and we again check that we
492−haven't filled the packet window. We will operate on the head of the
493−queue. If the packet is live, then do nothing. Otherwise, we go ahead
494−and send it.
495−
496−To send, we (1) decrement `wid`, our packet window width; (2) cons the
497−packet onto the `rub`, which will be returned as the list of packets to
498−send; (3) increment `nif`, the number of live packets; (4) set the
499−packet to be live; (5) increment the number of transmissions of the
500−packet; and (6) set the last sent time of the packet to now.
501−
502−```
503− ++ left
504− ?> ?=(^ puq)
505− ^+(. =+(lef=apse(puq l.puq) lef(puq [n.puq puq.lef r.puq])))
506− ++ rigt
507− ?> ?=(^ puq)
508− ^+(. =+(rig=apse(puq r.puq) rig(puq [n.puq l.puq puq.rig])))
509−```
510−
511−These do exactly what you would expect: they traverse the packet queue
512−so that `++apse` gets called recursively through it.
513−
514−Finally, `++abet` gets called, which resolves the changes.
515−
516−```
517− ++ abet
518− ?~ rub [~ +>.$]
519− [(flop rub) +>.$(rtn [~ (add rto now)])]
520−```
521−
522−This returns the packets that we wish to send, and it updates the
523−timeout so that we know when to try resending unacknowledged packets.
524−
525−This concludes our discussion of `++whap:pu`. To finish
526−`++wind:ho:um:am`, we just need to delve into `++busk:ho:um:am`. But
527−wait, in the call to `++busk`, the first argument is `xong:diz`. What is
528−this? This, my dear reader, is one more detour, this time into
529−`++xong:lax:as:go`.
530−
531−```
532− ++ xong :: xong:lax:as:go
533− ^- (list ship) :: route unto
534− =+ [fro=xen too=xeno]
535− =+ ^= oot ^- (list ship)
536− =| oot=(list ship)
537− |- ^+ oot
538− ?~ too ~
539− ?: (lien fro |=(a=ship =(a i.too))) ~
540− [i.too $(too t.too)]
541− :: ~& [%xong-to [our her] (weld oot ?>(?=(^ fro) t.fro))]
542− (weld oot ?>(?=(^ fro) t.fro))
543−```
544−
545−This gets the list of intermediate ships needed to get a packet from us
546−to our neighbor. First, we get `fro` and `too`, the "canons" of ourself
547−and our neighbor, respectively.
548−
549−What is this "canon", you ask? A canon is simply a ship plus its
550−"ancestors", as defined by `++sein`. For example, the canon of
551−`~hoclur-bicrel` is:
552−
553−```
554− ~hoclur-bicrel/try=> (saxo ~hoclur-bicrel)
555− ~[~hoclur-bicrel ~tasruc ~tug]
556−```
557−
558−If we follow the algorithm in `++xong`, we see that we are simply
559−creating a list of ships that form a path from our neighbor to ourself.
560−Essentially, we look through the canon of our neighbor until we find
561−something in our own cannon -- a common ancestor. Or, if we are from
562−different carriers, then there is no common ancestor. We then weld this
563−onto the tail of our own canon. In the end, this is simply a list of
564−possible ships to try to route via to get to our neighbor, ordered by
565−preferability (that is, closeness to our neighbor). We will end up
566−trying, in order, to find a lane to these.
567−
568−Now, we can finally get to `++busk:ho:um:am`.
569−
570−```
571− ++ busk :: busk:ho:um:am
572− |= [waz=(list ship) pax=(list rock)] :: send packets
573− %_ +>
574− bin
575− |- ^+ bin
576− ?~ pax bin
577− $(pax t.pax, bin (weld (flop (wist:diz now waz ~ i.pax)) bin))
578− ==
579−```
580−
581−Thankfully, `++busk` is fairly simple. We go through the list of packets
582−and convert them to `++boon`s with `++wist:lax:as:go`. These boons are
583−placed into `bin`, and they end up getting processed by `++clop` (this
584−happens in `++knob`).
585−
586−```
587− ++ wist :: wist:lax:as:go
588− |= $: now=@da :: route via
589− waz=(list ,@p)
590− ryn=(unit lane)
591− pac=rock
592− ==
593− ^- (list boon)
594− ?: =(our her) [[%ouzo *lane pac] ~]
595− ?~ waz ~
596− =+ dyr=?:(=(her i.waz) dur (gur i.waz))
597− ?. ?& !=(our i.waz)
598− ?=(^ lun.wod.dyr)
599− ==
600− $(waz t.waz)
601− :_ ?: ?=(%ix -.u.lun.wod.dyr)
602− $(waz t.waz)
603− ~
604− :+ %ouzo u.lun.wod.dyr
605− ?: &(=(i.waz her) =(~ ryn)) pac
606− =+ mal=(jam `meal`[%fore her ryn pac])
607− %- spit
608− ^- cake
609− :* [our i.waz]
610− ?~ yed.caq.dyr [%none mal]
611− :- %fast
612− %^ cat 7
613− p.u.yed.caq.dyr
614− (en:crua q.u.yed.caq.dyr mal)
615− ==
616−```
617−
618−This takes a sample of the current time, the list of ships that we just
619−generated, a lane if we already know it, and the packet itself.
620−
621−First, if we are sending a message to ourself, then we simply create a
622−`%ouzo` boon with a bunted lane. Otherwise, if there are no routing
623−candidates, there is nothing we can do, so we return nil.
624−
625−Next, we get the `dore` of the first routing candidate. If we're looking
626−at the neighbor to whom we're trying to send the message, then we simply
627−use the `dore` that we already have. Otherwise, we get a default `dore`.
628−
629−If we're the first routing candidate, or if we have don't have a lane to
630−this candidate, then we skip this candidate and move on to the next one.
631−
632−If we have only a provisional ip address, then we try to send on it, but
633−we also try to send on later routing candidates as well. Otherwise, we
634−only send on this one candidate.
635−
636−Finally, we create the actual `%ouzo` boon. The lane is the one from our
637−`dore`. If we're sending it directly to our intended recipient, and we
638−haven't been told to use a specific lane, then we just send the packet
639−directly. Otherwise, we wrap it in a little `%fore` meal, telling the
640−intermediary to whom we wish it to be sent. If we have already set up a
641−symmetric key with the intermediary, then we encrypt it with that.
642−Otherwise, we send it in the clear.
643−
644−Now, if you recall, we have traced all the way through from the
645−beginning when, in `++knob`, the `%wont` card was handled by a call to
646−`++wise`. There is only one more step before the packet is finally sent.
647−Looking in `++knob`, we see that the resultant list of boons is passed
648−into `++clop`, which will execute the correct actions and return a list
649−of moves. In `++clop`, we see the handling of each specific boon. The
650−one we are interested in is `%ouzo`, since that is the only one we have
651−sent thus far.
652−
653−```
654− %ouzo
655− :: ~& [%send now p.bon `@p`(mug (shaf %flap q.bon))]
656− :_ fox
657− [[gad.fox [%give %send p.bon q.bon]] ~]
658−```
659−
660−Very simply, we give a `%send` gift along the special duct that goes
661−straight into the bowels of unix. This is the last stop before we drop
662−into vere, and later libuv. And then... the world.
663−
664−The packet, after its creation, embarks on a journey across physical
665−time and space into the great unknown. Hurtling through fiber-optic
666−cables at hundreds of thousands of kilometers per second, it finally
667−arrives at our neighbor's network adapter. The adapter tells unix, unix
668−tells libuv, libuv tells vere, and vere sends a `%hear` kiss to ames.
669−And now we reenter the kernel.
670−
671−The `%hear` kiss goes straight to `++knob`, just as did the `%wont` kiss
672−earlier.
673−
674−```
675− %hear
676− (~(gnaw am [now fox]) %good p.kyz q.kyz)
677−```
678−
679−Here, though, we call `++gnaw:am` to process the packet. The arguments
680−to `++gnaw` are the same as those to the `%hear` kiss: the lane on which
681−the packet was received and the packet itself. The other argument is
682−just `%good`, which is a `++cape` saying that we expect the packet to
683−succeed. If a formal error occurs, then since we have a transactional
684−event system, the `%hear` event will never be considered to have
685−actually happened, and unix will send a `%hole` kiss so that we may send
686−a negative acknowledgment.
687−
688−```
689− ++ gnaw :: gnaw:am
690− |= [kay=cape ryn=lane pac=rock] :: process packet
691− ^- [p=(list boon) q=fort]
692− ?. =(2 (end 0 3 pac)) [~ fox]
693− =+ kec=(bite pac)
694− ?: (goop p.p.kec) [~ fox]
695− ?. (~(has by urb.ton.fox) q.p.kec)
696− [~ fox]
697− =< zork
698− =< zank
699− %- ~(chew la:(ho:(um q.p.kec) p.p.kec) kay ryn %none (shaf %flap pac))
700− [q.kec r.kec]
701−```
702−
703−First, we check the protocol number. If it is not correct, then we
704−simply ignore the packet entirely. Otherwise, we parse the packet with
705−`++bite`, which converts a packet atom into a `cake`, that is, a triple
706−of the `sock` (pair of sender and receiver), the `skin` (encryption
707−type), and the data.
708−
709−```
710− ++ bite :: packet to cake
711− |= pac=rock ^- cake
712− =+ [mag=(end 5 1 pac) bod=(rsh 5 1 pac)]
713− =+ :* vez=(end 0 3 mag) :: protocol version
714− chk=(cut 0 [3 20] mag) :: checksum
715− wix=(bex +((cut 0 [23 2] mag))) :: width of receiver
716− vix=(bex +((cut 0 [25 2] mag))) :: width of sender
717− tay=(cut 0 [27 5] mag) :: message type
718− ==
719− ?> =(2 vez)
720− ?> =(chk (end 0 20 (mug bod)))
721− :+ [(end 3 wix bod) (cut 3 [wix vix] bod)]
722− (kins tay)
723− (rsh 3 (add wix vix) bod)
724−```
725−
726−This is exactly the inverse of `++spit`. Note that here we check both
727−the protocol number and the hash, crashing on error. Remember that a
728−crash will result in a negative acknowledgment being sent.
729−
730−Continuing in `++gnaw`, we see that if the intended recipient is not on
731−our pier, then we drop the packet.
732−
733−If we've gotten this far, then we wish to process the packet. Recall
734−that `++ho` and `++um` set up the domestic server and foreign client
735−cores, respectively, and that `++zork` and `++zank` resolve any changes
736−to these cores.
737−
738−The new stuff here, then, is the `++la` core and the `++chew` arm. The
739−`++la` sets up a core for this particular packet, containing the current
740−success/failure `cape`, the lane it was sent on, the encryption type,
741−and a hash of the packet, used as an id.
742−
743−`++chew` is called with the encryption type and the message itself. It
744−contains a little helper core inside of it, which starts immediately
745−with `++apse`.
746−
747−```
748− ++ apse
749− ^+ +>.$
750− =+ oub=bust:puz
751− =+ neg==(~ yed.caq.dur.diz)
752− =. +>.$ east
753− =+ eng==(~ yed.caq.dur.diz)
754− =+ bou=bust:puz
755− =. bin
756− ?. &(oub !bou) bin
757− :_(bin [%wine [our her] " is ok"])
758− =. bin
759− ?. &(neg !eng) bin
760− :_(bin [%wine [our her] " is your neighbor"])
761− +>.$
762−```
763−
764−First, we let `oub` be true if our neighbor hasn't been responding to us
765−for more than sixteen seconds. Let `neg` be true if we haven't yet
766−proposed a symmetric key, meaning that we haven't yet corresponded with
767−this ship, so they are not our neighbor. Next, we run `++east`, which
768−we'll go into in just a minute.
769−
770−We now do the same two checks and store the results in `eng` and `bou`.
771−If our neighbor has, like the prodigal son, returned after an extended
772−absense, then we send a `%wine` boon as the proverbial fatted calf,
773−which is simply printed out to the console. Likewise, if we are meeting
774−one with whom we have never had the pleasure of acquainting ourselves,
775−we send a message to the console to that effect.
776−
777−We skipped over `++east`, which contains the meat of the processing. It
778−first decrypts the message, then calls `++chow:la:ho:um:am` with the
779−resultant meal. We'll go through each of the four cases in turn, but
780−first since each one calls `++bilk:pu`, we'll take a brief detour.
781−
782−```
783− ++ bilk :: bilk:pu
784− |= now=@da :: inbound packet
785− ^+ +>
786− =+ trt=(mul 2 rtt)
787− %= +>.$
788− rue [~ now]
789− rto trt
790− rtn ?~(puq ~ [~ (add now trt)])
791− ==
792−```
793−
794−This updates the timing information in our packet pump. `rue`, the last
795−time we have heard from this neighbor, is set to now. `rto`, the
796−retransmit timeout is set to twice the current ping time, and if there
797−is anything in the packet queue, then we reset the next timeout, since
798−we've just heard a message.
799−
800−Back to `++east`.
801−
802−```
803− %none
804− =. puz (bilk:puz now)
805− (chow ((hard meal) (cue msg)))
806−```
807−
808−The simplest case is when the encryption type is `%none`. We first call
809−`++bilk` to update the packet pump, then we cue (unjam) the message into
810−a meal. We hard cast it into a meal -- if the cast fails, then we do
811−want to crash since someone is sending us malformed data. Finally, we
812−send the result to `++chow` for interpretation and handling.
813−
814−```
815− %fast
816− =+ [mag=`hand`(end 7 1 msg) bod=(rsh 7 1 msg)]
817− =+ dey=(kuch:diz mag)
818− ?~ dey
819− ~& [%bad-key her mag]
820− +>.$ :: ignore unknown key
821− =. puz (bilk:puz now)
822− =^ key diz u.dey
823− (chow(aut sin) ((hard meal) (cue (dy:q:sen:gus key bod))))
824−```
825−
826−For symmetric encryption, we first get the `hand`, which is the hash of
827−the symmetric key. We pass it to `++kuch:lax:as:go`, which returns the
828−key if we either have used it before or we have proposed it. If we have
829−proposed it, then we change its status from proposed to real. If
830−`++kuch` fails, then we drop the packet and print out a `%bad-key`
831−message.
832−
833−Otherwise, we call `++bilk` as before to update the packet pump and pass
834−into `++chow` the decrypted data.
835−
836−```
837− %full
838− =+ mex=((hard ,[p=[p=life q=life] q=will r=@]) (cue msg))
839− =. diz (deng:diz q.mex)
840− =+ wug=cluy:diz
841− ?> =(q.p.mex p.wug)
842− =+ gey=(sev:gus p.p.mex)
843− =+ mes=(need (tear:as:q.gey pub:ex:r.wug r.mex))
844− =. diz (wasc:diz p.mes)
845− =. puz (bilk:puz now)
846− (west(msg q.mes))
847−```
848−
849−For sealed asymmetric encryption, we first take off the the layer of
850−data that gives us the life and will of our neighbor, and we apply try
851−to extend their former will with the new data. `++deng` will fail if
852−this is impossible.
853−
854−Next, we get our most current understanding of our neighbor's crypto,
855−and we verify that it's the same life as what they're sending. Then, we
856−get our own crypto from `++sev` and decrypt the message with the public
857−key from our neighbor's crypto. We register the proposed symmetric key,
858−update the packet pump, and call `++west`, which simply casts the
859−message to a meal and calls `++chow`, reporting any error.
860−
861−```
862− %open
863− =+ mex=((hard ,[p=[~ q=life] q=will r=@]) (cue msg))
864− =. diz (deng:diz q.mex)
865− =+ wug=cluy:diz
866− ?> =(q.p.mex p.wug)
867− =+ mes=(need (sure:as:r.wug *code r.mex))
868− =. puz (bilk:puz now)
869− (west(msg mes))
870−```
871−
872−Finally, for signed asymmetric encryption, we, as before, take off the
873−layer of data that gives us the life and will of our neighbor. This
874−time, of course, we do not get our own crypto -- only that of our
875−neighbor.
876−
877−The rest you have seen. We call `++deng` to extend the will, we verify
878−that their crypto life is what we think it ought to be, we "decrypt" the
879−data, we update the packet pump, and we call `++west` to call `++chow`.
880−
881−```
882− ++ chow :: chow:la:ho:um:am
883− |= fud=meal :: interpret meal
884− ^+ +>
885− =. diz ?:(=(%none aut) diz (wast:diz ryn))
886− (dine fud)
887−```
888−
889−Here, if the message was encrypted at all, then we call
890−`++wast:lax:as:go`, which simply updates the lane (route) to our
891−neighbor (unless we're given a provisional route). This ensures that we
892−always have the most direct possible path to them.
893−
894−We've been handling this meal for so long, we've almost forgotten what
895−we want to do with it. The telos is of any meal to be dined on. We will
896−choose out the cases here that are important to our current
897−investigation.
898−
899−```
900− %fore
901− =+ ^= lyn ^- lane
902− ?~ q.fud ryn
903− ?. ?=(%if -.u.q.fud) u.q.fud
904− [%ix +.u.q.fud]
905− :: u.q.fud
906− ?: =(our p.fud)
907− (emit %mead lyn r.fud)
908− =+ zid=(myx:gus p.fud)
909− (emir (wist:zid now xong:zid [~ lyn] r.fud))
910−```
911−
912−Forwarding is the simplest case, since we've seen all the arms before,
913−except perhaps `++emit` and `++emir`, which simply take a boon or list
914−of boons respectively and queue them up to be handled when the core
915−resolves. If we're told to forward a packet to ourselves, then we emit a
916−`%mead` boon which simply sends another `%hear` kiss to ourselves with
917−the data. Otherwise, we try to find a route to the recipient, as before.
918−
919−```
920− %carp
921− =+ zol=(~(get by olz.weg) s.fud)
922− ?^ zol cock(kay u.zol)
923− =^ neb nys.weg
924− =+ neb=(~(get by nys.weg) s.fud)
925− ?^ neb [u.neb nys.weg]
926− =+ neb=`bait`[(kins p.fud) 0 r.fud ~]
927− [neb (~(put by nys.weg) s.fud neb)]
928− ?> (lth q.fud p.r.neb)
929− ?> =((kins p.fud) p.neb)
930− ?> =(r.fud p.r.neb)
931− =+ doy=`(unit ,@)`(~(get by q.r.neb) q.fud)
932− ?^ doy cock
933− => ^+ . %= .
934− q.r.neb (~(put by q.r.neb) q.fud t.fud)
935− q.neb +(q.neb)
936− ==
937− :: ~& [%carp q.fud s.fud q.neb p.r.neb]
938− ?: =(q.neb p.r.neb)
939− =: nys.weg (~(del by nys.weg) s.fud)
940− olz.weg (~(put by olz.weg) s.fud kay)
941− ==
942− (golf p.neb r.neb)
943− =. +>.$ cock
944− +>.$(nys.weg (~(put by nys.weg) s.fud neb))
945−```
946−
947−Here, we have received a partial message, and we're just assembling the
948−individual packets into a message. Most of this code is fairly
949−algorithmic, so we'll just hit the high points. In the beginning, we
950−check if we've already received this message, and if so, we resend the
951−acknowledgment. Remember, "always ack a dupe, never ack an ack".
952−
953−In `nys.weg` we keep track of an incoming set of partial packets,
954−indexed by the `flap` hash that comes with every packet. We check to see
955−if we have already received this partial message, and if so we
956−acknowledge it. Otherwise, we put it in `nys.weg` unless this is the
957−last message, in which case we ack the last partial message, move the
958−complete message into `olz.weg`, and call `++golf`, which assembles the
959−message and calls `++chew`, to start the dance again with the complete
960−message.
961−
962−```
963− %bund
964− :: ~& [%bund q.fud r.fud]
965− ?> =(p:sen:gus p.fud)
966− (deer q.fud r.fud ?-(kay %dead ~, %good [~ s.fud]))
967−```
968−
969−What if we're just receiving a regular old, garden variety message? We
970−call `++deer` with the data from the message. If we already know that
971−the message processing will fail (that is, if we got a `%hole` card from
972−unix rather than a `%hear` card), then we don't even send the data at
973−all. Remember, if a packet fails to process, it's as if it never even
974−arrived, except that we send a negative acknowledgment.
975−
976−```
977− ++ deer :: deer:la:ho:um:am
978− |= [cha=path num=@ud dut=(unit)] :: interpret message
979− ^+ +>
980− =+ rum=(fall (~(get by raz.bah) cha) *race)
981− %= +>.$
982− +>
983− ?. (gte num did.rum) :: always ack a dup
984− (cook (~(get by bum.rum) num) cha ~ ryn dam)
985− ?: dod.rum
986− (coat cha rum(mis (~(put by mis.rum) num [kay ryn dam dut])))
987− %= +>.+>.$
988− raz.bah
989− %+ ~(put by raz.bah) cha
990− rum(mis (~(put by mis.rum) num [kay ryn dam dut]))
991− ==
992− ==
993−```
994−
995−First, we get the race for this particular triple of sender, receiver,
996−and path, creating it if it doesn't exist. If we've already acked the
997−message, then we resend the ack. Note that `did.rum` is the number of
998−packets we acknowledged, positively or negatively while `bum.rum` is a
999−map of message numbers to negative acknowledgments. Thus, if a message
1000−number is less than `did.rum`, then if it's in `bum.rum` then it was
1001−negatively acknowledged, otherwise it's postively acknowledged. Thus, we
1002−are constant in space with the number of successful messages and linear
1003−in the number of failed messages. We'll document `++cook` later on, but
1004−suffice it to say that it sends an acknowledgment. It is to end-to-end
1005−acknowledgments what `++cock` is to packet-level acknowledgments.
1006−
1007−If we are still processing a message (that is, `dod.rum` is false), then
1008−we simply put this message in the map of misordered packets to be
1009−processed when their time comes. "Processing a message" in this case
1010−means that we've received the message and notified the correct
1011−application, but we're still waiting for the application-level
1012−acknowledgment.
1013−
1014−Otherwise, we're ready for a packet, so we process it.
1015−
1016−```
1017− ++ coat :: coat:ho:um:am
1018− |= [cha=path rum=race] :: update input race
1019− ^+ +>
1020− =+ cun=(~(get by mis.rum) did.rum)
1021− ?~ cun
1022− +>.$(raz.bah (~(put by raz.bah) cha rum))
1023− ?. =(%good p.u.cun) +>.$
1024− ?> ?=(^ s.u.cun)
1025− %= +>.$
1026− raz.bah (~(put by raz.bah) cha rum(dod |))
1027− bin
1028− :_ bin
1029− :^ %mulk
1030− [our her]
1031− `soap`[[p:sen:gus clon:diz] cha did.rum]
1032− u.s.u.cun
1033− ==
1034−```
1035−
1036−First, we grab the message we want to process and store it in `cun`. If
1037−it's a good packet, then we change `dod.rum` to false, meaning that
1038−we're in the middle of processing a packet and should not start
1039−processing another one. We also put a `%mulk` boon into the queue so
1040−that, when it all resolves, we send a mesage to the intended recipient
1041−application. The boon contains the sender, the receiver, the identity of
1042−the message, and the message itself.
1043−
1044−This bubbles up all the way back to `++knob`, where we were handling the
1045−`%hear` card. Following the logic in `++knob`, we can see that the boons
1046−get sent into `++clop` to be turned into actual arvo-level moves. We've
1047−been here before, if you recall, when we handled the `%cake` boon to
1048−send a message. Now, we're handling the `%mulk` boon, which is
1049−unfortunately slightly more complicated.
1050−
1051−```
1052− %mulk
1053− :: ~& [%mulk p.bon q.bon]
1054− ?> ?=([@ @ *] q.q.bon)
1055− ?> ?=(%q i.q.q.bon)
1056− ?+ i.t.q.q.bon
1057− ~& %mulk-bad
1058− :_ fox
1059− :~ :- (claw p.p.bon)
1060− [%sick %wart p.bon i.t.q.q.bon t.t.q.q.bon r.bon]
1061− ==
1062− %ge :: %gall request
1063− ?> ?=([@ ~] t.t.q.q.bon)
1064− =+ app=`term`(need ((sand %tas) i.t.t.q.q.bon))
1065− =+ ^= pax
1066− :+ (scot %p p.p.bon)
1067− (scot %p q.p.bon)
1068− q.q.bon
1069− :_ fox [hen %pass pax %g %rote p.bon app r.bon]~
1070− %gh :: %gall response
1071− ?> ?=([@ ~] t.t.q.q.bon)
1072− =+ app=`term`(need ((sand %tas) i.t.t.q.q.bon))
1073− =+ ^= pax
1074− :+ (scot %p p.p.bon)
1075− (scot %p q.p.bon)
1076− q.q.bon
1077− :_ fox [hen %pass pax %g %roth p.bon app r.bon]~
1078− ==
1079−```
1080−
1081−We're dispatching messages based on the prefix of their path. Since only
1082−`%gall` apps use end-to-end acknowledgments at the moment, every path
1083−must have at least two elements, and the first one must be `%q`. Beyond
1084−that, we handle the `/q/ge` and `/q/gh` cases for gall requests and
1085−responses, respectively.
1086−
1087−In both cases, we require the next term in the path to be the name of
1088−the intended recipient `%gall` app. Thus, a message to `/q/ge/talk` for
1089−example, will send a message to the talk app.
1090−
1091−We then send a message to the app itself. The message is either a
1092−`%rote` or a `%roth` for a request and a response, respectively. The
1093−content is the `rook` or `roon` that was sent (stored in `r.bon`), but
1094−we don't actually handle that at all here. That's completely a
1095−`%gall`-level thing. We're just the messenger.
1096−
1097−Notice the path we send this over. We encode the sender, the receiver,
1098−and the path over which it was sent. This fully specifies the `race` so
1099−that when the app gives us the acknowledgment we know where to send it.
1100−
1101−We now have another interlude. We have entrusted our precious data, so
1102−carefully guarded and guided from the app on that far-away ship, to our
1103−local app. It has the ability to do whatever it pleases with it. It may
1104−take a significant amount of time to process. When the message has been
1105−handled by this app, though, it must produce an acknowledgment. Our
1106−final task is to deliver this acknowledgment to the sending app.
1107−
1108−We should describe here what exactly these oft-mentioned acknowledgments
1109−actually consist of. There are two kinds of acknowledgments: positive
1110−and negative. A positive acknowledgment contains no data other than its
1111−existence. A negative acknowledgment may optionally include a reason for
1112−said negativity. Formally, a negative acknowledgment is an `ares`, which
1113−is a unit pair of a term and a list of tanks. If this is null, this is
1114−simply a failure with no associated information. If the pair exists, the
1115−term is a short error code that is usually both human and computer
1116−readable. For example, if you try to send a message to a valid `%gall`
1117−app that doesn't have any `++poke` to handle it, then `%gall` will give
1118−a negative acknowledgment with error term `%poke-find-fail`. The list of
1119−tanks is a human-readable description of the error. This often contains
1120−a stack trace. At any rate, all this information is returned to the
1121−sending app on the other end of the wire.
1122−
1123−After this brief interlude, our story resumes in `++knap`, where we
1124−receive responses. In particular, a `%mean` indicates a negative
1125−acknowledgment while a `%nice` indicates a positive acknowledgment.
1126−
1127−```
1128− ?(%mean %nice)
1129− ?> ?=([@ @ @ *] tea)
1130− =+ soq=[(slav %p i.tea) (slav %p i.t.tea)]
1131− =+ pax=t.t.tea
1132− =+ ^= fuy
1133− =< zork =< zank
1134− %^ ~(rack am [now fox]) soq pax
1135− ?-(+<.sih %mean `p.+.sih, %nice ~)
1136− => %_(. fox q.fuy)
1137− =| out=(list move)
1138− |- ^- [p=(list move) q=_+>.^$]
1139− ?~ p.fuy
1140− [(flop out) +>.^$]
1141− =^ toe fox (clop now hen i.p.fuy)
1142− $(p.fuy t.p.fuy, out (weld (flop toe) out))
1143−```
1144−
1145−Recall the format of the path we sent the message on, and you'll
1146−understand why `soq` and `pax` are the sender/receiver pair and path on
1147−which the message was sent. The rest of this is structured much like
1148−`++knob`, so we call `++rack:am` and send the resulting boons to
1149−`++clop`. Business as usual.
1150−
1151−```
1152− ++ rack :: rack:am
1153− |= [soq=sock cha=path cop=coop] :: e2e ack
1154− =+ oh=(ho:(um p.soq) q.soq)
1155− =. oh (cook:oh cop cha ~)
1156− (cans:oh cha)
1157−```
1158−
1159−First, we set up `++um` and `++ho`, as we've done twice before, for our
1160−domestic and foreign servers, respectively. The other two things are
1161−new, though. Well, `++cook` is not actually new, but we delayed the
1162−explanation saying only that it sends an acknowledgment. The time has
1163−come.
1164−
1165−```
1166− ++ cook :: cook:ho:um:am
1167− |= [cop=coop cha=path ram=(unit ,[ryn=lane dam=flap])]
1168− ^+ +> :: acknowledgment
1169− =+ rum=(need (~(get by raz.bah) cha))
1170− =+ lat=(~(get by mis.rum) did.rum)
1171− ?: &(?=(~ lat) ?=(~ ram)) ~&(%ack-late-or-redundant +>.$)
1172− =+ ^- [ryn=lane dam=flap]
1173− ?^ ram [ryn.u.ram dam.u.ram]
1174− ?< ?=(~ lat)
1175− [q r]:u.lat
1176− =. raz.bah
1177− ?^ ram raz.bah
1178− %+ ~(put by raz.bah) cha
1179− rum(dod &, bum ?~(cop bum.rum (~(put by bum.rum) did.rum u.cop)))
1180− =^ roc diz (zuul:diz now [%buck cop dam ~s0])
1181− (busk(diz (wast:diz ryn)) xong:diz roc)
1182−```
1183−
1184−If we are acknowledging a message that we have already acked, the `ram`
1185−will contain the new lane and flap to send the duplicate ack to. This
1186−happens if we call `++cook` in `++deer`, but it doesn't happen from
1187−`++rack`. If there is no message waiting to be acknowledged and we're
1188−not given an explicit lane and flap (that is, we're not sending a
1189−duplicate ack), then the app must have sent us multiple acknowledgments.
1190−We do the only sensible thing we can do and drop all acknowledgments
1191−after the first, printing a message. This is, in fact, an error, so it
1192−could be argued that we ought to crash. Whatever you do, don't depend on
1193−this not crashing.
1194−
1195−First, we grab the race specified by the given path, and we get the most
1196−recent in-order message, which must be the one which is being
1197−acknowledged.
1198−
1199−Then, we decide which lane/flap to respond on/to. Basically, in the
1200−usual case we respond on the lane through which the initial message was
1201−sent, which is stored along with the other packet information in
1202−`mis.rum`, since it has to be remembered across calls to ames. However,
1203−if we receive a duplicate message, then we must respond to the new
1204−message. It's quite possible the reason the other acknowledgment didn't
1205−get returned was that the lane between the ships was broken.
1206−
1207−At any rate, we update the race by saying that we've finished processing
1208−this packet (unless we're sending a duplicate ack) and, if we're sending
1209−a negative acknowledgment, putting the negative ack into `bum.rum` so
1210−that we can resend it if necessary.
1211−
1212−We encode our new message, updating the packet pump, with `++zuul`, as
1213−before, and we send it off with `++busk`, routed via `++wast` to one of
1214−the ships in `++xong`. Of course, in practice, we don't even look at the
1215−ships in `++xong` because we already have a lane directly to our
1216−neighbor (the one over which they sent their message to us).
1217−
1218−We glossed over the actual message we're sending back. We're sending a
1219−`%buck` meal, which is an acknowledgment. The `cop` specifies whether
1220−this is a positive or a negative ack, `dam` specifies the message we're
1221−acknowledging, and the `~s0` is a placeholder for the processing time
1222−required. This time is neither calculated (though it is hopefully
1223−obvious how to do so) nor used at present, but this information may be
1224−used in the future for improved congestion control. Since the round-trip
1225−time for an end-to-end acknowledged packet includes the processing time
1226−on the other end, most common congestion control algorithms will stumble
1227−when some messages take much longer to process than others. As noted,
1228−though, this is simply an opportunity for improvement -- our congestion
1229−control algorithms are relatively naive at the moment.
1230−
1231−Recall that `++busk` calls `++wist` to put the actual `%ouzo` boon in
1232−the queue, which gets handled by `++clop` to actually send the message.
1233−This is the same pipeline as sending any other message, so we'll refer
1234−you to the explanation above if you've forgotten it.
1235−
1236−The last thing we need to do on this ship is move on to the next packet
1237−in the queue if there is one. If you recall, in `++rack` after the call
1238−to `++cook` there was a call to `++cans:ho:um:am`.
1239−
1240−```
1241− ++ cans :: cans:ho:um:am
1242− |= cha=path
1243− =+ rum=(need (~(get by raz.bah) cha))
1244− =. rum
1245− %= rum
1246− did +(did.rum)
1247− mis (~(del by mis.rum) did.rum)
1248− ==
1249− (coat cha rum)
1250−```
1251−
1252−This is very simple. We increment the number of packets that we've
1253−acknowledged on this race and we delete the packet that we just
1254−acknowledged from the set of misordered packets.
1255−
1256−Then, we call `++coat` again to process the next packet if we've already
1257−received it. And that's it for this.
1258−
1259−The acknowledgment now travels the same path that its forebearer, the
1260−original message, once tread, but this time not into the great unknown.
1261−The weary traveler is seeking out its familial roots, finding the app
1262−from whom sprung forth the original message way back in paragraph three.
1263−When it arrives at the network adapter of its ancestors, the adapter
1264−tells unix, unix tells libuv, libuv tells vere, and vere sends a `%hear`
1265−kiss to ames. Once more into the kernel.
1266−
1267−The `%hear` kiss is handled in `++knob` as before, leading to `++gnaw`,
1268−going over to `++chew`, `++apse`, `++chow`, and eventualy to `++dine`.
1269−We've seen most of the cases in `++dine`, but we haven't yet looked at
1270−the handling of this `%buck` meal.
1271−
1272−```
1273− %buck
1274− =. +> ?.(=(%full aut) +> cock) :: finish key exch
1275− +>(..la (tock p.fud q.fud r.fud))
1276−```
1277−
1278−We send a packet level acknowledgment if we're finishing a key exchange,
1279−else we call `++tock` to process the acknowledgment.
1280−
1281−This will get a little involved, so if you don't much care about how
1282−exactly an acknowledgment happens, just know that the result gets gifted
1283−as a `%woot` card back to the app who sent it. For those brave souls who
1284−wish to see this thing through to the end, it's once more into the
1285−breach.
1286−
1287−```
1288− ++ tock :: tock:ho:um:am
1289− |= [cop=coop fap=flap cot=@dr] :: e2e ack by hash
1290− ^+ +>
1291− =^ yoh puz (bick:puz now fap)
1292− =. +>.$
1293− ?~ p.yoh +>.$
1294− =^ hud +>.$
1295− (done p.u.p.yoh q.u.p.yoh)
1296− ?~ hud +>.$
1297− %= +>.$
1298− bin
1299− :_ bin
1300− `boon`[%cake [our her] [[p:sen:gus clon:diz] u.p.yoh] cop u.hud]
1301− ==
1302− (busk xong:diz q.yoh)
1303−```
1304−
1305−We're going to work through this one a little backwards since it's
1306−mostly fairly simple except the call to `++bick:pu`. In fact, we'll just
1307−skip `++bick` for the moment and finish the rest.
1308−
1309−If `++bick` succesfully acks the message, then we call `++done`.
1310−
1311−```
1312− ++ done :: done:ho:um:am
1313− |= [cha=path num=@ud] :: complete outgoing
1314− ^- [(unit duct) _+>]
1315− =+ rol=(need (~(get by ryl.bah) cha))
1316− =+ rix=(~(get by san.rol) num)
1317− ?~ rix [~ +>.$]
1318− :- rix
1319− %_ +>.$
1320− ryl.bah
1321− (~(put by ryl.bah) cha rol(san (~(del by san.rol) num)))
1322− ==
1323−```
1324−
1325−This very simply gets the rill (the outgoing counterpart to a race, if
1326−you recall), pulls out of the map of outstanding messages the duct over
1327−which the original message was sent, and produces this duct while
1328−deleting that entry from the map of outstanding messages.
1329−
1330−Going back to `++tock`, we now have the duct we need to return the
1331−result over. We do the very sensible thing and put a `%cake` boon in the
1332−queue to be processed later by `++clop`.
1333−
1334−In `q.yoh` we have a list of messages that may need to be sent, which we
1335−pass to `++busk` to send, as usual. When an acknowledgment arrives, that
1336−may trigger other messages immediately. This often happens when sending
1337−more messages than the width of the logical window since for congestion
1338−control reasons another message cannot be sent until some of the earlier
1339−ones have been acknowledged.
1340−
1341−We'll look at the processing of the `%cake` boon in `++clop` before we
1342−get back to talking about `++bick`.
1343−
1344−```
1345− %cake
1346− :_ fox
1347− :~ [s.bon %give %woot q.p.bon r.bon]
1348− ==
1349−```
1350−
1351−We very simply give, along the duct we found above, a `%woot` card with
1352−the ship who sent us the ack and the ack itself. This allows the
1353−application to decide what to do about the result. In case of a failure,
1354−we usually either resend the message or display it to the user.
1355−Sometimes, we recognize the error term and handle it internally. In any
1356−case, the decision of how to handle the acknowledgment is entirely up to
1357−the application. Our job is done.
1358−
1359−Well, except that we skipped `++bick:pu`. Let's go back to that.
1360−
1361−```
1362− ++ bick :: bick:pu
1363− |= [now=@da fap=flap] :: ack by hash
1364− ^- [[p=(unit soup) q=(list rock)] _+>]
1365− =+ sun=(~(get by diq) fap)
1366− ?~ sun
1367− [[~ ~] +>.$]
1368− =. diq (~(del by diq) fap)
1369− =^ gub +>.$ (bock now u.sun)
1370− =^ yop +>.$ (harv now)
1371− [[gub yop] +>.$]
1372−```
1373−
1374−If you recall, in `++whap:pu` we created the packet pump's
1375−representation of the message, which included putting the message into
1376−`diq`, which maps from packet hashes to packet sequence numbers. Thus,
1377−`u.sun` is the sequence number of this particular message.
1378−
1379−We delete this message from `diq` since we have now received an ack for
1380−it. We call `++bock` to perform the ack by sequence number. We call
1381−`++harv` to harvest the packet queue, sending any messages that are now
1382−able to be sent.
1383−
1384−In `++bock`, there are three arms we haven't seen before: `++bine`,
1385−`+wept`, and `++beet`. We'll describe each of these before we get to
1386−`++bock`. `++bine` looks scariest.
1387−
1388−```
1389− ++ bine :: bine:pu
1390− |= [now=@da num=@ud] :: apply ack
1391− ^- [(unit soup) _+>]
1392− ?~ puq !!
1393− ?. =(num p.n.puq)
1394− ?: (gth num p.n.puq)
1395− =+ lef=$(puq l.puq)
1396− [-.lef +.lef(puq [n.puq puq.lef r.puq])]
1397− =+ rig=$(puq r.puq)
1398− [-.rig +.rig(puq [n.puq l.puq puq.rig])]
1399− =: rtt ?. &(liv.q.n.puq =(1 nux.q.n.puq)) rtt
1400− =+ gap=(sub now lys.q.n.puq)
1401− :: ~& [%bock-trip num (div gap (div ~s1 1.000))]
1402− (div (add (mul 2 rtt) gap) 3)
1403− nif (sub nif !liv.q.n.puq)
1404− ==
1405− =+ lez=(dec (need (~(get by pyz) gom.q.n.puq)))
1406− =^ gub pyz
1407− ?: =(0 lez)
1408− [[~ gom.q.n.puq] (~(del by pyz) gom.q.n.puq)]
1409− [~ (~(put by pyz) gom.q.n.puq lez)]
1410− :- gub
1411− +>.$(puq ~(nap to puq))
1412−```
1413−
1414−The first few lines are simply looking through the packet queue until we
1415−find the correct packet to ack. This is basic queue manipulation that
1416−operates directly on the treap structure of the queue. If you understand
1417−treap queues, the logic is easy to follow. Otherwise, just trust us that
1418−by the time we get to the `=:`, the packet with sequence number `num` is
1419−on the top of the packet queue (that is, at `n.puq`).
1420−
1421−We first update the round-trip time. If the packet is either not alive
1422−or had to be transmitted more than once, then we don't have any reliable
1423−way of calculating the round-trip time since we're unsure of exactly
1424−which transmission was acknowledged. Otherwise, the round-trip time is
1425−the difference between now and when the packet was last sent. We set
1426−`rtt` by a little weighted average where the previous smoothed RTT is
1427−weighted twice as much as the RTT of the current packet. Thus,
1428−`(2*rtt+gap)/3`. This gives us a nice smooth RTT that is somewhat
1429−resilient to outlier data while still being responsive to our
1430−ever-changing world.
1431−
1432−If the packet wasn't already dead, then we decrement the number of live
1433−packets, which may allow more packets to be sent.
1434−
1435−We decrement the number of unacknowledged packets in our `pyz` for this
1436−particular message. If you recall, this was set in `++whap` to the
1437−number of packets required to send a message.
1438−
1439−If that was the last packet in the messge that needed to be acked, then
1440−we delete the messgae reference from `pyz` and produce the id of the
1441−message. Otherwise, we simply update `pyz` with the new number of
1442−unacked messages. In either case, we remove the packet from the packet
1443−queue.
1444−
1445−```
1446− ++ wept :: wept:pu
1447− |= [fip=@ud lap=@ud] :: fip thru lap-1
1448− =< abet =< apse
1449− |%
1450− ++ abet +>.$
1451− ++ apse
1452− ^+ .
1453− ?~ puq .
1454− ?: (lth p.n.puq fip) ?~(l.puq . left)
1455− ?: (gte p.n.puq lap) ?~(r.puq . rigt)
1456− => rigt =< left
1457− ?> ?=(^ puq)
1458− ?.(liv.q.n.puq . .(nif (dec nif), liv.q.n.puq |))
1459− ::
1460− ++ left
1461− ?> ?=(^ puq)
1462− ^+(. =+(lef=apse(puq l.puq) lef(puq [n.puq puq.lef r.puq])))
1463− ++ rigt
1464− ?> ?=(^ puq)
1465− ^+(. =+(rig=apse(puq r.puq) rig(puq [n.puq l.puq puq.rig])))
1466− --
1467−```
1468−
1469−The algorithm is a simple case of traversing the packet queue.
1470−Essentialy, we mark as dead all packets in the queue between `fip` and
1471−`(dec lap)`. We also update `nif`, the number of live packets. Lest you
1472−mourn too much the passing of these packets, know that they shall soon
1473−rise again. Recall that in `++bick` after the call to `++bock` we call
1474−`++harv`. This will resend the packets that have just been labeled dead.
1475−
1476−```
1477− ++ beet :: beet:pu
1478− ^+ . :: advance unacked
1479− =- +(nep ?~(foh nus u.foh))
1480− ^= foh
1481− |- ^- (unit ,@ud)
1482− ?~ puq ~
1483− ?: (lte p.n.puq nep) $(puq l.puq)
1484− =+ rig=$(puq r.puq)
1485− ?^(rig rig [~ p.n.puq])
1486−```
1487−
1488−Here we search for the next expected packet number. Basically, we search
1489−the queue for the leftmost packet whose number is greater than the
1490−current `nep`. If we don't find any such packet, we just use the total
1491−number of packets sent.
1492−
1493−We can now dive into `++bock`, our last arm.
1494−
1495−```
1496− ++ bock :: bock:pu
1497− |= [now=@da num=@ud] :: ack by sequence
1498− ^- [(unit soup) _+>]
1499− =^ gym +> (bine now num)
1500− :- gym
1501− ?: (gth num nep)
1502− =+ cam=(max 2 (div caw 2))
1503− :: ~& [%bock-hole num nep cam]
1504− beet:(wept(nep num, cag cam, caw cam) nep num)
1505− =. caw ?: (lth caw cag) +(caw)
1506− (add caw !=(0 (mod (mug now) caw)))
1507− ?: =(num nep)
1508− :: ~& [%bock-fine num nif caw cag]
1509− beet
1510− :: ~& [%bock-fill num nif caw cag]
1511− +>.$
1512−```
1513−
1514−First, we call `++bine` to apply the ack to the packet pump information.
1515−We produce `gym`, which, if it exists, is the id of the packet that was
1516−acked. If we received an ack for a packet later than the one we
1517−expected, then we halve the logical packet window and kill all the
1518−earlier packets so that they may be resent.
1519−
1520−Otherwise, we possibly increase the congestion window. If the window is
1521−less than the congestion threshold, then we increment the size of the
1522−window. Otherwise, we only increment one out of every `caw` times.
1523−
1524−If we received an ack for the packet we expected, then we simply advance
1525−`nep` with `++beet`. If we received an ack for a packet earlier than we
1526−expected, we do nothing.
1527−
1528−It may be hard to believe, but we are, in fact, done. The message has
1529−been sent, received, acknowledged, and the acknowledgment has been
1530−returned to the original sender. We hope it's clear that, while the
1531−process has been somewhat involved, the algorithms are not all that
1532−complicated. If you've read this far, you know `%ames`. The only other
1533−code involves initialization, timeouts, and the like.
1534−
1535−Below, we give detailed reference documentation for the data models
1536−involved.
1537−
1538−## Data Models
1539−
1540−### `++fort`, formal state
1541−
1542−```
1543− ++ fort :: formal state
1544− $: %0 :: version
1545− gad=duct :: client interface
1546− hop=@da :: network boot date
1547− ton=town :: security
1548− zac=(map ship corn) :: flows by server
1549− == ::
1550−```
1551−
1552−This is the state of our vane. Anything that must be remembered between
1553−calls to ames must be stored in this state.
1554−
1555−`%0` is the version of the ames state model itself. If the data model
1556−`++fort` changes, then this number needs to be incremented, and an
1557−adapter must be written to upgrade the old state into the new state.
1558−Note that this is the version number of the model itself, not the
1559−contents. When the data changes, there is of course no need to change
1560−this.
1561−
1562−`gad` is a `duct` over which we send `%send` cards to unix. This card is
1563−initialized when unix sends a `%barn` card as vere starts up. Vere
1564−treats this duct specially -- don't send anything weird over it.
1565−
1566−`hop` is the network boot date. This is set when the `%kick` card is
1567−sent by vere on start up.
1568−
1569−`ton` is a `++town`, where we store all of our security/encryption
1570−state. Note that this is shared across all ships on a pier.
1571−
1572−`zac` is a map of ships to `++corn`. This stores all the per-ship state.
1573−The keys to this map are the ships on the current pier.
1574−
1575−### `++town`, all security state
1576−
1577−```
1578− ++ town :: all security state
1579− $: lit=@ud :: imperial modulus
1580− any=@ :: entropy
1581− urb=(map ship sufi) :: all keys and routes
1582− fak=? ::
1583− == ::
1584−```
1585−
1586−This is the security state of our pier.
1587−
1588−`lit` is unused.
1589−
1590−`any` is 256 bits of entropy. This entropy is used and updated in
1591−exactly two places: when we send a `%junk` card, and when we generate a
1592−new symmetric key in `++griz:lax:as:go`. When it is updated, it is
1593−updated by a SHA-256 hash of the current time and the old value of the
1594−entropy.
1595−
1596−`urb` is a map of ships to `++sufi`. This is where we store all the
1597−per-ship state for the pier. The keys to this map are the ships on the
1598−current pier.
1599−
1600−`fak` is true if we are on a fake network. This disables certain
1601−security checks so that anyone may run a fake `~zod`. This is used only
1602−for development. To use, run vere with the `-F` option (and the
1603−`-I ~zod` option for a fake `~zod`).
1604−
1605−### `++sufi`, domestic host
1606−
1607−```
1608− ++ sufi :: domestic host
1609− $: hoy=(list ship) :: hierarchy
1610− val=wund :: private keys
1611− law=will :: server will
1612− seh=(map hand ,[p=ship q=@da]) :: key cache
1613− hoc=(map ship dore) :: neighborhood
1614− == ::
1615−```
1616−
1617−This is the security state of a domestic server.
1618−
1619−`hoy` is a list of the ships directly above us in the hierarchy of
1620−ships. For example, for `~hoclur-bicrel`, this would be `~tasruc` and
1621−`~tug`. See `++sein`.
1622−
1623−`val` is a list of our private keys.
1624−
1625−`law` is our certificate, which is a list of the XXX
1626−
1627−`seh`
1628−
1629−`hoc` is a map of ships to `++dore`. The stores all the security
1630−informatoin about foreign ships. The keys to this map are the neighbors
1631−(ships we have been in contact with) of this domestic server.
1632−
1633−### `++wund`, private keys
1634−
1635−```
1636− ++ wund (list ,[p=life q=ring r=acru]) :: mace in action
1637−```
1638−
1639−This is a list of our own private keys, indexed by life. The key itself
1640−is the `++ring`, and the `++acru` is the encryption engine. We generate
1641−the `++acru` from the private key by calling `++weur`. Thus, we can at
1642−any time regenerate our `++wund` from a `++mace`. The current crypto is
1643−at the head of the list and can be accessed with `++sen:as:go`.
1644−
1645−### `++ring`, private key
1646−
1647−```
1648− ++ ring ,@ :: private key
1649−```
1650−
1651−This is a private key. The first byte is reserved to identify the type
1652−of cryptography. Lower-case means public key, upper-case means public
1653−key, and the letter identifies which `++acru` to use.
1654−
1655−### `++pass`, public key
1656−
1657−```
1658− ++ pass ,@ :: public key
1659−```
1660−
1661−This is a public key. The first byte is reserved to identify the type of
1662−cryptography. Lower-case means public key, upper-case means public key,
1663−and the letter identifies which `++acru` to use.
1664−
1665−### `++mace`, private secrets
1666−
1667−```
1668− ++ mace (list ,[p=life q=ring]) :: private secrets
1669−```
1670−
1671−This is a list of the our private keys, indexed by life. From this we
1672−can generate a `++wund` for actual use.
1673−
1674−### `++skin`, encoding stem
1675−
1676−```
1677− ++ skin ?(%none %open %fast %full) :: encoding stem
1678−```
1679−
1680−This defines the type of encryption used for each message. `%none`
1681−refers to messages sent in the clear, `%open` refers to signed messages,
1682−`%full` refers to sealed messages, and `%fast` refers to symmetrically
1683−encrypted messages. See `++acru` for details.
1684−
1685−### `++acru`, asymmetric cryptosuite
1686−
1687−```
1688− ++ acru :: asym cryptosuite
1689− $_ ^? |% :: opaque object
1690− ++ as ^? :: asym ops
1691− |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a
1692− ++ sign |=([a=@ b=@] _@) :: certify as us
1693− ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us
1694− ++ tear |= [a=pass b=@] :: accept from a
1695− *(unit ,[p=@ q=@]) ::
1696− -- ::
1697− ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft
1698− ++ dy |+([a=@ b=@] _@) :: symmetric de, hard
1699− ++ en |+([a=@ b=@] _@) :: symmetric en
1700− ++ ex ^? :: export
1701− |% ++ fig _@uvH :: fingerprint
1702− ++ pac _@uvG :: default passcode
1703− ++ pub *pass :: public key
1704− ++ sec *ring :: private key
1705− --
1706− ++ nu ^? :: reconstructors
1707− |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed]
1708− ++ nol |=(a=@ ^?(..nu)) :: from naked ring
1709− ++ com |=(a=@ ^?(..nu)) :: from naked pass
1710− --
1711− --
1712−```
1713−
1714−This is an opaque interface for a general asymmetric cryptosuite. Any
1715−form of asymmetric cryptography can be dropped in to be used instead of
1716−the default. Right now, there are two cryptosuites, `++crua`, which is
1717−your standard RSA, and `++crub`, which is elliptic curve crypto but is
1718−mostly stubbed out at the moment.
1719−
1720−#### `++as:acru`, asymmetric operations
1721−
1722−```
1723− ++ as ^? :: asym ops
1724− |% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a
1725− ++ sign |=([a=@ b=@] _@) :: certify as us
1726− ++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us
1727− ++ tear |= [a=pass b=@] :: accept from a
1728− *(unit ,[p=@ q=@]) ::
1729− -- ::
1730−```
1731−
1732−This is the core that defines the standard asymmetric cryptography
1733−operations.
1734−
1735−`++seal:as:acru` allows us to send a message encrypted with someone's
1736−public key so that only they may read it. If Alice seals a message with
1737−Bob's public key, then she can be sure that Bob is the only one who can
1738−read it. This is associated with the `++skin` `%full`.
1739−
1740−`++sign:as:acru` allows us to sign a message with our private key so
1741−that others can verify that we sent the message. If Alice signs a
1742−message with her private key, then Bob can verify with her public key
1743−that it was indeed Alice who sent it. This is associated with the
1744−`++skin` `%open`.
1745−
1746−`++sure:as:acru` is the dual to `++sign:as:acru`. It allows us to verify
1747−that a message we have received is indeed from the claimed sender. If
1748−Alice sends a message with her private key, then Bob can use this arm to
1749−verify that it was indeed Alice who sent it. This is associated with the
1750−`++skin` `%open`.
1751−
1752−`++tear:as:acru` is the dual to `++seal:as:acru`. It allows us to read a
1753−message that we can be sure is only read by us. If Alice seals a message
1754−with Bob's public key, then Bob can use this arm to read it. This is
1755−associated with the `++skin` `%full`.
1756−
1757−#### `++de:acru`, `++dy:acru`, and `++en:acru`, symmetric encryption/decryption
1758−
1759−```
1760− ++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft
1761− ++ dy |+([a=@ b=@] _@) :: symmetric de, hard
1762− ++ en |+([a=@ b=@] _@) :: symmetric en
1763−```
1764−
1765−Symmetric encryption is associated with the `++skin` `%fast`.
1766−
1767−`++de:acru` decrypts a message with a symmetric key, returning `~` on
1768−failure and `[~ u=data]` on success.
1769−
1770−`++dy:acru` decrypts a message with a symmetric key, crashing on
1771−failure. This should almost always be defined as, and should always be
1772−semantically equivalent to, `(need (de a b))`.
1773−
1774−`++en:acru` encrypts a message with a symmetric key.
1775−
1776−#### `++ex:acru`, exporting data
1777−
1778−```
1779− ++ ex ^? :: export
1780− |% ++ fig _@uvH :: fingerprint
1781− ++ pac _@uvG :: default passcode
1782− ++ pub *pass :: public key
1783− ++ sec *ring :: private key
1784− --
1785−```
1786−
1787−`++fig:ex:acru` is our fingerprint, usually a hash of our public key.
1788−This is used, for example, in `++zeno`, where every carrier owner's
1789−fingerprint is stored so that we can ensure that carriers are indeed
1790−owned by their owners
1791−
1792−`++pac:ex:acru` is our default passcode, which is unused at present.
1793−
1794−`++pub:ex:acru` is the `++pass` form of our public key.
1795−
1796−`++sec:ex:acru` is the `++ring` form of our private key.
1797−
1798−#### `++nu:acru`, reconstructors
1799−
1800−```
1801− ++ nu ^? :: reconstructors
1802− |% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed]
1803− ++ nol |=(a=@ ^?(..nu)) :: from naked ring
1804− ++ com |=(a=@ ^?(..nu)) :: from naked pass
1805− --
1806−```
1807−
1808−These arms allow us to reconstruct a `++acru` from basic data.
1809−
1810−`++pit:nu:acru` constructs a `++acru` from the width of our intended key
1811−and seed entropy. This is usually used in the initial construction of
1812−the `++acru`.
1813−
1814−`++nol:nu:acru` constructs a `++acru` from a "naked ring", meaning a
1815−`++ring` without the initial byte identifying the type of crypto. There
1816−is often a helper arm that that wraps this; see `++weur` for `++crua`
1817−and `++wear` for `++crub`.
1818−
1819−`++com:nu:acru` constructs a `++acru` from a "naked pass", meaning a
1820−`++ring` without the initial byte identifying the type of crypto. There
1821−is often a helper arm that that wraps this; see `++haul` for `++crua`
1822−and `++hail` for `++crub`.
1823−
1824−### `++will`, certificate
1825−
1826−```
1827− ++ will (list deed) :: certificate
1828−```
1829−
1830−This is a list of deeds associated with the current ship. There should
1831−be an item in this list for every ship from this point up in the
1832−hierarchy times the number of lives that each ship has had. For example,
1833−\~hoclur-bicrel may have a will with three items: one for itself, one
1834−for \~tasruc (who issued \~hoclur-bicrel's deed) and one for \~tug (who
1835−issued \~tasruc's deed).
1836−
1837−### `++deed`, identity
1838−
1839−```
1840− ++ deed ,[p=@ q=step r=?] :: sig, stage, fake?
1841−```
1842−
1843−`p` is the signature of a particular deed, which is a signed copy of
1844−`q`.
1845−
1846−`q` is the stage in the identity.
1847−
1848−`r` is true if we're working on a fake network, where we don't check
1849−that the carrier fingerprints are correct. This allows us to create fake
1850−networks for development without interfering with the real network.
1851−
1852−### `++step`, identity stage
1853−
1854−```
1855− ++ step ,[p=bray q=gens r=pass] :: identity stage
1856−```
1857−
1858−This is a single stage in our identity. Thus, this is specific to a
1859−single life in a single ship. Everything in here may change between
1860−lives.
1861−
1862−`p`
1863−
1864−`q`
1865−
1866−`r` is the public key for this stage in the identity.
1867−
1868−### `++bray`
1869−
1870−```
1871− ++ bray ,[p=life q=(unit life) r=ship s=@da] :: our parent us now
1872−```
1873−
1874−XXX
1875−
1876−### `++gens`, general identity
1877−
1878−```
1879− ++ gens ,[p=lang q=gcos] :: general identity
1880−```
1881−
1882−`p` is the IETF language code for the preferred language of this
1883−identity. This is unused at the moment, but in the future text should be
1884−localized based on this.
1885−
1886−`q` is the description of the ship.
1887−
1888−### `++gcos`, identity description
1889−
1890−```
1891− ++ gcos :: id description
1892− $% [%czar ~] :: 8-bit ship
1893− [%duke p=what] :: 32-bit ship
1894− [%earl p=@t] :: 64-bit ship
1895− [%king p=@t] :: 16-bit ship
1896− [%pawn p=(unit ,@t)] :: 128-bit ship
1897− == ::
1898−```
1899−
1900−This is the description of the identity of a ship. Most types of
1901−identity have a `@t` field, which is their human-readable name. The
1902−identity of a `%duke` is more involved.
1903−
1904−A `%czar`, a carrier, is a ship with an 8-bit address. Thus, there are
1905−only 256 carriers. These are at the top of the namespace hierarchy, and
1906−the fingerprint of each carrier is stored in `++zeno`. These are the
1907−"senators" of Urbit.
1908−
1909−A `%king`, a cruiser, is a ship with a 16-bit address. Thus, there are
1910−65,536 cruisers. Each carrier may issue 256 cruisers. These are the
1911−infrastructure of Urbit.
1912−
1913−A `%duke`, a destroyer, is a ship with a 32-bit address. Thus, there are
1914−4,294,967,296 destroyers. Each cruiser may issue 65,536 cruisers. These
1915−are the individuals of Urbit.
1916−
1917−A `%earl`, a yacht, is a ship with a 64-bit address. Thus, there are
1918−18,446,744,073,709,551,616 yachts. Each destroyer may issue
1919−4,294,967,296 yachts. These are the devices of Urbit.
1920−
1921−A `%pawn`, a submarine, is a ship with a 128-bit address. Thus, there
1922−are a lot of submarines. The chance of random name collision is
1923−negligible, so submarines are not issued by any ship. They must simply
1924−assert their presence, and they are all considered children of \~zod.
1925−This is the underworld of Urbit, where anonymity reigns supreme.
1926−
1927−### `++what`, logical destroyer identity
1928−
1929−```
1930− ++ what :: logical identity
1931− $% [%anon ~] :: anonymous
1932− [%lady p=whom] :: female person ()
1933− [%lord p=whom] :: male person []
1934− [%punk p=sect q=@t] :: opaque handle ""
1935− == ::
1936−```
1937−
1938−This is the logical identity of a destroyer.
1939−
1940−A `%anon` is a completely anonymous destroyer. The difference between
1941−this and a submarine is that a submarine is ephemeral while a `%anon`
1942−destroyer is not. Thus, we may not know who \~hoclur-bicrel is, but we
1943−do know that it's always the same person.
1944−
1945−A `%lady` is a female person. The name used here should be a real name.
1946−
1947−A `%lord` is a male person. The name used here should be a real name.
1948−
1949−A `%punk` is a person who is identified only by a handle.
1950−
1951−### `++whom`, real person
1952−
1953−```
1954− ++ whom ,[p=@ud q=govt r=sect s=name] :: year/govt/id
1955−```
1956−
1957−Ths is the information associated with a real person. It is mostly
1958−information that could be observed with the briefest of interactions.
1959−
1960−`p` is the birth year.
1961−
1962−`q` is the location of a user, usually of the form "country/zip".
1963−
1964−`r` is the sect of the user.
1965−
1966−`s` is the real name of the person.
1967−
1968−### `++govt`
1969−
1970−```
1971− ++ govt path :: country/postcode
1972−```
1973−
1974−This is the location of the user, usually of the form "country/zip".
1975−
1976−### `++sect`
1977−
1978−```
1979− ++ sect ?(%black %blue %red %orange %white) :: banner
1980−```
1981−
1982−XXX
1983−
1984−### `++name`
1985−
1986−```
1987− ++ name ,[p=@t q=(unit ,@t) r=(unit ,@t) s=@t] :: first mid/nick last
1988−```
1989−
1990−This is the given name, possible middle name/initial, possible nickname,
1991−and surname of a user.
learn/arvo/arvo-internals/clay.udon+2611−1
@@ -25,4 +25,2614 @@ zuse. Second is the write, query, and subscription logic. Finally, there
2525is the logic for communicating requests to, and receiving requests from,
2626foreign ships.
2727
28−;list;
28+;=
29+ ;h2
30+ ;div(id "architecture"): Architecture
31+ ==
32+==
33+
34+Clay is the primary filesystem for the arvo operating system,
35+which is the core of an urbit. The architecture of clay is
36+intrinsically connected with arvo, but we assume no knowledge of
37+either arvo or urbit. We will point out only those features of
38+arvo that are necessary for an understanding of clay, and we will
39+do so only when they arise.
40+
41+The first relevant feature of arvo is that it is a deterministic
42+system where input and output are defined as a series of events
43+and effects. The state of arvo is simply a function of its event
44+log. None of the effects from an event are emitted until the
45+event is entered in the log and persisted, either to disk or
46+another trusted source of persistence, such as a Kafka cluster.
47+Consequently, arvo is a single-level store: everything in its
48+state is persistent.
49+
50+In a more traditional OS, everything in RAM can be erased at any
51+time by power failure, and is always erased on reboot. Thus, a
52+primary purpose of a filesystem is to ensure files persist across
53+power failures and reboots. In arvo, both power failures and
54+reboots are special cases of suspending computation, which is
55+done safely since our event log is already persistent. Therefore,
56+clay is not needed in arvo for persistence. Why, then, do we have a
57+filesystem? There are two answers to this question.
58+
59+First, clay provides a filesystem tree, which is a convenient
60+user interface for some applications. Unix has the useful concept
61+of virtual filesystems, which are used for everything from direct
62+access to devices, to random number generators, to the /proc
63+tree. It is easy and intuitive to read from and write to a
64+filesystem tree.
65+
66+Second, clay has a distributed revision control system baked into
67+it. Traditional filesystems are not revision controlled, so
68+userspace software -- such as git -- is written on top of them to
69+do so. clay natively provides the same functionality as modern
70+DVCSes, and more.
71+
72+clay has two other unique properties that we'll cover later on:
73+it supports typed data and is referentially transparent.
74+
75+### Revision Control
76+
77+Every urbit has one or more "desks", which are independently
78+revision-controlled branches. Each desk contains its own mark
79+definitions, apps, doc, and so forth.
80+
81+Traditionally, an urbit has at least a base and a home desk. The
82+base desk has all the system software from the distribution. the
83+home desk is a fork of base with all the stuff specific to the
84+user of the urbit.
85+
86+A desk is a series of numbered commits, the most recent of which
87+represents the current state of the desk. A commit is composed of
88+(1) an absolute time when it was created, (2) a list of zero or
89+more parents, and (3) a map from paths to data.
90+
91+Most commits have exactly one parent, but the initial commit on a
92+desk may have zero parents, and merge commits have more than one
93+parent.
94+
95+The non-meta data is stored in the map of paths to data. It's
96+worth noting that no constraints are put on this map, so, for
97+example, both /a/b and /a/b/c could have data. This is impossible
98+in a traditional Unix filesystem since it means that /a/b is both
99+a file and a directory. Conventionally, the final element in the
100+path is its mark -- much like a filename extension in Unix. Thus,
101+/doc/readme.md in Unix is stored as /doc/readme/md in urbit.
102+
103+The data is not stored directly in the map; rather, a hash of the
104+data is stored, and we maintain a master blob store. Thus, if the
105+same data is referred to in multiple commits (as, for example,
106+when a file doesn't change between commits), only the hash is
107+duplicated.
108+
109+In the master blob store, we either store the data directly, or
110+else we store a diff against another blob. The hash is dependent
111+only on the data within and not on whether or not it's stored
112+directly, so we may on occasion rearrange the contents of the
113+blob store for performance reasons.
114+
115+Recall that a desk is a series of numbered commits. Not every
116+commit in a desk must be numbered. For example, if the base desk
117+has had 50 commits since home was forked from it, then a merge
118+from base to home will only add a single revision number to home,
119+although the full commit history will be accessible by traversing
120+the parentage of the individual commits.
121+
122+We do guarantee that the first commit is numbered 1, commits are
123+numbered consecutively after that (i.e. there are no "holes"),
124+the topmost commit is always numbered, and every numbered commit
125+is an ancestor of every later numbered commit.
126+
127+There are three ways to refer to particular commits in the
128+revision history. Firstly, one can use the revision number.
129+Secondly, one can use any absolute time between the one numbered
130+commit and the next (inclusive of the first, exclusive of the
131+second). Thirdly, every desk has a map of labels to revision
132+numbers. These labels may be used to refer to specific commits.
133+
134+Additionally, clay is a global filesystem, so data on other urbit
135+is easily accessible the same way as data on our local urbit. In
136+general, the path to a particular revision of a desk is
137+/~urbit-name/desk-name/revision. Thus, to get /try/readme/md
138+from revision 5 of the home desk on ~sampel-sipnym, we refer to
139+/~sampel-sipnym/home/5/try/readme/md. Clay's namespace is thus
140+global and referentially transparent.
141+
142+XXX reactivity here?
143+
144+### A Typed Filesystem
145+
146+Since clay is a general filesystem for storing data of arbitrary
147+types, in order to revision control correctly it needs to be
148+aware of types all the way through. Traditional revision control
149+does an excellent job of handling source code, so for source code
150+we act very similar to traditional revision control. The
151+challenge is to handle other data similarly well.
152+
153+For example, modern VCSs generally support "binary files", which
154+are files for which the standard textual diffing, patching, and
155+merging algorithms are not helpful. A "diff" of two binary files
156+is just a pair of the files, "patching" this diff is just
157+replacing the old file with the new one, and "merging"
158+non-identical diffs is always a conflict, which can't even be
159+helpfully annotated. Without knowing anything about the structure
160+of a blob of data, this is the best we can do.
161+
162+Often, though, "binary" files have some internal structure, and
163+it is possible to create diff, patch, and merge algorithms that
164+take advantage of this structure. An image may be the result of a
165+base image with some set of operations applied. With algorithms
166+aware of this set of operations, not only can revision control
167+software save space by not having to save every revision of the
168+image individually, these transformations can be made on parallel
169+branches and merged at will.
170+
171+Suppose Alice is tasked with touching up a picture, improving the
172+color balance, adjusting the contrast, and so forth, while Bob
173+has the job of cropping the picture to fit where it's needed and
174+adding textual overlay. Without type-aware revision control,
175+these changes must be made serially, requiring Alice and Bob to
176+explicitly coordinate their efforts. With type-aware revision
177+control, these operations may be performed in parallel, and then
178+the two changesets can be merged programmatically.
179+
180+Of course, even some kinds of text files may be better served by
181+diff, patch, and merge algorithms aware of the structure of the
182+files. Consider a file containing a pretty-printed JSON object.
183+Small changes in the JSON object may result in rather significant
184+changes in how the object is pretty-printed (for example, by
185+addding an indentation level, splitting a single line into
186+multiple lines).
187+
188+A text file wrapped at 80 columns also reacts suboptimally with
189+unadorned Hunt-McIlroy diffs. A single word inserted in a
190+paragraph may push the final word or two of the line onto the
191+next line, and the entire rest of the paragraph may be flagged as
192+a change. Two diffs consisting of a single added word to
193+different sentences may be flagged as a conflict. In general,
194+prose should be diffed by sentence, not by line.
195+
196+As far as the author is aware, clay is the first generalized,
197+type-aware revision control system. We'll go into the workings
198+of this system in some detail.
199+
200+### Marks
201+
202+Central to a typed filesystem is the idea of types. In clay, we
203+call these "marks". A mark is a file that defines a type,
204+conversion routines to and from the mark, and diff, patch, and
205+merge routines.
206+
207+For example, a `%txt` mark may be a list of lines of text, and it
208+may include conversions to `%mime` to allow it to be serialized
209+and sent to a browswer or to the unix filesystem. It will also
210+include Hunt-McIlroy diff, patch, and merge algorithms.
211+
212+A `%json` mark would be defined as a json object in the code, and
213+it would have a parser to convert from `%txt` and a printer to
214+convert back to `%txt`. The diff, patch, and merge algorithms are
215+fairly straightforward for json, though they're very different
216+from the text ones.
217+
218+More formally, a mark is a core with three arms, `++grab`,
219+`++grow`, and `++grad`. In `++grab` is a series of functions to
220+convert from other marks to the given mark. In `++grow` is a
221+series of functions to convert from the given mark to other
222+marks. In `++grad` is `++diff`, `++pact`, `++join`, and `++mash`.
223+
224+The types are as follows, in an informal pseudocode:
225+
226+```
227+ ++ grab:
228+ ++ mime: <mime> -> <mark-type>
229+ ++ txt: <txt> -> <mark-type>
230+ ...
231+ ++ grow:
232+ ++ mime: <mark-type> -> <mime>
233+ ++ txt: <mark-type> -> <txt>
234+ ...
235+ ++ grad
236+ ++ diff: (<mark-type>, <mark-type>) -> <diff-type>
237+ ++ pact: (<mark-type>, <diff-type>) -> <mark-type>
238+ ++ join: (<diff-type>, <diff-type>) -> <diff-type> or NULL
239+ ++ mash: (<diff-type>, <diff-type>) -> <diff-type>
240+```
241+
242+These types are basically what you would expect. Not every mark
243+has each of these functions defined -- all of them are optional
244+in the general case.
245+
246+In general, for a particular mark, the `++grab` and `++grow` entries
247+(if they exist) should be inverses of each other.
248+
249+In `++grad`, `++diff` takes two instances of a mark and produces
250+a diff of them. `++pact` takes an instance of a mark and patches
251+it with the given diff. `++join` takes two diffs and attempts to
252+merge them into a single diff. If there are conflicts, it
253+produces null. `++mash` takes two diffs and forces a merge,
254+annotating any conflicts.
255+
256+In general, if `++diff` called with A and B produces diff D, then
257+`++pact` called with A and D should produce B. Also, if `++join`
258+of two diffs does not produce null, then `++mash` of the same
259+diffs should produce the same result.
260+
261+Alternately, instead of `++diff`, `++pact`, `++join`, and
262+`++mash`, a mark can provide the same functionality by defining
263+`++sted` to be the name of another mark to which we wish to
264+delegate the revision control responsibilities. Then, before
265+running any of those functions, clay will convert to the other
266+mark, and convert back afterward. For example, the `%hoon` mark
267+is revision-controlled in the same way as `%txt`, so its `++grad`
268+is simply `++sted %txt`. Of course, `++txt` must be defined in
269+`++grow` and `++grab` as well.
270+
271+Every file in clay has a mark, and that mark must have a
272+fully-functioning `++grad`. Marks are used for more than just
273+clay, and other marks don't need a `++grad`, but if a piece of
274+data is to be saved to clay, we must know how to revision-control
275+it.
276+
277+Additionally, if a file is to be synced out to unix, then it must
278+have conversion routines to and from the `%mime` mark.
279+
280+##Using clay
281+
282+### Reading and Subscribing
283+
284+When reading from Clay, there are three types of requests. A
285+`%sing` request asks for data at single revsion. A `%next`
286+request asks to be notified the next time there's a change to
287+given file. A `%many` request asks to be notified on every
288+change in a desk for a range of changes.
289+
290+For `%sing` and `%next`, there are generally three things to be
291+queried. A `%u` request simply checks for the existence of a
292+file at a path. A `%x` request gets the data in the file at a
293+path. A `%y` request gets a hash of the data in the file at the
294+path combined with all its children and their data. Thus, `%y`
295+of a node changes if it or any of its children change.
296+
297+A `%sing` request is fulfilled immediately if possible. If the
298+requested revision is in the future, or is on another ship for
299+which we don't have the result cached, we don't respond
300+immediately. If the requested revision is in the future, we wait
301+until the revision happens before we respond to the request. If
302+the request is for data on another ship, we pass on the request
303+to the other ship. In general, Clay subscriptions, like most
304+things in Urbit, aren't guaranteed to return immediately.
305+They'll return when they can, and they'll do so in a
306+referentially transparent manner.
307+
308+A `%next` request checks query at the given revision, and it
309+produces the result of the query the next time it changes, along
310+with the revsion number when it changes. Thus, a `%next` of a
311+`%u` is triggered when a file is added or deleted, a `%next` of a
312+`%x` is triggered when a file is added, deleted, or changed, and
313+a `%next` of a `%y` is triggered when a file or any of its
314+children is added, deleted, or changed.
315+
316+A `%many` request is triggered every time the given desk has a
317+new revision. Unlike a `%next`, a `%many` has both a start and
318+an end revsion, after which it stops returning. For `%next`, a
319+single change is reported, and if the caller wishes to hear of
320+the next change, it must resubscribe. For `%many`, every revsion
321+from the start to the end triggers a response. Since a `%many`
322+request doesn't ask for any particular data, there aren't `%u`,
323+`%x`, and `%y` versions for it.
324+
325+### Unix sync
326+
327+One of the primary functions of clay is as a convenient user
328+interface. While tools exist to use clay from within urbit, it's
329+often useful to be able to treat clay like any other filesystem
330+from the Unix perspective -- to "mount" it, as it were.
331+
332+From urbit, you can run `|mount /path/to/directory %mount-point`,
333+and this will mount the given clay directory to the mount-point
334+directory in Unix. Every file is converted to `%mime` before it's
335+written to Unix, and converted back when read from Unix. The
336+entire directory is watched (a la Dropbox), and every change is
337+auto-committed to clay.
338+
339+### Merging
340+
341+Merging is a fundamental operation for a distributed revision
342+control system. At their root, clay's merges are similar to
343+git's, but with some additions to accomodate typed data. There
344+are seven different merge strategies.
345+
346+Throughout our discussion, we'll say that the merge is from
347+Alice's desk to Bob's. Recall that a commit is a date (for all
348+new commits this will be the current date), a list of parents,
349+and the data itself.
350+
351+A `%init` merge should be used iff it's the first commit to a
352+desk. The head of Alice's desk is used as the number 1 commit to
353+Bob's desk. Obviously, the ancestry remains intact through
354+traversing the parentage of the commit even though previous
355+commits are not numbered for Bob's desk.
356+
357+A `%this` merge means to keep what's in Bob's desk, but join the
358+ancestry. Thus, the new commit has the head of each desk as
359+parents, but the data is exactly what's in Bob's desk. For those
360+following along in git, this is the 'ours' merge strategy, not
361+the '--ours' option to the 'recursive' merge strategy. In other
362+words, even if Alice makes a change that does not conflict with
363+Bob, we throw it away. It's Bob's way or the highway.
364+
365+A `%that` merge means to take what's in Alice's desk, but join
366+the ancestry. This is the reverse of `%this`.
367+
368+A `%fine` merge is a "fast-forward" merge. This succeeds iff one
369+head is in the ancestry of the other. In this case, we use the
370+descendant as our new head.
371+
372+For `%meet`, `%mate`, and `%meld` merges, we first find the most
373+recent common ancestor to use as our merge base. If we have no
374+common ancestors, then we fail. If we have more than one most
375+recent common ancestor, then we have a criss-cross situation,
376+which should be handled delicately. At present, we delicately
377+throw up our hands and give up, but something akin to git's
378+'recursive' strategy should be implemented in the future.
379+
380+There's a functional inclusion ordering on `%fine`, `%meet`,
381+`%mate`, and `%meld` such that if an earlier strategy would have
382+succeeded, then every later strategy will produce the same
383+result. Put another way, every earlier strategy is the same as
384+every later strategy except with a restricted domain.
385+
386+A `%meet` merge only succeeds if the changes from the merge base
387+to Alice's head (hereafter, "Alice's changes") are in different
388+files than Bob's changes. In this case, the parents are both
389+Alice's and Bob's heads, and the data is the merge base plus
390+Alice's changed files plus Bob's changed files.
391+
392+A `%mate` merge attempts to merge changes to the same file when
393+both Alice and bob change it. If the merge is clean, we use it;
394+otherwise, we fail. A merge between different types of changes --
395+for example, deleting a file vs changing it -- is always a
396+conflict. If we succeed, the parents are both Alice's and Bob's
397+heads, and the data is the merge base plus Alice's changed files
398+plus Bob's changed files plus the merged files.
399+
400+A `%meld` merge will succeed even if there are conflicts. If
401+there are conflicts in a file, then we use the merge base's
402+version of that file, and we produce a set of files with
403+conflicts. The parents are both Alice's and Bob's heads, and the
404+data is the merge base plus Alice's changed files plus Bob's
405+changed files plus the successfully merged files plus the merge
406+base's version of the conflicting files.
407+
408+That's the extent of the merge options in clay proper. In
409+userspace there's a final option `%auto`, which is the most
410+common. `%auto` checks to see if Bob's desk exists, and if it
411+doesn't we use a `%init` merge. Otherwise, we progressively try
412+`%fine`, `%meet`, and `%mate` until one succeeds.
413+
414+If none succeed, we merge Bob's desk into a scratch desk. Then,
415+we merge Alice's desk into the scratch desk with the `%meld`
416+option to force the merge. For each file in the produced set of
417+conflicting files, we call the `++mash` function for the
418+appropriate mark, which annotates the conflicts if we know how.
419+
420+Finally, we display a message to the user informing them of the
421+scratch desk's existence, which files have annotated conflicts,
422+and which files have unannotated conflicts. When the user has
423+resolved the conflicts, they can merge the scratch desk back into
424+Bob's desk. This will be a `%fine` merge since Bob's head is in
425+the ancestry of the scratch desk.
426+
427+### Autosync
428+
429+Tracking and staying in sync with another desk is another
430+fundamental operation. We call this "autosync". This doesn't mean
431+simply mirroring a desk, since that wouldn't allow local changes.
432+We simply want to apply changes as they are made upstream, as
433+long as there are no conflicts with local changes.
434+
435+This is implemented by watching the other desk, and, when it has
436+changes, merging these changes into our desk with the usual merge
437+strategies.
438+
439+Note that it's quite reasonable for two desks to be autosynced to
440+each other. This results in any change on one desk being mirrored
441+to the other and vice versa.
442+
443+Additionally, it's fine to set up an autosync even if one desk,
444+the other desk, or both desks do not exist. The sync will be
445+activated when the upstream desk comes into existence and will
446+create the downstream desk if needed.
447+
448+;=
449+ ;h2
450+ ;div(id "commentary"): Commentary
451+ ==
452+==
453+
454+The first part of this section will be reference documentation for the data
455+types used by our filesystem. In fact, as a general guide, we recommend
456+reading and attempting to understand the data structures used in any
457+Hoon code before you try to read the code itself. Although complete
458+understanding of the data structures is impossible without seeing them
459+used in the code, an 80% understanding greatly clarifies the code. As
460+another general guide, when reading Hoon, it rarely pays off to
461+understand every line of code when it appears. Try to get the gist of
462+it, and then move on. The next time you come back to it, it'll likely
463+make a lot more sense.
464+
465+After a description of the data models, we'll give an overview of the
466+interface that vanes and applications can use to interact with the
467+filesystem.
468+
469+Finally, we'll dive into the code and the algorithms themselves. You
470+know, the fun part.
471+
472+### Data Models
473+
474+As you're reading through this section, remember you can always come
475+back to this when you run into these types later on. You're not going to
476+remember everything the first time through, but it is worth reading, or
477+at least skimming, this so that you get a rough idea of how our state is
478+organized.
479+
480+The types that are certainly worth reading are `++raft`, `++room`,
481+`++dome`, `++ankh`, `++rung`, `++rang`, `++blob`, `++yaki`, and `++nori`
482+(possibly in that order). All in all, though, this section isn't too
483+long, so many readers may wish to quickly read through all of it. If you
484+get bored, though, just skip to the next section. You can always come
485+back when you need to.
486+
487+### `++raft`, formal state
488+
489+```
490+ ++ raft :: filesystem
491+ $: fat=(map ship room) :: domestic
492+ hoy=(map ship rung) :: foreign
493+ ran=rang :: hashes
494+ == ::
495+```
496+
497+This is the state of our vane. Anything that must be remembered between
498+calls to clay is stored in this state.
499+
500+`fat` is the set of domestic servers. This stores all the information
501+that is specfic to a particular ship on this pier. The keys to this map
502+are the ships on the current pier. all the information that is specific
503+to a particular foreign ship. The keys to this map are all the ships
504+whose filesystems we have attempted to access through clay.
505+
506+`ran` is the store of all commits and deltas, keyed by hash. The is
507+where all the "real" data we know is stored; the rest is "just
508+bookkeeping".
509+
510+#### `++room`, filesystem per domestic ship
511+
512+```
513+ ++ room :: fs per ship
514+ $: hun=duct :: terminal duct
515+ hez=(unit duct) :: sync duch
516+ dos=(map desk dojo) :: native desk
517+ == ::
518+```
519+
520+This is the representation of the filesystem of a ship on our pier.
521+
522+`hun` is the duct we use to send messages to dill to display
523+notifications of filesystem changes. Only `%note` gifts should be
524+produced along this duct. This is set by the `%init` kiss.
525+
526+`hez`, if present, is the duct we use to send sync messages to unix so
527+that they end up in the pier unix directory. Only `%ergo` gifts should
528+be producd along this duct. This is set by `%into` and `%invo` kisses.
529+
530+`dos` is a well-known operating system released in 1981. It is also the
531+set of desks on this ship, mapped to their data.
532+
533+#### `++desk`, filesystem branch
534+
535+```
536+ ++ desk ,@tas :: ship desk case spur
537+```
538+
539+This is the name of a branch of the filesystem. The default desks are
540+"arvo", "main", and "try". More may be created by simply referencing
541+them. Desks have independent histories and states, and they may be
542+merged into each other.
543+
544+### `++dojo`, domestic desk state
545+
546+```
547+ ++ dojo ,[p=cult q=dome] :: domestic desk state
548+```
549+
550+This is the all the data that is specific to a particular desk on a
551+domestic ship. `p` is the set of subscribers to this desk and `q` is the
552+data in the desk.
553+
554+#### `++cult`, subscriptions
555+
556+```
557+ ++ cult (map duct rave) :: subscriptions
558+```
559+
560+This is the set of subscriptions to a particular desk. The keys are the
561+ducts from where the subscriptions requests came. The results will be
562+produced along these ducts. The values are a description of the
563+requested information.
564+
565+#### `++rave`, general subscription request
566+
567+```
568+ ++ rave :: general request
569+ $% [& p=mood] :: single request
570+ [| p=moat] :: change range
571+ == ::
572+```
573+
574+This represents a subscription request for a desk. The request can be
575+for either a single item in the desk or else for a range of changes on
576+the desk.
577+
578+### `++rove`, stored general subscription request
579+
580+```
581+ ++ rove (each mood moot) :: stored request
582+```
583+
584+When we store a request, we store subscriptions with a little extra
585+information so that we can determine whether new versions actually
586+affect the path we're subscribed to.
587+
588+#### `++mood`, single subscription request
589+
590+```
591+ ++ mood ,[p=care q=case r=path] :: request in desk
592+```
593+
594+This represents a request for the state of the desk at a particular
595+commit, specfied by `q`. `p` specifies what kind of information is
596+desired, and `r` specifies the path we are requesting.
597+
598+#### `++moat`, range subscription request
599+
600+```
601+ ++ moat ,[p=case q=case r=path] :: change range
602+```
603+
604+This represents a request for all changes between `p` and `q` on path
605+`r`. You will be notified when a change is made to the node referenced
606+by the path or to any of its children.
607+
608+### `++moot`, stored range subscription request
609+
610+```
611+ ++ moot ,[p=case q=case r=path s=(map path lobe)] ::
612+```
613+
614+This is just a `++moat` plus a map of paths to lobes. This map
615+represents the data at the node referenced by the path at case `p`, if
616+we've gotten to that case (else null). We only send a notification along
617+the subscription if the data at a new revision is different than it was.
618+
619+### ` `++care`, clay submode
620+
621+```
622+ ++ care ?(%u %v %w %x %y %z) :: clay submode
623+```
624+
625+This specifies what type of information is requested in a subscription
626+or a scry.
627+
628+`%u` requests the `++rang` at the current moment. Because this
629+information is not stored for any moment other than the present, we
630+crash if the `++case` is not a `%da` for now.
631+
632+`%v` requests the `++dome` at the specified commit.
633+
634+`%w` requests the revsion number of the desk.
635+
636+`%x` requests the file at a specified path at the specified commit. If
637+there is no node at that path or if the node has no contents (that is,
638+if `q:ankh` is null), then this produces null.
639+
640+`%y` requests a `++arch` of the specfied commit at the specified path.
641+
642+`%z` requests the `++ankh` of the specified commit at the specfied path.
643+
644+### `++arch`, shallow filesystem node
645+
646+```
647+ ++ arch ,[p=@uvI q=(unit ,@uvI) r=(map ,@ta ,~)] :: fundamental node
648+```
649+
650+This is analogous to `++ankh` except that the we have neither our
651+contents nor the ankhs of our children. The other fields are exactly the
652+same, so `p` is a hash of the associated ankh, `u.q`, if it exists, is a
653+hash of the contents of this node, and the keys of `r` are the names of
654+our children. `r` is a map to null rather than a set so that the
655+ordering of the map will be equivalent to that of `r:ankh`, allowing
656+efficient conversion.
657+
658+#### `++case`, specifying a commit
659+
660+```
661+ ++ case :: ship desk case spur
662+ $% [%da p=@da] :: date
663+ [%tas p=@tas] :: label
664+ [%ud p=@ud] :: number
665+ == ::
666+```
667+
668+A commit can be referred to in three ways: `%da` refers to the commit
669+that was at the head on date `p`, `%tas` refers to the commit labeled
670+`p`, and `%ud` refers to the commit numbered `p`. Note that since these
671+all can be reduced down to a `%ud`, only numbered commits may be
672+referenced with a `++case`.
673+
674+#### `++dome`, desk data
675+
676+```
677+ ++ dome :: project state
678+ $: ang=agon :: pedigree
679+ ank=ankh :: state
680+ let=@ud :: top id
681+ hit=(map ,@ud tako) :: changes by id
682+ lab=(map ,@tas ,@ud) :: labels
683+ == ::
684+```
685+
686+This is the data that is actually stored in a desk.
687+
688+`ang` is unused and should be removed.
689+
690+`ank` is the current state of the desk. Thus, it is the state of the
691+filesystem at revison `let`. The head of a desk is always a numbered
692+commit.
693+
694+`let` is the number of the most recently numbered commit. This is also
695+the total number of numbered commits.
696+
697+`hit` is a map of numerical ids to hashes of commits. These hashes are
698+mapped into their associated commits in `hut:rang`. In general, the keys
699+of this map are exactly the numbers from 1 to `let`, with no gaps. Of
700+course, when there are no numbered commits, `let` is 0, so `hit` is
701+null. Additionally, each of the commits is an ancestor of every commit
702+numbered greater than this one. Thus, each is a descendant of every
703+commit numbered less than this one. Since it is true that the date in
704+each commit (`t:yaki`) is no earlier than that of each of its parents,
705+the numbered commits are totally ordered in the same way by both
706+pedigree and date. Of course, not every commit is numbered. If that
707+sounds too complicated to you, don't worry about it. It basically
708+behaves exactly as you would expect.
709+
710+`lab` is a map of textual labels to numbered commits. Note that labels
711+can only be applied to numbered commits. Labels must be unique across a
712+desk.
713+
714+#### `++ankh`, filesystem node
715+
716+```
717+ ++ ankh :: fs node (new)
718+ $: p=cash :: recursive hash
719+ q=(unit ,[p=cash q=*]) :: file
720+ r=(map ,@ta ankh) :: folders
721+ == ::
722+```
723+
724+This is a single node in the filesystem. This may be file or a directory
725+or both. In earth filesystems, a node is a file xor a directory. On
726+mars, we're inclusive, so a node is a file ior a directory.
727+
728+`p` is a recursive hash that depends on the contents of the this file or
729+directory and on any children.
730+
731+`q` is the contents of this file, if any. `p.q` is a hash of the
732+contents while `q.q` is the data itself.
733+
734+`r` is the set of children of this node. In the case of a pure file,
735+this is empty. The keys are the names of the children and the values
736+are, recursively, the nodes themselves.
737+
738+#### `++cash`, ankh hash
739+
740+```
741+ ++ cash ,@uvH :: ankh hash
742+```
743+
744+This is a 128-bit hash of an ankh. These are mostly stored within ankhs
745+themselves, and they are used to check for changes in possibly-deep
746+hierarchies.
747+
748+#### `++rung`, filesystem per neighbor ship
749+
750+```
751+ ++ rung $: rus=(map desk rede) :: neighbor desks
752+ == ::
753+```
754+
755+This is the filesystem of a neighbor ship. The keys to this map are all
756+the desks we know about on their ship.
757+
758+#### `++rede`, desk state
759+
760+```
761+ ++ rede :: universal project
762+ $: lim=@da :: complete to
763+ qyx=cult :: subscribers
764+ ref=(unit rind) :: outgoing requests
765+ dom=dome :: revision state
766+ == ::
767+```
768+
769+This is our knowledge of the state of a desk, either foreign or
770+domestic.
771+
772+`lim` is the date of the last full update. We only respond to requests
773+for stuff before this time.
774+
775+`qyx` is the list of subscribers to this desk. For domestic desks, this
776+is simply `p:dojo`, all subscribers to the desk, while in foreign desks
777+this is all the subscribers from our ship to the foreign desk.
778+
779+`ref` is the request manager for the desk. For domestic desks, this is
780+null since we handle requests ourselves.
781+
782+`dom` is the actual data in the desk.
783+
784+#### `++rind`, request manager
785+
786+```
787+ ++ rind :: request manager
788+ $: nix=@ud :: request index
789+ bom=(map ,@ud ,[p=duct q=rave]) :: outstanding
790+ fod=(map duct ,@ud) :: current requests
791+ haw=(map mood (unit)) :: simple cache
792+ == ::
793+```
794+
795+This is the request manager for a foreign desk.
796+
797+`nix` is one more than the index of the most recent request. Thus, it is
798+the next available request number.
799+
800+`bom` is the set of outstanding requests. The keys of this map are some
801+subset of the numbers between 0 and one less than `nix`. The members of
802+the map are exactly those requests that have not yet been fully
803+satisfied.
804+
805+`fod` is the same set as `bom`, but from a different perspective. In
806+particular, the values of `fod` are the same as the values of `bom`, and
807+the `p` out of the values of `bom` are the same as the keys of `fod`.
808+Thus, we can map ducts to their associated request number and `++rave`,
809+and we can map numbers to their associated duct and `++rave`.
810+
811+`haw` is a map from simple requests to their values. This acts as a
812+cache for requests that have already been made. Thus, the second request
813+for a particular `++mood` is nearly instantaneous.
814+
815+#### `++rang`, data store
816+
817+```
818+ ++ rang $: hut=(map tako yaki) ::
819+ lat=(map lobe blob) ::
820+ == ::
821+```
822+
823+This is a set of data keyed by hash. Thus, this is where the "real" data
824+is stored, but it is only meaningful if we know the hash of what we're
825+looking for.
826+
827+`hut` is a map from hashes to commits. We often get the hashes from
828+`hit:dome`, which keys them by logical id. Not every commit has an id.
829+
830+`lat` is a map from hashes to the actual data. We often get the hashes
831+from a `++yaki`, a commit, which references this map to get the data.
832+There is no `++blob` in any `++yaki`. They are only accessible through
833+this map.
834+
835+#### `++tako`, commit reference
836+
837+```
838+ ++ tako ,@ :: yaki ref
839+```
840+
841+This is a hash of a `++yaki`, a commit. These are most notably used as
842+the keys in `hut:rang`, where they are associated with the actual
843+`++yaki`, and as the values in `hit:dome`, where sequential ids are
844+associated with these.
845+
846+#### `++yaki`, commit
847+
848+```
849+ ++ yaki ,[p=(list tako) q=(map path lobe) r=tako t=@da] :: commit
850+```
851+
852+This is a single commit.
853+
854+`p` is a list of the hashes of the parents of this commit. In most
855+cases, this will be a single commit, but in a merge there may be more
856+parents. In theory, there may be an arbitrary number of parents, but in
857+practice merges have exactly two parents. This may change in the future.
858+For commit 1, there is no parent.
859+
860+`q` is a map of the paths on a desk to the data at that location. If you
861+understand what a `++lobe` and a `++blob` is, then the type signature
862+here tells the whole story.
863+
864+`r` is the hash associated with this commit.
865+
866+`t` is the date at which this commit was made.
867+
868+#### `++lobe`, data reference
869+
870+```
871+ ++ lobe ,@ :: blob ref
872+```
873+
874+This is a hash of a `++blob`. These are most notably used in `lat:rang`,
875+where they are associated with the actual `++blob`, and as the values in
876+`q:yaki`, where paths are associated with their data in a commit.
877+
878+#### `++blob`, data
879+
880+```
881+ ++ blob $% [%delta p=lobe q=lobe r=udon] :: delta on q
882+ [%direct p=lobe q=* r=umph] ::
883+ [%indirect p=lobe q=* r=udon s=lobe] ::
884+ == ::
885+```
886+
887+This is a node of data. In every case, `p` is the hash of the blob.
888+
889+`%delta` is the case where we define the data by a delta on other data.
890+In practice, the other data is always the previous commit, but nothing
891+depends on this. `q` is the hash of the parent blob, and `r` is the
892+delta.
893+
894+`%direct` is the case where we simply have the data directly. `q` is the
895+data itself, and `r` is any preprocessing instructions. These almost
896+always come from the creation of a file.
897+
898+`%indirect` is both of the preceding cases at once. `q` is the direct
899+data, `r` is the delta, and `s` is the parent blob. It should always be
900+the case that applying `r` to `s` gives the same data as `q` directly
901+(with the prepreprocessor instructions in `p.r`). This exists purely for
902+performance reasons. This is unused, at the moment, but in general these
903+should be created when there are a long line of changes so that we do
904+not have to traverse the delta chain back to the creation of the file.
905+
906+#### `++udon`, abstract delta
907+
908+```
909+ ++ udon :: abstract delta
910+ $: p=umph :: preprocessor
911+ $= q :: patch
912+ $% [%a p=* q=*] :: trivial replace
913+ [%b p=udal] :: atomic indel
914+ [%c p=(urge)] :: list indel
915+ [%d p=upas q=upas] :: tree edit
916+ == ::
917+ == ::
918+```
919+
920+This is an abstract change to a file. This is a superset of what would
921+normally be called diffs. Diffs usually refer to changes in lines of
922+text while we have the ability to do more interesting deltas on
923+arbitrary data structures.
924+
925+`p` is any preprocessor instructions.
926+
927+`%a` refers to the trival delta of a complete replace of old data with
928+new data.
929+
930+`%b` refers to changes in an opaque atom on the block level. This has
931+very limited usefulness, and is not used at the moment.
932+
933+`%c` refers to changes in a list of data. This is often lines of text,
934+which is your classic diff. We, however, will work on any list of data.
935+
936+`%d` refers to changes in a tree of data. This is general enough to
937+describe changes to any hoon noun, but often more special-purpose delta
938+should be created for different content types. This is not used at the
939+moment, and may in fact be unimplemented.
940+
941+#### `++urge`, list change
942+
943+```
944+ ++ urge |*(a=_,* (list (unce a))) :: list change
945+```
946+
947+This is a parametrized type for list changes. For example, `(urge ,@t)`
948+is a list change for lines of text.
949+
950+#### `++unce`, change part of a list.
951+
952+```
953+ ++ unce |* a=_,* :: change part
954+ $% [%& p=@ud] :: skip[copy]
955+ [%| p=(list a) q=(list a)] :: p -> q[chunk]
956+ == ::
957+```
958+
959+This is a single change in a list of elements of type `a`. For example,
960+`(unce ,@t)` is a single change in a lines of text.
961+
962+`%&` means the next `p` lines are unchanged.
963+
964+`%|` means the lines `p` have changed to `q`.
965+
966+#### `++umph`, preprocessing information
967+
968+```
969+ ++ umph :: change filter
970+ $| $? %a :: no filter
971+ %b :: jamfile
972+ %c :: LF text
973+ == ::
974+ $% [%d p=@ud] :: blocklist
975+ == ::
976+```
977+
978+This space intentionally left undocumented. This stuff will change once
979+we get a well-typed clay.
980+
981+#### `++upas`, tree change
982+
983+```
984+ ++ upas :: tree change (%d)
985+ $& [p=upas q=upas] :: cell
986+ $% [%0 p=axis] :: copy old
987+ [%1 p=*] :: insert new
988+ [%2 p=axis q=udon] :: mutate!
989+ == ::
990+```
991+
992+This space intentionally left undocumented. This stuff is not known to
993+work, and will likely change when we get a well-typed clay. Also, this
994+is not a complicated type; it is not difficult to work out the meaning.
995+
996+#### `++nori`, repository action
997+
998+```
999+ ++ nori :: repository action
1000+ $% [& q=soba] :: delta
1001+ [| p=@tas] :: label
1002+ == ::
1003+```
1004+
1005+This describes a change that we are asking clay to make to the desk.
1006+There are two kinds of changes that may be made: we can modify files or
1007+we can apply a label to a commit.
1008+
1009+In the `|` case, we will simply label the current commit with the given
1010+label. In the `&` case, we will apply the given changes.
1011+
1012+#### `++soba`, delta
1013+
1014+```
1015+ ++ soba ,[p=cart q=(list ,[p=path q=miso])] :: delta
1016+```
1017+
1018+This describes a set of changes to make to a desk. The `cart` is simply
1019+a pair of the old hash and the new hash of the desk. The list is a list
1020+of changes keyed by the file they're changing. Thus, the paths are paths
1021+to files to be changed while `miso` is a description of the change
1022+itself.
1023+
1024+#### `++miso`, ankh delta
1025+
1026+```
1027+ ++ miso :: ankh delta
1028+ $% [%del p=*] :: delete
1029+ [%ins p=*] :: insert
1030+ [%mut p=udon] :: mutate
1031+ == ::
1032+```
1033+
1034+There are three kinds of changes that may be made to a node in a desk.
1035+We can insert a file, in which case `p` is the contents of the new file.
1036+We can delete a file, in which case `p` is the contents of the old file.
1037+Finally, we can mutate that file, in which case the `udon` describes the
1038+changes we are applying to the file.
1039+
1040+#### `++mizu`, merged state
1041+
1042+```
1043+ ++ mizu ,[p=@u q=(map ,@ud tako) r=rang] :: new state
1044+```
1045+
1046+This is the input to the `%merg` kiss, which allows us to perform a
1047+merge. The `p` is the number of the new head commit. The `q` is a map
1048+from numbers to commit hashes. This is all the new numbered commits that
1049+are to be inserted. The keys to this should always be the numbers from
1050+`let.dom` plus one to `p`, inclusive. The `r` is the maps of all the new
1051+commits and data. Since these are merged into the current state, no old
1052+commits or data need be here.
1053+
1054+#### `++riff`, request/desist
1055+
1056+```
1057+ ++ riff ,[p=desk q=(unit rave)] :: request/desist
1058+```
1059+
1060+This represents a request for data about a particular desk. If `q`
1061+contains a `rave`, then this opens a subscription to the desk for that
1062+data. If `q` is null, then this tells clay to cancel the subscription
1063+along this duct.
1064+
1065+#### `++riot`, response
1066+
1067+```
1068+ ++ riot (unit rant) :: response/complete
1069+```
1070+
1071+A riot is a response to a subscription. If null, the subscription has
1072+been completed, and no more responses will be sent. Otherwise, the
1073+`rant` is the produced data.
1074+
1075+#### `++rant`, response data
1076+
1077+```
1078+ ++ rant :: namespace binding
1079+ $: p=[p=care q=case r=@tas] :: clade release book
1080+ q=path :: spur
1081+ r=* :: data
1082+ == ::
1083+```
1084+
1085+This is the data at a particular node in the filesystem. `p.p` specifies
1086+the type of data that was requested (and is produced). `q.p` gives the
1087+specific version reported (since a range of versions may be requested in
1088+a subscription). `r.p` is the desk. `q` is the path to the filesystem
1089+node. `r` is the data itself (in the format specified by `p.p`).
1090+
1091+### `++nako`, subscription response data
1092+
1093+```
1094+ ++ nako $: gar=(map ,@ud tako) :: new ids
1095+ let=@ud :: next id
1096+ lar=(set yaki) :: new commits
1097+ bar=(set blob) :: new content
1098+ == ::
1099+```
1100+
1101+This is the data that is produced by a request for a range of revisions
1102+of a desk. This allows us to easily keep track of a remote repository --
1103+all the new information we need is contained in the `nako`.
1104+
1105+`gar` is a map of the revisions in the range to the hash of the commit
1106+at that revision. These hashes can be used with `hut:rang` to find the
1107+commit itself.
1108+
1109+`let` is either the last revision number in the range or the most recent
1110+revision number, whichever is smaller.
1111+
1112+`lar` is the set of new commits, and `bar` is the set of new content.
1113+
1114+## Public Interface
1115+
1116+As with all vanes, there are exactly two ways to interact with clay.
1117+`%clay` exports a namespace accessible through `.^`, which is described
1118+above under `++care`. The primary way of interacting with clay, though,
1119+is by sending kisses and receiving gifts.
1120+
1121+```
1122+ ++ gift :: out result <-$
1123+ $% [%ergo p=@p q=@tas r=@ud] :: version update
1124+ [%note p=@tD q=tank] :: debug message
1125+ [%writ p=riot] :: response
1126+ == ::
1127+ ++ kiss :: in request ->$
1128+ $% [%info p=@p q=@tas r=nori] :: internal edit
1129+ [%ingo p=@p q=@tas r=nori] :: internal noun edit
1130+ [%init p=@p] :: report install
1131+ [%into p=@p q=@tas r=nori] :: external edit
1132+ [%invo p=@p q=@tas r=nori] :: external noun edit
1133+ [%merg p=@p q=@tas r=mizu] :: internal change
1134+ [%wart p=sock q=@tas r=path s=*] :: network request
1135+ [%warp p=sock q=riff] :: file request
1136+ == ::
1137+```
1138+
1139+There are only a small number of possible kisses, so it behooves us to
1140+describe each in detail.
1141+
1142+```
1143+ $% [%info p=@p q=@tas r=nori] :: internal edit
1144+
1145+ [%into p=@p q=@tas r=nori] :: external edit
1146+```
1147+
1148+These two kisses are nearly identical. At a high level, they apply
1149+changes to the filesystem. Whenever we add, remove, or edit a file, one
1150+of these cards is sent. The `p` is the ship whose filesystem we're
1151+trying to change, the `q` is the desk we're changing, and the `r` is the
1152+request change. For the format of the requested change, see the
1153+documentation for `++nori` above.
1154+
1155+When a file is changed in the unix filesystem, vere will send a `%into`
1156+kiss. This tells clay that the duct over which the kiss was sent is the
1157+duct that unix is listening on for changes. From within Arvo, though, we
1158+should never send a `%into` kiss. The `%info` kiss is exactly identical
1159+except it does not reset the duct.
1160+
1161+```
1162+ [%ingo p=@p q=@tas r=nori] :: internal noun edit
1163+
1164+ [%invo p=@p q=@tas r=nori] :: external noun edit
1165+```
1166+
1167+These kisses are currently identical to `%info` and `%into`, though this
1168+will not always be the case. The intent is for these kisses to allow
1169+typed changes to clay so that we may store typed data. This is currently
1170+unimplemented.
1171+
1172+```
1173+ [%init p=@p] :: report install
1174+```
1175+
1176+Init is called when a ship is started on our pier. This simply creates a
1177+default `room` to go into our `raft`. Essentially, this initializes the
1178+filesystem for a ship.
1179+
1180+```
1181+ [%merg p=@p q=@tas r=mizu] :: internal change
1182+```
1183+
1184+This is called to perform a merge. This is most visibly called by
1185+:update to update the filesystem of the current ship to that of its
1186+sein. The `p` and `q` are as in `%info`, and the `r` is the description
1187+of the merge. See `++mizu` above.
1188+
1189+XX
1190+`XX [%wake ~] :: timer activate XX`
1191+XX\
1192+XX This card is sent by unix at the time specified by `++doze`. This
1193+time is XX usually the closest time specified in a subscription request.
1194+When `%wake` is XX called, we update our subscribers if there have been
1195+any changes.
1196+
1197+```
1198+ [%wart p=sock q=@tas r=path s=*] :: network request
1199+```
1200+
1201+This is a request that has come across the network for a particular
1202+file. When another ship asks for a file from us, that request comes to
1203+us in the form of a `%wart` kiss. This is handled by trivially turning
1204+it into a `%warp`.
1205+
1206+```
1207+ [%warp p=sock q=riff] :: file request
1208+```
1209+
1210+This is a request for information about a particular desk. This is, in
1211+its most general form, a subscription, though in many cases it is the
1212+trivial case of a subscription -- a read. See `++riff` for the format of
1213+the request.
1214+
1215+## Lifecycle of a Local Read
1216+
1217+There are two real types of interaction with a filesystem: you can read,
1218+and you can write. We'll describe each process, detailing both the flow
1219+of control followed by the kernel and the algorithms involved. The
1220+simpler case is that of the read, so we'll begin with that.
1221+
1222+When a vane or an application wishes to read a file from the filesystem,
1223+it sends a `%warp` kiss, as described above. Of course, you may request
1224+a file on another ship and, being a global filesystem, clay will happily
1225+produce it for you. That code pathway will be described in another
1226+section; here, we will restrict ourselves to examining the case of a
1227+read from a ship on our own pier.
1228+
1229+The kiss can request either a single version of a file node or a range
1230+of versions of a desk. Here, we'll deal only with a request for a single
1231+version.
1232+
1233+As in all vanes, a kiss enters clay via a call to `++call`. Scanning
1234+through the arm, we quickly see where `%warp` is handled.
1235+
1236+```
1237+ ?: =(p.p.q.hic q.p.q.hic)
1238+ =+ une=(un p.p.q.hic now ruf)
1239+ =+ wex=(di:une p.q.q.hic)
1240+ =+ ^= wao
1241+ ?~ q.q.q.hic
1242+ (ease:wex hen)
1243+ (eave:wex hen u.q.q.q.hic)
1244+ =+ ^= woo
1245+ abet:wao
1246+ [-.woo abet:(pish:une p.q.q.hic +.woo ran.wao)]
1247+```
1248+
1249+We're following the familar patern of producing a list of moves and an
1250+updated state. In this case, the state is `++raft`.
1251+
1252+We first check to see if the sending and receiving ships are the same.
1253+If they're not, then this is a request for data on another ship. We
1254+describe that process later. Here, we discuss only the case of a local
1255+read.
1256+
1257+At a high level, the call to `++un` sets up the core for the domestic
1258+ship that contains the files we're looking for. The call to `++di` sets
1259+up the core for the particular desk we're referring to.
1260+
1261+After this, we perform the actual request. If there is no rave in the
1262+riff, then that means we are cancelling a request, so we call
1263+`++ease:de`. Otherwise, we start a subscription with `++eave:de`. We
1264+call `++abet:de` to resolve our various types of output into actual
1265+moves. We produce the moves we found above and the `++un` core resolved
1266+with `++pish:un` (putting the modified desk in the room) and `++abet:un`
1267+(putting the modified room in the raft).
1268+
1269+Much of this is fairly straightforward, so we'll only describe `++ease`,
1270+`++eave`, and `++abet:de`. Feel free to look up the code to the other
1271+steps -- it should be easy to follow.
1272+
1273+Although it's called last, it's usually worth examining `++abet` first,
1274+since it defines in what ways we can cause side effects. Let's do that,
1275+and also a few of the lines at the beginning of `++de`.
1276+
1277+```
1278+ =| yel=(list ,[p=duct q=gift])
1279+ =| byn=(list ,[p=duct q=riot])
1280+ =| vag=(list ,[p=duct q=gift])
1281+ =| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]])
1282+ =| tag=(list ,[p=duct q=path c=note])
1283+ |%
1284+ ++ abet
1285+ ^- [(list move) rede]
1286+ :_ red
1287+ ;: weld
1288+ %+ turn (flop yel)
1289+ |=([a=duct b=gift] [hun %give b])
1290+ ::
1291+ %+ turn (flop byn)
1292+ |=([a=duct b=riot] [a %give [%writ b]])
1293+ ::
1294+ %+ turn (flop vag)
1295+ |=([a=duct b=gift] [a %give b])
1296+ ::
1297+ %+ turn (flop say)
1298+ |= [a=duct b=path c=ship d=[p=@ud q=riff]]
1299+ :- a
1300+ [%pass b %a %want [who c] [%q %re p.q.d (scot %ud p.d) ~] q.d]
1301+ ::
1302+ %+ turn (flop tag)
1303+ |=([a=duct b=path c=note] [a %pass b c])
1304+ ==
1305+```
1306+
1307+This is very simple code. We see there are exactly five different kinds
1308+of side effects we can generate.
1309+
1310+In `yel` we put gifts that we wish to be sent along the `hun:room` duct
1311+to dill. See the documentation for `++room` above. This is how we
1312+display messages to the terminal.
1313+
1314+In `byn` we put riots that we wish returned to subscribers. Recall that
1315+a riot is a response to a subscription. These are returned to our
1316+subscribers in the form of a `%writ` gift.
1317+
1318+In `vag` we put gifts along with the ducts on which to send them. This
1319+allows us to produce arbitrary gifts, but in practice this is only used
1320+to produce `%ergo` gifts.
1321+
1322+In `say` we put messages we wish to pass to ames. These messages are
1323+used to request information from clay on other piers. We must provide
1324+not only the duct and the request (the riff), but also the return path,
1325+the other ship to talk to, and the sequence number of the request.
1326+
1327+In `tag` we put arbitrary notes we wish to pass to other vanes. For now,
1328+the only notes we pass here are `%wait` and `%rest` to the timer vane.
1329+
1330+Now that we know what kinds of side effects we may have, we can jump
1331+into the handling of requests.
1332+
1333+```
1334+ ++ ease :: release request
1335+ |= hen=duct
1336+ ^+ +>
1337+ ?~ ref +>
1338+ =+ rov=(~(got by qyx) hen)
1339+ =. qyx (~(del by qyx) hen)
1340+ (mabe rov (cury best hen))
1341+ =. qyx (~(del by qyx) hen)
1342+ |- ^+ +>+.$
1343+ =+ nux=(~(get by fod.u.ref) hen)
1344+ ?~ nux +>+.$
1345+ %= +>+.$
1346+ say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
1347+ fod.u.ref (~(del by fod.u.ref) hen)
1348+ bom.u.ref (~(del by bom.u.ref) u.nux)
1349+ ==
1350+```
1351+
1352+This is called when we're cancelling a subscription. For domestic desks,
1353+`ref` is null, so we're going to cancel any timer we might have created.
1354+We first delete the duct from our map of requests, and then we call
1355+`++mabe` with `++best` to send a `%rest` kiss to the timer vane if we
1356+have started a timer. We'll describe `++best` and `++mabe` momentarily.
1357+
1358+Although we said we're not going to talk about foreign requests yet,
1359+it's easy to see that for foreign desks, we cancel any outstanding
1360+requests for this duct and send a message over ames to the other ship
1361+telling them to cancel the subscription.
1362+
1363+```
1364+ ++ best
1365+ |= [hen=duct tym=@da]
1366+ %_(+> tag :_(tag [hen /tyme %t %rest tym]))
1367+```
1368+
1369+This simply pushes a `%rest` note onto `tag`, from where it will be
1370+passed back to arvo to be handled. This cancels the timer at the given
1371+duct (with the given time).
1372+
1373+```
1374+ ++ mabe :: maybe fire function
1375+ |* [rov=rove fun=$+(@da _+>.^$)]
1376+ ^+ +>.$
1377+ %- fall :_ +>.$
1378+ %- bind :_ fun
1379+ ^- (unit ,@da)
1380+ ?- -.rov
1381+ %&
1382+ ?. ?=(%da -.q.p.rov) ~
1383+ `p.q.p.rov
1384+ %|
1385+ =* mot p.rov
1386+ %+ hunt
1387+ ?. ?=(%da -.p.mot) ~
1388+ ?.((lth now p.p.mot) ~ [~ p.p.mot])
1389+ ?. ?=(%da -.q.mot) ~
1390+ ?.((lth now p.q.mot) [~ now] [~ p.q.mot])
1391+ ==
1392+```
1393+
1394+This decides whether the given request can only be satsified in the
1395+future. In that case, we call the given function with the time in the
1396+future when we expect to have an update to give to this request. This is
1397+called with `++best` to cancel timers and with `++bait` to start them.
1398+
1399+For single requests, we have a time if the request is for a particular
1400+time (which is assumed to be in the future). For ranges of requests, we
1401+check both the start and end cases to see if they are time cases. If so,
1402+we choose the earlier time.
1403+
1404+If any of those give us a time, then we call the given funciton with the
1405+smallest time.
1406+
1407+The more interesting case is, of course, when we're not cancelling a
1408+subscription but starting one.
1409+
1410+```
1411+ ++ eave :: subscribe
1412+ |= [hen=duct rav=rave]
1413+ ^+ +>
1414+ ?- -.rav
1415+ &
1416+ ?: &(=(p.p.rav %u) !=(p.q.p.rav now))
1417+ ~& [%clay-fail p.q.p.rav %now now]
1418+ !!
1419+ =+ ver=(aver p.rav)
1420+ ?~ ver
1421+ (duce hen rav)
1422+ ?~ u.ver
1423+ (blub hen)
1424+ (blab hen p.rav u.u.ver)
1425+```
1426+
1427+There are two types of subscriptions -- either we're requesting a single
1428+file or we're requesting a range of versions of a desk. We'll dicuss the
1429+simpler case first.
1430+
1431+First, we check that we're not requesting the `rang` from any time other
1432+than the present. Since we don't store that information for any other
1433+time, we can't produce it in a referentially transparent manner for any
1434+time other than the present.
1435+
1436+Then, we try to read the requested `mood` `p.rav`. If we can't access
1437+the request data right now, we call `++duce` to put the request in our
1438+queue to be satisfied when the information becomes available.
1439+
1440+This case occurs when we make a request for a case whose (1) date is
1441+after the current date, (2) number is after the current number, or (3)
1442+label is not yet used.
1443+
1444+```
1445+ ++ duce :: produce request
1446+ |= [hen=duct rov=rove]
1447+ ^+ +>
1448+ =. qyx (~(put by qyx) hen rov)
1449+ ?~ ref
1450+ (mabe rov (cury bait hen))
1451+ |- ^+ +>+.$ :: XX why?
1452+ =+ rav=(reve rov)
1453+ =+ ^= vaw ^- rave
1454+ ?. ?=([%& %v *] rav) rav
1455+ [%| [%ud let.dom] `case`q.p.rav r.p.rav]
1456+ =+ inx=nix.u.ref
1457+ %= +>+.$
1458+ say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
1459+ nix.u.ref +(nix.u.ref)
1460+ bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
1461+ fod.u.ref (~(put by fod.u.ref) hen inx)
1462+ ==
1463+```
1464+
1465+The code for `++duce` is nearly the exact inverse of `++ease`, which in
1466+the case of a domestic desk is very simple -- we simply put the duct and
1467+rave into `qyx` and possibly start a timer with `++mabe` and `++bait`.
1468+Recall that `ref` is null for domestic desks and that `++mabe` fires the
1469+given function with the time we need to be woken up at, if we need to be
1470+woken up at a particular time.
1471+
1472+```
1473+ ++ bait
1474+ |= [hen=duct tym=@da]
1475+ %_(+> tag :_(tag [hen /tyme %t %wait tym]))
1476+```
1477+
1478+This sets an alarm by sending a `%wait` card with the given time to the
1479+timer vane.
1480+
1481+Back in `++eave`, if `++aver` returned `[~ ~]`, then we cancel the
1482+subscription. This occurs when we make (1) a `%x` request for a file
1483+that does not exist, (2) a `%w` request with a case that is not a
1484+number, or (3) a `%w` request with a nonempty path. The `++blub` is
1485+exactly what you would expect it to be.
1486+
1487+```
1488+ ++ blub :: ship stop
1489+ |= hen=duct
1490+ %_(+> byn [[hen ~] byn])
1491+```
1492+
1493+We notify the duct that we're cancelling their subscription since it
1494+isn't satisfiable.
1495+
1496+Otherwise, we have received the desired information, so we send it on to
1497+the subscriber with `++blab`.
1498+
1499+```
1500+ ++ blab :: ship result
1501+ |= [hen=duct mun=mood dat=*]
1502+ ^+ +>
1503+ +>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn])
1504+```
1505+
1506+The most interesting arm called in `++eave` is, of course, `++aver`,
1507+where we actually try to read the data.
1508+
1509+```
1510+ ++ aver :: read
1511+ |= mun=mood
1512+ ^- (unit (unit ,*))
1513+ ?: &(=(p.mun %u) !=(p.q.mun now)) :: prevent bad things
1514+ ~& [%clay-fail p.q.mun %now now]
1515+ !!
1516+ =+ ezy=?~(ref ~ (~(get by haw.u.ref) mun))
1517+ ?^ ezy ezy
1518+ =+ nao=(~(case-to-aeon ze lim dom ran) q.mun)
1519+ ?~(nao ~ [~ (~(read-at-aeon ze lim dom ran) u.nao mun)])
1520+```
1521+
1522+We check immediately that we're not requesting the `rang` for any time
1523+other than the present.
1524+
1525+If this is a foreign desk, then we check our cache for the specific
1526+request. If either this is a domestic desk or we don't have the request
1527+in our cache, then we have to actually go read the data from our dome.
1528+
1529+We need to do two things. First, we try to find the number of the commit
1530+specified by the given case, and then we try to get the data there.
1531+
1532+Here, we jump into `arvo/zuse.hoon`, which is where much of the
1533+algorithmic code is stored, as opposed to the clay interface, which is
1534+stored in `arvo/clay.hoon`. We examine `++case-to-aeon:ze`.
1535+
1536+```
1537+ ++ case-to-aeon :: case-to-aeon:ze
1538+ |= lok=case :: act count through
1539+ ^- (unit aeon)
1540+ ?- -.lok
1541+ %da
1542+ ?: (gth p.lok lim) ~
1543+ |- ^- (unit aeon)
1544+ ?: =(0 let) [~ 0] :: avoid underflow
1545+ ?: %+ gte p.lok
1546+ =< t
1547+ %- tako-to-yaki
1548+ %- aeon-to-tako
1549+ let
1550+ [~ let]
1551+ $(let (dec let))
1552+ ::
1553+ %tas (~(get by lab) p.lok)
1554+ %ud ?:((gth p.lok let) ~ [~ p.lok])
1555+ ==
1556+```
1557+
1558+We handle each type of `case` differently. The latter two types are
1559+easy.
1560+
1561+If we're requesting a revision by label, then we simply look up the
1562+requested label in `lab` from the given dome. If it exists, that is our
1563+aeon; else we produce null, indicating the requested revision does not
1564+yet exist.
1565+
1566+If we're requesting a revision by number, we check if we've yet reached
1567+that number. If so, we produce the number; else we produce null.
1568+
1569+If we're requesting a revision by date, we check first if the date is in
1570+the future, returning null if so. Else we start from the most recent
1571+revision and scan backwards until we find the first revision committed
1572+before that date, and we produce that. If we requested a date before any
1573+revisions were committed, we produce `0`.
1574+
1575+The definitions of `++aeon-to-tako` and `++tako-to-yaki` are trivial.
1576+
1577+```
1578+ ++ aeon-to-tako ~(got by hit)
1579+
1580+ ++ tako-to-yaki ~(got by hut) :: grab yaki
1581+```
1582+
1583+We simply look up the aeon or tako in their respective maps (`hit` and
1584+`hut`).
1585+
1586+Assuming we got a valid version number, `++aver` calls
1587+`++read-at-aeon:ze`, which reads the requested data at the given
1588+revision.
1589+
1590+```
1591+ ++ read-at-aeon :: read-at-aeon:ze
1592+ |= [oan=aeon mun=mood] :: seek and read
1593+ ^- (unit)
1594+ ?: &(?=(%w p.mun) !?=(%ud -.q.mun)) :: NB only for speed
1595+ ?^(r.mun ~ [~ oan])
1596+ (read:(rewind oan) mun)
1597+```
1598+
1599+If we're requesting the revision number with a case other than by
1600+number, then we go ahead and just produce the number we were given.
1601+Otherwise, we call `++rewind` to rewind our state to the given revision,
1602+and then we call `++read` to get the requested information.
1603+
1604+```
1605+ ++ rewind :: rewind:ze
1606+ |= oan=aeon :: rewind to aeon
1607+ ^+ +>
1608+ ?: =(let oan) +>
1609+ ?: (gth oan let) !! :: don't have version
1610+ +>(ank (checkout-ankh q:(tako-to-yaki (aeon-to-tako oan))), let oan)
1611+```
1612+
1613+If we're already at the requested version, we do nothing. If we're
1614+requesting a version later than our head, we are unable to comply.
1615+
1616+Otherwise, we get the hash of the commit at the number, and from that we
1617+get the commit itself (the yaki), which has the map of path to lobe that
1618+represents a version of the filesystem. We call `++checkout-ankh` to
1619+checkout the commit, and we replace `ank` in our context with the
1620+result.
1621+
1622+```
1623+ ++ checkout-ankh :: checkout-ankh:ze
1624+ |= hat=(map path lobe) :: checkout commit
1625+ ^- ankh
1626+ %- cosh
1627+ %+ roll (~(tap by hat) ~)
1628+ |= [[pat=path bar=lobe] ank=ankh]
1629+ ^- ankh
1630+ %- cosh
1631+ ?~ pat
1632+ =+ zar=(lobe-to-noun bar)
1633+ ank(q [~ (sham zar) zar])
1634+ =+ nak=(~(get by r.ank) i.pat)
1635+ %= ank
1636+ r %+ ~(put by r.ank) i.pat
1637+ $(pat t.pat, ank (fall nak _ankh))
1638+ ==
1639+```
1640+
1641+Twice we call `++cosh`, which hashes a commit, updating `p` in an
1642+`ankh`. Let's jump into that algorithm before we describe
1643+`++checkout-ankh`.
1644+
1645+```
1646+ ++ cosh :: locally rehash
1647+ |= ank=ankh :: NB v/unix.c
1648+ ank(p rehash:(zu ank))
1649+```
1650+
1651+We simply replace `p` in the hash with the `cash` we get from a call to
1652+`++rehash:zu`.
1653+
1654+```
1655+ ++ zu !: :: filesystem
1656+ |= ank=ankh :: filesystem state
1657+ =| myz=(list ,[p=path q=miso]) :: changes in reverse
1658+ =| ram=path :: reverse path into
1659+ |%
1660+ ++ rehash :: local rehash
1661+ ^- cash
1662+ %+ mix ?~(q.ank 0 p.u.q.ank)
1663+ =+ axe=1
1664+ |- ^- cash
1665+ ?~ r.ank _@
1666+ ;: mix
1667+ (shaf %dash (mix axe (shaf %dush (mix p.n.r.ank p.q.n.r.ank))))
1668+ $(r.ank l.r.ank, axe (peg axe 2))
1669+ $(r.ank r.r.ank, axe (peg axe 3))
1670+ ==
1671+```
1672+
1673+`++zu` is a core we set up with a particular filesystem node to traverse
1674+a checkout of the filesystem and access the actual data inside it. One
1675+of the things we can do with it is to create a recursive hash of the
1676+node.
1677+
1678+In `++rehash`, if this node is a file, then we xor the remainder of the
1679+hash with the hash of the contents of the file. The remainder of the
1680+hash is `0` if we have no children, else we descend into our children.
1681+Basically, we do a half SHA-256 of the xor of the axis of this child and
1682+the half SHA-256 of the xor of the name of the child and the hash of the
1683+child. This is done for each child and all the results are xored
1684+together.
1685+
1686+Now we return to our discussion of `++checkout-ankh`.
1687+
1688+We fold over every path in this version of the filesystem and create a
1689+great ankh out of them. First, we call `++lobe-to-noun` to get the raw
1690+data referred to be each lobe.
1691+
1692+```
1693+ ++ lobe-to-noun :: grab blob
1694+ |= p=lobe :: ^- *
1695+ %- blob-to-noun
1696+ (lobe-to-blob p)
1697+```
1698+
1699+This converts a lobe into the raw data it refers to by first getting the
1700+blob with `++lobe-to-blob` and converting that into data with
1701+`++blob-to-noun`.
1702+
1703+```
1704+ ++ lobe-to-blob ~(got by lat) :: grab blob
1705+```
1706+
1707+This just grabs the blob that the lobe refers to.
1708+
1709+```
1710+ ++ blob-to-noun :: grab blob
1711+ |= p=blob
1712+ ?- -.p
1713+ %delta (lump r.p (lobe-to-noun q.p))
1714+ %direct q.p
1715+ %indirect q.p
1716+ ==
1717+```
1718+
1719+If we have either a direct or an indirect blob, then the data is stored
1720+right in the blob. Otherwise, we have to reconstruct it from the diffs.
1721+We do this by calling `++lump` on the diff in the blob with the data
1722+obtained by recursively calling the parent of this blob.
1723+
1724+```
1725+ ++ lump :: apply patch
1726+ |= [don=udon src=*]
1727+ ^- *
1728+ ?+ p.don ~|(%unsupported !!)
1729+ %a
1730+ ?+ -.q.don ~|(%unsupported !!)
1731+ %a q.q.don
1732+ %c (lurk ((hard (list)) src) p.q.don)
1733+ %d (lure src p.q.don)
1734+ ==
1735+ ::
1736+ %c
1737+ =+ dst=(lore ((hard ,@) src))
1738+ %- roly
1739+ ?+ -.q.don ~|(%unsupported !!)
1740+ %a ((hard (list ,@t)) q.q.don)
1741+ %c (lurk dst p.q.don)
1742+ ==
1743+ ==
1744+```
1745+
1746+This is defined in `arvo/hoon.hoon` for historical reasons which are
1747+likely no longer applicable. Since the `++umph` structure will likely
1748+change we convert clay to be a typed filesystem, we'll only give a
1749+high-level description of this process. If we have a `%a` udon, then
1750+we're performing a trivial replace, so we produce simply `q.q.don`. If
1751+we have a `%c` udon, then we're performing a list merge (as in, for
1752+example, lines of text). The merge is performed by `++lurk`.
1753+
1754+```
1755+ ++ lurk :: apply list patch
1756+ |* [hel=(list) rug=(urge)]
1757+ ^+ hel
1758+ =+ war=`_hel`~
1759+ |- ^+ hel
1760+ ?~ rug (flop war)
1761+ ?- -.i.rug
1762+ &
1763+ %= $
1764+ rug t.rug
1765+ hel (slag p.i.rug hel)
1766+ war (weld (flop (scag p.i.rug hel)) war)
1767+ ==
1768+ ::
1769+ |
1770+ %= $
1771+ rug t.rug
1772+ hel =+ gur=(flop p.i.rug)
1773+ |- ^+ hel
1774+ ?~ gur hel
1775+ ?>(&(?=(^ hel) =(i.gur i.hel)) $(hel t.hel, gur t.gur))
1776+ war (weld q.i.rug war)
1777+ ==
1778+ ==
1779+```
1780+
1781+We accumulate our final result in `war`. If there's nothing more in our
1782+list of merge instructions (unces), we just reverse `war` and produce
1783+it. Otherwise, we process another unce. If the unce is of type `&`, then
1784+we have `p.i.rug` lines of no changes, so we just copy them over from
1785+`hel` to `war`. If the unice is of type `|`, then we verify that the
1786+source lines (in `hel`) are what we expect them to be (`p.i.rug`),
1787+crashing on failure. If they're good, then we append the new lines in
1788+`q.i.rug` onto `war`.
1789+
1790+And that's really it. List merges are pretty easy. Anyway, if you
1791+recall, we were discussing `++checkout-ankh`.
1792+
1793+```
1794+ ++ checkout-ankh :: checkout-ankh:ze
1795+ |= hat=(map path lobe) :: checkout commit
1796+ ^- ankh
1797+ %- cosh
1798+ %+ roll (~(tap by hat) ~)
1799+ |= [[pat=path bar=lobe] ank=ankh]
1800+ ^- ankh
1801+ %- cosh
1802+ ?~ pat
1803+ =+ zar=(lobe-to-noun bar)
1804+ ank(q [~ (sham zar) zar])
1805+ =+ nak=(~(get by r.ank) i.pat)
1806+ %= ank
1807+ r %+ ~(put by r.ank) i.pat
1808+ $(pat t.pat, ank (fall nak _ankh))
1809+ ==
1810+```
1811+
1812+If the path is null, then we calculate `zar`, the raw data at the path
1813+`pat` in this version. We produce the given ankh with the correct data.
1814+
1815+Otherwise, we try to get the child we're looking at from our parent
1816+ankh. If it's already been created, this succeeds; otherwise, we simply
1817+create a default blank ankh. We place ourselves in our parent after
1818+recursively computing our children.
1819+
1820+This algorithm really isn't that complicated, but it may not be
1821+immediately obvious why it works. An example should clear everything up.
1822+
1823+Suppose `hat` is a map of the following information.
1824+
1825+```
1826+ /greeting --> "customary upon meeting"
1827+ /greeting/english --> "hello"
1828+ /greeting/spanish --> "hola"
1829+ /greeting/russian/short --> "привет"
1830+ /greeting/russian/long --> "Здравствуйте"
1831+ /farewell/russian --> "до свидания"
1832+```
1833+
1834+Furthermore, let's say that we process them in this order:
1835+
1836+```
1837+ /greeting/english
1838+ /greeting/russian/short
1839+ /greeting/russian/long
1840+ /greeting
1841+ /greeting/spanish
1842+ /farewell/russian
1843+```
1844+
1845+Then, the first path we process is `/greeting/english` . Since our path
1846+is not null, we try to get `nak`, but because our ankh is blank at this
1847+point it doesn't find anything. Thus, update our blank top-level ankh
1848+with a child `%greeting`. and recurse with the blank `nak` to create the
1849+ankh of the new child.
1850+
1851+In the recursion, we our path is `/english` and our ankh is again blank.
1852+We try to get the `english` child of our ankh, but this of course fails.
1853+Thus, we update our blank `/greeting` ankh with a child `english`
1854+produced by recursing.
1855+
1856+Now our path is null, so we call `++lobe-to-noun` to get the actual
1857+data, and we place it in the brand-new ankh.
1858+
1859+Next, we process `/greeting/russian/short`. Since our path is not null,
1860+we try to get the child named `%greeting`, which does exist since we
1861+created it earlier. We put modify this child by recursing on it. Our
1862+path is now `/russian/short`, so we look for a `%russian` child in our
1863+`/greeting` ankh. This doesn't exist, so we add it by recursing. Our
1864+path is now `/short`, so we look for a `%short` child in our
1865+`/greeting/russian` ankh. This doesn't exist, so we add it by recursing.
1866+Now our path is null, so we set the contents of this node to `"привет"`,
1867+and we're done processing this path.
1868+
1869+Next, we process `/greeting/russian/long`. This proceeds similarly to
1870+the previous except that now the ankh for `/greeting/russian` already
1871+exists, so we simply reuse it rather than creating a new one. Of course,
1872+we still must create a new `/greeting/russian/long` ankh.
1873+
1874+Next, we process `/greeting`. This ankh already exists, so after we've
1875+recursed once, our path is null, and our ankh is not blank -- it already
1876+has two children (and two grandchildren). We don't touch those, though,
1877+since a node may be both a file and a directory. We just add the
1878+contents of the file -- "customary upon meeting" -- to the existing
1879+ankh.
1880+
1881+Next, we process `/greeting/spanish`. Of course, the `/greeting` ankh
1882+already exists, but it doesn't have a `%spanish` child, so we create
1883+that, taking care not to disturb the contents of the `/greeting` file.
1884+We put "hola" into the ankh and call it good.
1885+
1886+Finally, we process `/farewell/russian`. Here, the `/farewell` ankh
1887+doesn't exist, so we create it. Clearly the newly-created ankh doesn't
1888+have any children, so we have to add a `%russian` child, and in this
1889+child we put our last content -- "до свидания".
1890+
1891+We hope it's fairly obvious that the order we process the paths doesn't
1892+affect the final ankh tree. The tree will be constructed in a very
1893+different order depending on what order the paths come in, but the
1894+resulting tree is independent of order.
1895+
1896+At any rate, we were talking about something important, weren't we? If
1897+you recall, that concludes our discussion of `++rewind`, which was
1898+called from `++read-at-aeon`. In summary, `++rewind` returns a context
1899+in which our current state is (very nearly) as it was when the specified
1900+version of the desk was the head. This allows `++read-at-aeon` to call
1901+`++read` to read the requested information.
1902+
1903+```
1904+ ++ read :: read:ze
1905+ |= mun=mood :: read at point
1906+ ^- (unit)
1907+ ?: ?=(%v p.mun)
1908+ [~ `dome`+<+<.read]
1909+ ?: &(?=(%w p.mun) !?=(%ud -.q.mun))
1910+ ?^(r.mun ~ [~ let])
1911+ ?: ?=(%w p.mun)
1912+ =+ ^= yak
1913+ %- tako-to-yaki
1914+ %- aeon-to-tako
1915+ let
1916+ ?^(r.mun ~ [~ [t.yak (forge-nori yak)]])
1917+ ::?> ?=(^ hit) ?^(r.mun ~ [~ i.hit]) :: what do?? need [@da nori]
1918+ (query(ank ank:(descend-path:(zu ank) r.mun)) p.mun)
1919+```
1920+
1921+If we're requesting the dome, then we just return that immediately.
1922+
1923+If we're requesting the revision number of the desk and we're not
1924+requesting it by number, then we just return the current number of this
1925+desk. Note of course that this was really already handled in
1926+`++read-at-aeon`.
1927+
1928+If we're requesting a `%w` with a specific revision number, then we do
1929+something or other with the commit there. It's kind of weird, and it
1930+doesn't seem to work, so we'll ignore this case.
1931+
1932+Otherwise, we descend into the ankh tree to the given path with
1933+`++descend-path:zu`, and then we handle specific request in `++query`.
1934+
1935+```
1936+ ++ descend-path :: descend recursively
1937+ |= way=path
1938+ ^+ +>
1939+ ?~(way +> $(way t.way, +> (descend i.way)))
1940+```
1941+
1942+This is simple recursion down into the ankh tree. `++descend` descends
1943+one level, so this will eventually get us down to the path we want.
1944+
1945+```
1946+ ++ descend :: descend
1947+ |= lol=@ta
1948+ ^+ +>
1949+ =+ you=(~(get by r.ank) lol)
1950+ +>.$(ram [lol ram], ank ?~(you [*cash ~ ~] u.you))
1951+```
1952+
1953+`ram` is the path that we're at, so to descend one level we push the
1954+name of this level onto that path. We update the ankh with the correct
1955+one at that path if it exists; else we create a blank one.
1956+
1957+Once we've decscended to the correct level, we need to actually deal
1958+with the request.
1959+
1960+```
1961+ ++ query :: query:ze
1962+ |= ren=?(%u %v %x %y %z) :: endpoint query
1963+ ^- (unit ,*)
1964+ ?- ren
1965+ %u [~ `rang`+<+>.query]
1966+ %v [~ `dome`+<+<.query]
1967+ %x ?~(q.ank ~ [~ q.u.q.ank])
1968+ %y [~ as-arch]
1969+ %z [~ ank]
1970+ ==
1971+```
1972+
1973+Now that everything's set up, it's really easy. If they're requesting
1974+the rang, dome, or ankh, we give it to them. If the contents of a file,
1975+we give it to them if it is in fact a file. If the `arch`, then we
1976+calculate it with `++as-arch`.
1977+
1978+```
1979+ ++ as-arch :: as-arch:ze
1980+ ^- arch :: arch report
1981+ :+ p.ank
1982+ ?~(q.ank ~ [~ p.u.q.ank])
1983+ |- ^- (map ,@ta ,~)
1984+ ?~ r.ank ~
1985+ [[p.n.r.ank ~] $(r.ank l.r.ank) $(r.ank r.r.ank)]
1986+```
1987+
1988+This very simply strips out all the "real" data and returns just our own
1989+hash, the hash of the file contents (if we're a file), and a map of the
1990+names of our immediate children.
1991+
1992+## Lifecycle of a Local Subscription
1993+
1994+A subscription to a range of revisions of a desk initially follows the
1995+same path that a single read does. In `++aver`, we checked the head of
1996+the given rave. If the head was `&`, then it was a single request, so we
1997+handled it above. If `|`, then we handle it with the following code.
1998+
1999+```
2000+ =+ nab=(~(case-to-aeon ze lim dom ran) p.p.rav)
2001+ ?~ nab
2002+ ?> =(~ (~(case-to-aeon ze lim dom ran) q.p.rav))
2003+ (duce hen (rive rav))
2004+ =+ huy=(~(case-to-aeon ze lim dom ran) q.p.rav)
2005+ ?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab))))
2006+ (blub hen)
2007+ =+ top=?~(huy let.dom u.huy)
2008+ =+ sar=(~(lobes-at-path ze lim dom ran) u.nab r.p.rav)
2009+ =+ ear=(~(lobes-at-path ze lim dom ran) top r.p.rav)
2010+ =. +>.$
2011+ ?: =(sar ear) +>.$
2012+ =+ fud=(~(make-nako ze lim dom ran) u.nab top)
2013+ (bleb hen u.nab fud)
2014+ ?^ huy
2015+ (blub hen)
2016+ =+ ^= ptr ^- case
2017+ [%ud +(let.dom)]
2018+ (duce hen `rove`[%| ptr q.p.rav r.p.rav ear])
2019+ ==
2020+```
2021+
2022+Recall that `++case-to-aeon:ze` produces the revision number that a case
2023+corresponds to, if it corresponds to any. If it doesn't yet correspond
2024+to a revision, then it produces null.
2025+
2026+Thus, we first check to see if we've even gotten to the beginning of the
2027+range of revisions requested. If not, then we assert that we haven't yet
2028+gotten to the end of the range either, because that would be really
2029+strange. If not, then we immediately call `++duce`, which, if you
2030+recall, for a local request, simply puts this duct and rove into our
2031+cult `qyx`, so that we know who to respond to when the revision does
2032+appear.
2033+
2034+If we've already gotten to the first revision, then we can produce some
2035+content immediately. If we've also gotten to the final revision, and
2036+that revision is earlier than the start revision, then it's a bad
2037+request and we call `++blub`, which tells the subscriber that his
2038+subscription will not be satisfied.
2039+
2040+Otherwise, we find the data at the given path at the beginning of the
2041+subscription and at the last available revision in the subscription. If
2042+they're the same, then we don't send a notification. Otherwise, we call
2043+`++gack`, which creates the `++nako` we need to produce. We call
2044+`++bleb` to actually produce the information.
2045+
2046+If we already have the last requested revision, then we also tell the
2047+subscriber with `++blub` that the subscription will receive no further
2048+updates.
2049+
2050+If there will be more revisions in the subscription, then we call
2051+`++duce`, adding the duct to our subscribers. We modify the rove to
2052+start at the next revision since we've already handled all the revisions
2053+up to the present.
2054+
2055+We glossed over the calls to `++lobes-at-path`, `++make-nako`, and
2056+`++bleb`, so we'll get back to those right now. `++bleb` is simple, so
2057+we'll start with that.
2058+
2059+```
2060+ ++ bleb :: ship sequence
2061+ |= [hen=duct ins=@ud hip=nako]
2062+ ^+ +>
2063+ (blab hen [%w [%ud ins] ~] hip)
2064+```
2065+
2066+We're given a duct, the beginning revision number, and the nako that
2067+contains the updates since that revision. We use `++blab` to produce
2068+this result to the subscriber. The case is `%w` with a revision number
2069+of the beginning of the subscription, and the data is the nako itself.
2070+
2071+We call `++lobes-at-path:ze` to get the data at the particular path.
2072+
2073+```
2074+ ++ lobes-at-path :: lobes-at-path:ze
2075+ |= [oan=aeon pax=path] :: data at path
2076+ ^- (map path lobe)
2077+ ?: =(0 oan) ~
2078+ %- mo
2079+ %+ skim
2080+ %. ~
2081+ %~ tap by
2082+ =< q
2083+ %- tako-to-yaki
2084+ %- aeon-to-tako
2085+ oan
2086+ |= [p=path q=lobe]
2087+ ?| ?=(~ pax)
2088+ ?& !?=(~ p)
2089+ =(-.pax -.p)
2090+ $(p +.p, pax +.pax)
2091+ == ==
2092+```
2093+
2094+At revision zero, the theoretical common revision between all
2095+repositories, there is no data, so we produce null.
2096+
2097+We get the list of paths (paired with their lobe) in the revision
2098+referred to by the given number and we keep only those paths which begin
2099+with `pax`. Converting to a map, we now have a map from the subpaths at
2100+the given path to the hash of their data. This is simple and efficient
2101+to calculate and compare to later revisions. This allows us to easily
2102+tell if a node or its children have changed.
2103+
2104+Finally, we will describe `++make-nako:ze`.
2105+
2106+```
2107+ ++ make-nako :: gack a through b
2108+ |= [a=aeon b=aeon]
2109+ ^- [(map aeon tako) aeon (set yaki) (set blob)]
2110+ :_ :- b
2111+ =- [(takos-to-yakis -<) (lobes-to-blobs ->)]
2112+ %+ reachable-between-takos
2113+ (~(get by hit) a) :: if a not found, a=0
2114+ (aeon-to-tako b)
2115+ ^- (map aeon tako)
2116+ %- mo %+ skim (~(tap by hit) ~)
2117+ |= [p=aeon *]
2118+ &((gth p a) (lte p b))
2119+```
2120+
2121+We need to produce four things -- the numbers of the new commits, the
2122+number of the latest commit, the new commits themselves, and the new
2123+data itself.
2124+
2125+The first is fairly easy to produce. We simply go over our map of
2126+numbered commits and produce all those numbered greater than `a` and not
2127+greater than `b`.
2128+
2129+The second is even easier to produce -- `b` is clearly our most recent
2130+commit.
2131+
2132+The third and fourth are slightly more interesting, though not too
2133+terribly difficult. First, we call `++reachable-between-takos`.
2134+
2135+```
2136+ ++ reachable-between-takos
2137+ |= [a=(unit tako) b=tako] :: pack a through b
2138+ ^- [(set tako) (set lobe)]
2139+ =+ ^= sar
2140+ ?~ a ~
2141+ (reachable-takos r:(tako-to-yaki u.a))
2142+ =+ yak=`yaki`(tako-to-yaki b)
2143+ %+ new-lobes-takos (new-lobes ~ sar) :: get lobes
2144+ |- ^- (set tako) :: walk onto sar
2145+ ?: (~(has in sar) r.yak)
2146+ ~
2147+ =+ ber=`(set tako)`(~(put in `(set tako)`~) `tako`r.yak)
2148+ %- ~(uni in ber)
2149+ ^- (set tako)
2150+ %+ roll p.yak
2151+ |= [yek=tako bar=(set tako)]
2152+ ^- (set tako)
2153+ ?: (~(has in bar) yek) :: save some time
2154+ bar
2155+ %- ~(uni in bar)
2156+ ^$(yak (tako-to-yaki yek))
2157+```
2158+
2159+We take a possible starting commit and a definite ending commit, and we
2160+produce the set of commits and the set of data between them.
2161+
2162+We let `sar` be the set of commits reachable from `a`. If `a` is null,
2163+then obviously no commits are reachable. Otherwise, we call
2164+`++reachable-takos` to calculate this.
2165+
2166+```
2167+ ++ reachable-takos :: reachable
2168+ |= p=tako :: XX slow
2169+ ^- (set tako)
2170+ =+ y=(tako-to-yaki p)
2171+ =+ t=(~(put in _(set tako)) p)
2172+ %+ roll p.y
2173+ |= [q=tako s=_t]
2174+ ?: (~(has in s) q) :: already done
2175+ s :: hence skip
2176+ (~(uni in s) ^$(p q)) :: otherwise traverse
2177+```
2178+
2179+We very simply produce the set of the given tako plus its parents,
2180+recursively.
2181+
2182+Back in `++reachable-between-takos`, we let `yak` be the yaki of `b`,
2183+the ending commit. With this, we create a set that is the union of `sar`
2184+and all takos reachable from `b`.
2185+
2186+We pass `sar` into `++new-lobes` to get all the lobes referenced by any
2187+tako referenced by `a`. The result is passed into `++new-lobes-takos` to
2188+do the same, but not recomputing those in already calculated last
2189+sentence. This produces the sets of takos and lobes we need.
2190+
2191+```
2192+ ++ new-lobes :: object hash set
2193+ |= [b=(set lobe) a=(set tako)] :: that aren't in b
2194+ ^- (set lobe)
2195+ %+ roll (~(tap in a) ~)
2196+ |= [tak=tako bar=(set lobe)]
2197+ ^- (set lobe)
2198+ =+ yak=(tako-to-yaki tak)
2199+ %+ roll (~(tap by q.yak) ~)
2200+ |= [[path lob=lobe] far=_bar]
2201+ ^- (set lobe)
2202+ ?~ (~(has in b) lob) :: don't need
2203+ far
2204+ =+ gar=(lobe-to-blob lob)
2205+ ?- -.gar
2206+ %direct (~(put in far) lob)
2207+ %delta (~(put in $(lob q.gar)) lob)
2208+ %indirect (~(put in $(lob s.gar)) lob)
2209+ ==
2210+```
2211+
2212+Here, we're creating a set of lobes referenced in a commit in `a`. We
2213+start out with `b` as the initial set of lobes, so we don't need to
2214+recompute any of the lobes referenced in there.
2215+
2216+The algorithm is pretty simple, so we won't bore you with the details.
2217+We simply traverse every commit in `a`, looking at every blob referenced
2218+there, and, if it's not already in `b`, we add it to `b`. In the case of
2219+a direct blob, we're done. For a delta or an indirect blob, we
2220+recursively add every blob referenced within the blob.
2221+
2222+```
2223+ ++ new-lobes-takos :: garg & repack
2224+ |= [b=(set lobe) a=(set tako)]
2225+ ^- [(set tako) (set lobe)]
2226+ [a (new-lobes b a)]
2227+```
2228+
2229+Here, we just update the set of lobes we're given with the commits we're
2230+given and produce both sets.
2231+
2232+This concludes our discussion of a local subscription.
2233+
2234+## Lifecycle of a Foreign Read or Subscription
2235+
2236+Foreign reads and subscriptions are handled in much the same way as
2237+local ones. The interface is the same -- a vane or app sends a `%warp`
2238+kiss with the request. The difference is simply that the `sock` refers
2239+to the foreign ship.
2240+
2241+Thus, we start in the same place -- in `++call`, handling `%warp`.
2242+However, since the two side of the `sock` are different, we follow a
2243+different path.
2244+
2245+```
2246+ =+ wex=(do now p.q.hic p.q.q.hic ruf)
2247+ =+ ^= woo
2248+ ?~ q.q.q.hic
2249+ abet:(ease:wex hen)
2250+ abet:(eave:wex hen u.q.q.q.hic)
2251+ [-.woo (posh q.p.q.hic p.q.q.hic +.woo ruf)]
2252+```
2253+
2254+If we compare this to how the local case was handled, we see that it's
2255+not all that different. We use `++do` rather than `++un` and `++de` to
2256+set up the core for the foreign ship. This gives us a `++de` core, so we
2257+either cancel or begin the request by calling `++ease` or `++eave`,
2258+exactly as in the local case. In either case, we call `++abet:de` to
2259+resolve our various types of output into actual moves, as described in
2260+the local case. Finally, we call `++posh` to update our raft, putting
2261+the modified rung into the raft.
2262+
2263+We'll first trace through `++do`.
2264+
2265+```
2266+ ++ do
2267+ |= [now=@da [who=ship him=ship] syd=@tas ruf=raft]
2268+ =+ ^= rug ^- rung
2269+ =+ rug=(~(get by hoy.ruf) him)
2270+ ?^(rug u.rug *rung)
2271+ =+ ^= red ^- rede
2272+ =+ yit=(~(get by rus.rug) syd)
2273+ ?^(yit u.yit `rede`[~2000.1.1 ~ [~ *rind] *dome])
2274+ ((de now ~ ~) [who him] syd red ran.ruf)
2275+```
2276+
2277+If we already have a rung for this foreign ship, then we use that.
2278+Otherwise, we create a new blank one. If we already have a rede in this
2279+rung, then we use that, otherwise we create a blank one. An important
2280+point to note here is that we let `ref` in the rede be `[~ *rind]`.
2281+Recall, for domestic desks `ref` is null. We use this to distinguish
2282+between foreign and domestic desks in `++de`.
2283+
2284+With this information, we create a `++de` core as usual.
2285+
2286+Although we've already covered `++ease` and `++eave`, we'll go through
2287+them quickly again, highlighting the case of foreign request.
2288+
2289+```
2290+ ++ ease :: release request
2291+ |= hen=duct
2292+ ^+ +>
2293+ ?~ ref +>
2294+ =+ rov=(~(got by qyx) hen)
2295+ =. qyx (~(del by qyx) hen)
2296+ (mabe rov (cury best hen))
2297+ =. qyx (~(del by qyx) hen)
2298+ |- ^+ +>+.$
2299+ =+ nux=(~(get by fod.u.ref) hen)
2300+ ?~ nux +>+.$
2301+ %= +>+.$
2302+ say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
2303+ fod.u.ref (~(del by fod.u.ref) hen)
2304+ bom.u.ref (~(del by bom.u.ref) u.nux)
2305+ ==
2306+```
2307+
2308+Here, we still remove the duct from our cult (we maintain a cult even
2309+for foreign desks), but we also need to tell the foreign desk to cancel
2310+our subscription. We do this by sending a request (by appending to
2311+`say`, which gets resolved in `++abet:de` to a `%want` kiss to ames) to
2312+the foreign ship to cancel the subscription. Since we don't anymore
2313+expect a response on this duct, we remove it from `fod` and `bom`, which
2314+are the maps between ducts, raves, and request sequence numbers.
2315+Basically, we remove every trace of the subscription from our request
2316+manager.
2317+
2318+In the case of `++eave`, where we're creating a new request, everything
2319+is exactly identical to the case of the local request except `++duce`.
2320+We said that `++duce` simply puts the request into our cult. This is
2321+true for a domestic request, but distinctly untrue for foreign requests.
2322+
2323+```
2324+ ++ duce :: produce request
2325+ |= [hen=duct rov=rove]
2326+ ^+ +>
2327+ =. qyx (~(put by qyx) hen rov)
2328+ ?~ ref +>.$
2329+ |- ^+ +>+.$ :: XX why?
2330+ =+ rav=(reve rov)
2331+ =+ ^= vaw ^- rave
2332+ ?. ?=([%& %v *] rav) rav
2333+ [%| [%ud let.dom] `case`q.p.rav r.p.rav]
2334+ =+ inx=nix.u.ref
2335+ %= +>+.$
2336+ say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
2337+ nix.u.ref +(nix.u.ref)
2338+ bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
2339+ fod.u.ref (~(put by fod.u.ref) hen inx)
2340+ ==
2341+```
2342+
2343+If we have a request manager (i.e. this is a foreign desk), then we do
2344+the approximate inverse of `++ease`. We create a rave out of the given
2345+request and send it off to the foreign desk by putting it in `say`. Note
2346+that the rave is created to request the information starting at the next
2347+revision number. Since this is a new request, we put it into `fod` and
2348+`bom` to associate the request with its duct and its sequence number.
2349+Since we're using another sequence number, we must increment `nix`,
2350+which represents the next available sequence number.
2351+
2352+And that's really it for this side of the request. Requesting foreign
2353+information isn't that hard. Let's see what it looks like on the other
2354+side. When we get a request from another ship for information on our
2355+ship, that comes to us in the form of a `%wart` from ames.
2356+
2357+We handle a `%wart` in `++call`, right next to where we handle the
2358+`%warp` case.
2359+
2360+```
2361+ %wart
2362+ ?> ?=(%re q.q.hic)
2363+ =+ ryf=((hard riff) s.q.hic)
2364+ :_ ..^$
2365+ :~ :- hen
2366+ :^ %pass [(scot %p p.p.q.hic) (scot %p q.p.q.hic) r.q.hic]
2367+ %c
2368+ [%warp [p.p.q.hic p.p.q.hic] ryf]
2369+ ==
2370+```
2371+
2372+Every request we receive should be of type `riff`, so we coerce it into
2373+that type. We just convert this into a new `%warp` kiss that we pass to
2374+ourself. This gets handled like normal, as a local request. When the
2375+request produces a value, it does so like normal as a `%writ`, which is
2376+returned to `++take` along the path we just sent it on.
2377+
2378+```
2379+ %writ
2380+ ?> ?=([@ @ *] tea)
2381+ =+ our=(need (slaw %p i.tea))
2382+ =+ him=(need (slaw %p i.t.tea))
2383+ :_ ..^$
2384+ :~ :- hen
2385+ [%pass ~ %a [%want [our him] [%r %re %c t.t.tea] p.+.q.hin]]
2386+ ==
2387+```
2388+
2389+Since we encoded the ship we need to respond to in the path, we can just
2390+pass our `%want` back to ames, so that we tell the requesting ship about
2391+the new data.
2392+
2393+This comes back to the original ship as a `%waft` from ames, which comes
2394+into `++take`, right next to where we handled `%writ`.
2395+
2396+```
2397+ %waft
2398+ ?> ?=([@ @ ~] tea)
2399+ =+ syd=(need (slaw %tas i.tea))
2400+ =+ inx=(need (slaw %ud i.t.tea))
2401+ =+ ^= zat
2402+ =< wake
2403+ (knit:(do now p.+.q.hin syd ruf) [inx ((hard riot) q.+.q.hin)])
2404+ =^ mos ruf
2405+ =+ zot=abet.zat
2406+ [-.zot (posh q.p.+.q.hin syd +.zot ruf)]
2407+ [mos ..^$(ran.ruf ran.zat)] :: merge in new obj
2408+```
2409+
2410+This gets the desk and sequence number from the path the request was
2411+sent over. This determines exactly which request is being responded to.
2412+We call `++knit:de` to apply the changes to our local desk, and we call
2413+`++wake` to update our subscribers. Then we call `++abet:de` and
2414+`++posh` as normal (like in `++eave`).
2415+
2416+We'll examine `++knit` and `++wake`, in that order.
2417+
2418+```
2419+ ++ knit :: external change
2420+ |= [inx=@ud rot=riot]
2421+ ^+ +>
2422+ ?> ?=(^ ref)
2423+ |- ^+ +>+.$
2424+ =+ ruv=(~(get by bom.u.ref) inx)
2425+ ?~ ruv +>+.$
2426+ => ?. |(?=(~ rot) ?=(& -.q.u.ruv)) .
2427+ %_ .
2428+ bom.u.ref (~(del by bom.u.ref) inx)
2429+ fod.u.ref (~(del by fod.u.ref) p.u.ruv)
2430+ ==
2431+ ?~ rot
2432+ =+ rav=`rave`q.u.ruv
2433+ %= +>+.$
2434+ lim
2435+ ?.(&(?=(| -.rav) ?=(%da -.q.p.rav)) lim `@da`p.q.p.rav)
2436+ ::
2437+ haw.u.ref
2438+ ?. ?=(& -.rav) haw.u.ref
2439+ (~(put by haw.u.ref) p.rav ~)
2440+ ==
2441+ ?< ?=(%v p.p.u.rot)
2442+ =. haw.u.ref
2443+ (~(put by haw.u.ref) [p.p.u.rot q.p.u.rot q.u.rot] ~ r.u.rot)
2444+ ?. ?=(%w p.p.u.rot) +>+.$
2445+ |- ^+ +>+.^$
2446+ =+ nez=[%w [%ud let.dom] ~]
2447+ =+ nex=(~(get by haw.u.ref) nez)
2448+ ?~ nex +>+.^$
2449+ ?~ u.nex +>+.^$ :: should never happen
2450+ =. +>+.^$ =+ roo=(edis ((hard nako) u.u.nex))
2451+ ?>(?=(^ ref.roo) roo)
2452+ %= $
2453+ haw.u.ref (~(del by haw.u.ref) nez)
2454+ ==
2455+```
2456+
2457+This is kind of a long gate, but don't worry, it's not bad at all.
2458+
2459+First, we assert that we're not a domestic desk. That wouldn't make any
2460+sense at all.
2461+
2462+Since we have the sequence number of the request, we can get the duct
2463+and rave from `bom` in our request manager. If we didn't actually
2464+request this data (or the request was canceled before we got it), then
2465+we do nothing.
2466+
2467+Else, we remove the request from `bom` and `fod` unless this was a
2468+subscription request and we didn't receive a null riot (which would
2469+indicate the last message on the subscription).
2470+
2471+Now, if we received a null riot, then if this was a subscription request
2472+by date, then we update `lim` in our request manager (representing the
2473+latest time at which we have complete information for this desk) to the
2474+date that was requested. If this was a single read request, then we put
2475+the result in our simple cache `haw` to make future requests faster.
2476+Then we're done.
2477+
2478+If we received actual data, then we put it into our cache `haw`. Unless
2479+it's a `%w` request, we're done.
2480+
2481+If it is a `%w` request, then we try to get the `%w` at our current head
2482+from the cache. In general, that should be the thing we just put in a
2483+moment ago, but that is not guaranteed. The most common case where this
2484+is different is when we receive desk updates out of order. At any rate,
2485+since we now have new information, we need to apply it to our local copy
2486+of the desk. We do so in `++edis`, and then we remove the stuff we just
2487+applied from the cache, since it's not really a true "single read", like
2488+what should really be in the cache.
2489+
2490+```
2491+ ++ edis :: apply subscription
2492+ |= nak=nako
2493+ ^+ +>
2494+ %= +>
2495+ hit.dom (~(uni by hit.dom) gar.nak)
2496+ let.dom let.nak
2497+ lat.ran %+ roll (~(tap in bar.nak) ~)
2498+ =< .(yeb lat.ran)
2499+ |= [sar=blob yeb=(map lobe blob)]
2500+ =+ zax=(blob-to-lobe sar)
2501+ %+ ~(put by yeb) zax sar
2502+ hut.ran %+ roll (~(tap in lar.nak) ~)
2503+ =< .(yeb hut.ran)
2504+ |= [sar=yaki yeb=(map tako yaki)]
2505+ %+ ~(put by yeb) r.sar sar
2506+ ==
2507+```
2508+
2509+This shows, of course, exactly why nako is defined the way it is. To
2510+become completely up to date with the foreign desk, we need to merge
2511+`hit` with the foreign one so that we have all the revision numbers. We
2512+update `let` so that we know which revision is the head.
2513+
2514+We merge the new blobs in `lat`, keying them by their hash, which we get
2515+from a call to `++blob-to-lobe`. Recall that the hash is stored in the
2516+actual blob itself. We do the same thing to the new yakis, putting them
2517+in `hut`, keyed by their hash.
2518+
2519+Now, our local dome should be exactly the same as the foreign one.
2520+
2521+This concludes our discussion of `++knit`. Now the changes have been
2522+applied to our local copy of the desk, and we just need to update our
2523+subscribers. We do so in `++wake:de`.
2524+
2525+```
2526+ ++ wake :: update subscribers
2527+ ^+ .
2528+ =+ xiq=(~(tap by qyx) ~)
2529+ =| xaq=(list ,[p=duct q=rove])
2530+ |- ^+ ..wake
2531+ ?~ xiq
2532+ ..wake(qyx (~(gas by *cult) xaq))
2533+ ?- -.q.i.xiq
2534+ &
2535+ =+ cas=?~(ref ~ (~(get by haw.u.ref) `mood`p.q.i.xiq))
2536+ ?^ cas
2537+ %= $
2538+ xiq t.xiq
2539+ ..wake ?~ u.cas (blub p.i.xiq)
2540+ (blab p.i.xiq p.q.i.xiq u.u.cas)
2541+ ==
2542+ =+ nao=(~(case-to-aeon ze lim dom ran) q.p.q.i.xiq)
2543+ ?~ nao $(xiq t.xiq, xaq [i.xiq xaq])
2544+ $(xiq t.xiq, ..wake (balk p.i.xiq u.nao p.q.i.xiq))
2545+ ::
2546+ |
2547+ =+ mot=`moot`p.q.i.xiq
2548+ =+ nab=(~(case-to-aeon ze lim dom ran) p.mot)
2549+ ?~ nab
2550+ $(xiq t.xiq, xaq [i.xiq xaq])
2551+ =+ huy=(~(case-to-aeon ze lim dom ran) q.mot)
2552+ ?~ huy
2553+ =+ ptr=[%ud +(let.dom)]
2554+ %= $
2555+ xiq t.xiq
2556+ xaq [[p.i.xiq [%| ptr q.mot r.mot s.mot]] xaq]
2557+ ..wake =+ ^= ear
2558+ (~(lobes-at-path ze lim dom ran) let.dom r.p.q.i.xiq)
2559+ ?: =(s.p.q.i.xiq ear) ..wake
2560+ =+ fud=(~(make-nako ze lim dom ran) u.nab let.dom)
2561+ (bleb p.i.xiq let.dom fud)
2562+ ==
2563+ %= $
2564+ xiq t.xiq
2565+ ..wake =- (blub:- p.i.xiq)
2566+ =+ ^= ear
2567+ (~(lobes-at-path ze lim dom ran) u.huy r.p.q.i.xiq)
2568+ ?: =(s.p.q.i.xiq ear) (blub p.i.xiq)
2569+ =+ fud=(~(make-nako ze lim dom ran) u.nab u.huy)
2570+ (bleb p.i.xiq +(u.nab) fud)
2571+ ==
2572+ ==
2573+ --
2574+```
2575+
2576+This is even longer than `++knit`, but it's pretty similar to `++eave`.
2577+We loop through each of our subscribers `xiq`, processing each in turn.
2578+When we're done, we just put the remaining subscribers back in our
2579+subscriber list.
2580+
2581+If the subscriber is a single read, then, if this is a foreign desk
2582+(note that `++wake` is called from other arms, and not only on foreign
2583+desks). Obviously, if we find an identical request there, then we can
2584+produce the result immediately. Referential transparency for the win. We
2585+produce the result with a call to `++blab`. If this is a foreign desk
2586+but the result is not in the cache, then we produce `++blub` (canceled
2587+subscription with no data) for reasons entirely opaque to me. Seriously,
2588+it seems like we should wait until we get an actual response to the
2589+request. If someone figures out why this is, let me know. At any rate,
2590+it seems to work.
2591+
2592+If this is a domestic desk, then we check to see if the case exists yet.
2593+If it doesn't, then we simply move on to the next subscriber, consing
2594+this one onto `xaq` so that we can check again the next time around. If
2595+it does exist, then we call `++balk` to fulfill the request and produce
2596+it.
2597+
2598+`++balk` is very simple, so we'll describe it here before we get to the
2599+subscription case.
2600+
2601+```
2602+ ++ balk :: read and send
2603+ |= [hen=duct oan=@ud mun=mood]
2604+ ^+ +>
2605+ =+ vid=(~(read-at-aeon ze lim dom ran) oan mun)
2606+ ?~ vid (blub hen) (blab hen mun u.vid)
2607+```
2608+
2609+We call `++read-at-aeon` on the given request and aeon. If you recall,
2610+this processes a `mood` at a particular aeon and produces the result, if
2611+there is one. If there is data at the requested location, then we
2612+produce it with `++blab`. Else, we call `++blub` to notify the
2613+subscriber that no data can ever come over this subscriptioin since it
2614+is now impossible for there to ever be data for the given request.
2615+Because referential transparency.
2616+
2617+At any rate, back to `++wake`. If the given rave is a subscription
2618+request, then we proceed similarly to how we do in `++eave`. We first
2619+try to get the aeon referred to by the starting case. If it doesn't
2620+exist yet, then we can't do anything interesting with this subscription,
2621+so we move on to the next one.
2622+
2623+Otherwise, we try to get the aeon referred to by the ending case. If it
2624+doesn't exist yet, then we produce all the information we can. We call
2625+`++lobes-at-path` at the given aeon and path to see if the requested
2626+path has actually changed. If it hasn't, then we don't produce anything;
2627+else, we produce the correct nako by calling `++bleb` on the result of
2628+`++make-nako`, as in `++eave`. At any rate, we move on to the next
2629+subscription, putting back into our cult the current subscription with a
2630+new start case of the next aeon after the present.
2631+
2632+If the aeon referred to by the ending case does exist, then we drop this
2633+subscriber from our cult and satisfy its request immediately. This is
2634+the same as before -- we check to see if the data at the path has
2635+actually changed, producing it if it has; else, we call `++blub` since
2636+no more data can be produced over this subscription.
2637+
2638+This concludes our discussion of foreign requests.
learn/arvo/arvo-internals/clay/architecture.udondeleted−424
@@ -1,424 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− sort/'1'
4− title/'Clay Architecture'
5− ==
6−;>
7−
8−# Clay
9−
10−## high-level
11−
12−Clay is the primary filesystem for the arvo operating system,
13−which is the core of an urbit. The architecture of clay is
14−intrinsically connected with arvo, but we assume no knowledge of
15−either arvo or urbit. We will point out only those features of
16−arvo that are necessary for an understanding of clay, and we will
17−do so only when they arise.
18−
19−The first relevant feature of arvo is that it is a deterministic
20−system where input and output are defined as a series of events
21−and effects. The state of arvo is simply a function of its event
22−log. None of the effects from an event are emitted until the
23−event is entered in the log and persisted, either to disk or
24−another trusted source of persistence, such as a Kafka cluster.
25−Consequently, arvo is a single-level store: everything in its
26−state is persistent.
27−
28−In a more traditional OS, everything in RAM can be erased at any
29−time by power failure, and is always erased on reboot. Thus, a
30−primary purpose of a filesystem is to ensure files persist across
31−power failures and reboots. In arvo, both power failures and
32−reboots are special cases of suspending computation, which is
33−done safely since our event log is already persistent. Therefore,
34−clay is not needed in arvo for persistence. Why, then, do we have a
35−filesystem? There are two answers to this question.
36−
37−First, clay provides a filesystem tree, which is a convenient
38−user interface for some applications. Unix has the useful concept
39−of virtual filesystems, which are used for everything from direct
40−access to devices, to random number generators, to the /proc
41−tree. It is easy and intuitive to read from and write to a
42−filesystem tree.
43−
44−Second, clay has a distributed revision control system baked into
45−it. Traditional filesystems are not revision controlled, so
46−userspace software -- such as git -- is written on top of them to
47−do so. clay natively provides the same functionality as modern
48−DVCSes, and more.
49−
50−clay has two other unique properties that we'll cover later on:
51−it supports typed data and is referentially transparent.
52−
53−### Revision Control
54−
55−Every urbit has one or more "desks", which are independently
56−revision-controlled branches. Each desk contains its own mark
57−definitions, apps, doc, and so forth.
58−
59−Traditionally, an urbit has at least a base and a home desk. The
60−base desk has all the system software from the distribution. the
61−home desk is a fork of base with all the stuff specific to the
62−user of the urbit.
63−
64−A desk is a series of numbered commits, the most recent of which
65−represents the current state of the desk. A commit is composed of
66−(1) an absolute time when it was created, (2) a list of zero or
67−more parents, and (3) a map from paths to data.
68−
69−Most commits have exactly one parent, but the initial commit on a
70−desk may have zero parents, and merge commits have more than one
71−parent.
72−
73−The non-meta data is stored in the map of paths to data. It's
74−worth noting that no constraints are put on this map, so, for
75−example, both /a/b and /a/b/c could have data. This is impossible
76−in a traditional Unix filesystem since it means that /a/b is both
77−a file and a directory. Conventionally, the final element in the
78−path is its mark -- much like a filename extension in Unix. Thus,
79−/doc/readme.md in Unix is stored as /doc/readme/md in urbit.
80−
81−The data is not stored directly in the map; rather, a hash of the
82−data is stored, and we maintain a master blob store. Thus, if the
83−same data is referred to in multiple commits (as, for example,
84−when a file doesn't change between commits), only the hash is
85−duplicated.
86−
87−In the master blob store, we either store the data directly, or
88−else we store a diff against another blob. The hash is dependent
89−only on the data within and not on whether or not it's stored
90−directly, so we may on occasion rearrange the contents of the
91−blob store for performance reasons.
92−
93−Recall that a desk is a series of numbered commits. Not every
94−commit in a desk must be numbered. For example, if the base desk
95−has had 50 commits since home was forked from it, then a merge
96−from base to home will only add a single revision number to home,
97−although the full commit history will be accessible by traversing
98−the parentage of the individual commits.
99−
100−We do guarantee that the first commit is numbered 1, commits are
101−numbered consecutively after that (i.e. there are no "holes"),
102−the topmost commit is always numbered, and every numbered commit
103−is an ancestor of every later numbered commit.
104−
105−There are three ways to refer to particular commits in the
106−revision history. Firstly, one can use the revision number.
107−Secondly, one can use any absolute time between the one numbered
108−commit and the next (inclusive of the first, exclusive of the
109−second). Thirdly, every desk has a map of labels to revision
110−numbers. These labels may be used to refer to specific commits.
111−
112−Additionally, clay is a global filesystem, so data on other urbit
113−is easily accessible the same way as data on our local urbit. In
114−general, the path to a particular revision of a desk is
115−/~urbit-name/desk-name/revision. Thus, to get /try/readme/md
116−from revision 5 of the home desk on ~sampel-sipnym, we refer to
117−/~sampel-sipnym/home/5/try/readme/md. Clay's namespace is thus
118−global and referentially transparent.
119−
120−XXX reactivity here?
121−
122−### A Typed Filesystem
123−
124−Since clay is a general filesystem for storing data of arbitrary
125−types, in order to revision control correctly it needs to be
126−aware of types all the way through. Traditional revision control
127−does an excellent job of handling source code, so for source code
128−we act very similar to traditional revision control. The
129−challenge is to handle other data similarly well.
130−
131−For example, modern VCSs generally support "binary files", which
132−are files for which the standard textual diffing, patching, and
133−merging algorithms are not helpful. A "diff" of two binary files
134−is just a pair of the files, "patching" this diff is just
135−replacing the old file with the new one, and "merging"
136−non-identical diffs is always a conflict, which can't even be
137−helpfully annotated. Without knowing anything about the structure
138−of a blob of data, this is the best we can do.
139−
140−Often, though, "binary" files have some internal structure, and
141−it is possible to create diff, patch, and merge algorithms that
142−take advantage of this structure. An image may be the result of a
143−base image with some set of operations applied. With algorithms
144−aware of this set of operations, not only can revision control
145−software save space by not having to save every revision of the
146−image individually, these transformations can be made on parallel
147−branches and merged at will.
148−
149−Suppose Alice is tasked with touching up a picture, improving the
150−color balance, adjusting the contrast, and so forth, while Bob
151−has the job of cropping the picture to fit where it's needed and
152−adding textual overlay. Without type-aware revision control,
153−these changes must be made serially, requiring Alice and Bob to
154−explicitly coordinate their efforts. With type-aware revision
155−control, these operations may be performed in parallel, and then
156−the two changesets can be merged programmatically.
157−
158−Of course, even some kinds of text files may be better served by
159−diff, patch, and merge algorithms aware of the structure of the
160−files. Consider a file containing a pretty-printed JSON object.
161−Small changes in the JSON object may result in rather significant
162−changes in how the object is pretty-printed (for example, by
163−addding an indentation level, splitting a single line into
164−multiple lines).
165−
166−A text file wrapped at 80 columns also reacts suboptimally with
167−unadorned Hunt-McIlroy diffs. A single word inserted in a
168−paragraph may push the final word or two of the line onto the
169−next line, and the entire rest of the paragraph may be flagged as
170−a change. Two diffs consisting of a single added word to
171−different sentences may be flagged as a conflict. In general,
172−prose should be diffed by sentence, not by line.
173−
174−As far as the author is aware, clay is the first generalized,
175−type-aware revision control system. We'll go into the workings
176−of this system in some detail.
177−
178−### Marks
179−
180−Central to a typed filesystem is the idea of types. In clay, we
181−call these "marks". A mark is a file that defines a type,
182−conversion routines to and from the mark, and diff, patch, and
183−merge routines.
184−
185−For example, a `%txt` mark may be a list of lines of text, and it
186−may include conversions to `%mime` to allow it to be serialized
187−and sent to a browswer or to the unix filesystem. It will also
188−include Hunt-McIlroy diff, patch, and merge algorithms.
189−
190−A `%json` mark would be defined as a json object in the code, and
191−it would have a parser to convert from `%txt` and a printer to
192−convert back to `%txt`. The diff, patch, and merge algorithms are
193−fairly straightforward for json, though they're very different
194−from the text ones.
195−
196−More formally, a mark is a core with three arms, `++grab`,
197−`++grow`, and `++grad`. In `++grab` is a series of functions to
198−convert from other marks to the given mark. In `++grow` is a
199−series of functions to convert from the given mark to other
200−marks. In `++grad` is `++diff`, `++pact`, `++join`, and `++mash`.
201−
202−The types are as follows, in an informal pseudocode:
203−
204−```
205− ++ grab:
206− ++ mime: <mime> -> <mark-type>
207− ++ txt: <txt> -> <mark-type>
208− ...
209− ++ grow:
210− ++ mime: <mark-type> -> <mime>
211− ++ txt: <mark-type> -> <txt>
212− ...
213− ++ grad
214− ++ diff: (<mark-type>, <mark-type>) -> <diff-type>
215− ++ pact: (<mark-type>, <diff-type>) -> <mark-type>
216− ++ join: (<diff-type>, <diff-type>) -> <diff-type> or NULL
217− ++ mash: (<diff-type>, <diff-type>) -> <diff-type>
218−```
219−
220−These types are basically what you would expect. Not every mark
221−has each of these functions defined -- all of them are optional
222−in the general case.
223−
224−In general, for a particular mark, the `++grab` and `++grow` entries
225−(if they exist) should be inverses of each other.
226−
227−In `++grad`, `++diff` takes two instances of a mark and produces
228−a diff of them. `++pact` takes an instance of a mark and patches
229−it with the given diff. `++join` takes two diffs and attempts to
230−merge them into a single diff. If there are conflicts, it
231−produces null. `++mash` takes two diffs and forces a merge,
232−annotating any conflicts.
233−
234−In general, if `++diff` called with A and B produces diff D, then
235−`++pact` called with A and D should produce B. Also, if `++join`
236−of two diffs does not produce null, then `++mash` of the same
237−diffs should produce the same result.
238−
239−Alternately, instead of `++diff`, `++pact`, `++join`, and
240−`++mash`, a mark can provide the same functionality by defining
241−`++sted` to be the name of another mark to which we wish to
242−delegate the revision control responsibilities. Then, before
243−running any of those functions, clay will convert to the other
244−mark, and convert back afterward. For example, the `%hoon` mark
245−is revision-controlled in the same way as `%txt`, so its `++grad`
246−is simply `++sted %txt`. Of course, `++txt` must be defined in
247−`++grow` and `++grab` as well.
248−
249−Every file in clay has a mark, and that mark must have a
250−fully-functioning `++grad`. Marks are used for more than just
251−clay, and other marks don't need a `++grad`, but if a piece of
252−data is to be saved to clay, we must know how to revision-control
253−it.
254−
255−Additionally, if a file is to be synced out to unix, then it must
256−have conversion routines to and from the `%mime` mark.
257−
258−##Using clay
259−
260−### Reading and Subscribing
261−
262−When reading from Clay, there are three types of requests. A
263−`%sing` request asks for data at single revsion. A `%next`
264−request asks to be notified the next time there's a change to
265−given file. A `%many` request asks to be notified on every
266−change in a desk for a range of changes.
267−
268−For `%sing` and `%next`, there are generally three things to be
269−queried. A `%u` request simply checks for the existence of a
270−file at a path. A `%x` request gets the data in the file at a
271−path. A `%y` request gets a hash of the data in the file at the
272−path combined with all its children and their data. Thus, `%y`
273−of a node changes if it or any of its children change.
274−
275−A `%sing` request is fulfilled immediately if possible. If the
276−requested revision is in the future, or is on another ship for
277−which we don't have the result cached, we don't respond
278−immediately. If the requested revision is in the future, we wait
279−until the revision happens before we respond to the request. If
280−the request is for data on another ship, we pass on the request
281−to the other ship. In general, Clay subscriptions, like most
282−things in Urbit, aren't guaranteed to return immediately.
283−They'll return when they can, and they'll do so in a
284−referentially transparent manner.
285−
286−A `%next` request checks query at the given revision, and it
287−produces the result of the query the next time it changes, along
288−with the revsion number when it changes. Thus, a `%next` of a
289−`%u` is triggered when a file is added or deleted, a `%next` of a
290−`%x` is triggered when a file is added, deleted, or changed, and
291−a `%next` of a `%y` is triggered when a file or any of its
292−children is added, deleted, or changed.
293−
294−A `%many` request is triggered every time the given desk has a
295−new revision. Unlike a `%next`, a `%many` has both a start and
296−an end revsion, after which it stops returning. For `%next`, a
297−single change is reported, and if the caller wishes to hear of
298−the next change, it must resubscribe. For `%many`, every revsion
299−from the start to the end triggers a response. Since a `%many`
300−request doesn't ask for any particular data, there aren't `%u`,
301−`%x`, and `%y` versions for it.
302−
303−### Unix sync
304−
305−One of the primary functions of clay is as a convenient user
306−interface. While tools exist to use clay from within urbit, it's
307−often useful to be able to treat clay like any other filesystem
308−from the Unix perspective -- to "mount" it, as it were.
309−
310−From urbit, you can run `|mount /path/to/directory %mount-point`,
311−and this will mount the given clay directory to the mount-point
312−directory in Unix. Every file is converted to `%mime` before it's
313−written to Unix, and converted back when read from Unix. The
314−entire directory is watched (a la Dropbox), and every change is
315−auto-committed to clay.
316−
317−### Merging
318−
319−Merging is a fundamental operation for a distributed revision
320−control system. At their root, clay's merges are similar to
321−git's, but with some additions to accomodate typed data. There
322−are seven different merge strategies.
323−
324−Throughout our discussion, we'll say that the merge is from
325−Alice's desk to Bob's. Recall that a commit is a date (for all
326−new commits this will be the current date), a list of parents,
327−and the data itself.
328−
329−A `%init` merge should be used iff it's the first commit to a
330−desk. The head of Alice's desk is used as the number 1 commit to
331−Bob's desk. Obviously, the ancestry remains intact through
332−traversing the parentage of the commit even though previous
333−commits are not numbered for Bob's desk.
334−
335−A `%this` merge means to keep what's in Bob's desk, but join the
336−ancestry. Thus, the new commit has the head of each desk as
337−parents, but the data is exactly what's in Bob's desk. For those
338−following along in git, this is the 'ours' merge strategy, not
339−the '--ours' option to the 'recursive' merge strategy. In other
340−words, even if Alice makes a change that does not conflict with
341−Bob, we throw it away. It's Bob's way or the highway.
342−
343−A `%that` merge means to take what's in Alice's desk, but join
344−the ancestry. This is the reverse of `%this`.
345−
346−A `%fine` merge is a "fast-forward" merge. This succeeds iff one
347−head is in the ancestry of the other. In this case, we use the
348−descendant as our new head.
349−
350−For `%meet`, `%mate`, and `%meld` merges, we first find the most
351−recent common ancestor to use as our merge base. If we have no
352−common ancestors, then we fail. If we have more than one most
353−recent common ancestor, then we have a criss-cross situation,
354−which should be handled delicately. At present, we delicately
355−throw up our hands and give up, but something akin to git's
356−'recursive' strategy should be implemented in the future.
357−
358−There's a functional inclusion ordering on `%fine`, `%meet`,
359−`%mate`, and `%meld` such that if an earlier strategy would have
360−succeeded, then every later strategy will produce the same
361−result. Put another way, every earlier strategy is the same as
362−every later strategy except with a restricted domain.
363−
364−A `%meet` merge only succeeds if the changes from the merge base
365−to Alice's head (hereafter, "Alice's changes") are in different
366−files than Bob's changes. In this case, the parents are both
367−Alice's and Bob's heads, and the data is the merge base plus
368−Alice's changed files plus Bob's changed files.
369−
370−A `%mate` merge attempts to merge changes to the same file when
371−both Alice and bob change it. If the merge is clean, we use it;
372−otherwise, we fail. A merge between different types of changes --
373−for example, deleting a file vs changing it -- is always a
374−conflict. If we succeed, the parents are both Alice's and Bob's
375−heads, and the data is the merge base plus Alice's changed files
376−plus Bob's changed files plus the merged files.
377−
378−A `%meld` merge will succeed even if there are conflicts. If
379−there are conflicts in a file, then we use the merge base's
380−version of that file, and we produce a set of files with
381−conflicts. The parents are both Alice's and Bob's heads, and the
382−data is the merge base plus Alice's changed files plus Bob's
383−changed files plus the successfully merged files plus the merge
384−base's version of the conflicting files.
385−
386−That's the extent of the merge options in clay proper. In
387−userspace there's a final option `%auto`, which is the most
388−common. `%auto` checks to see if Bob's desk exists, and if it
389−doesn't we use a `%init` merge. Otherwise, we progressively try
390−`%fine`, `%meet`, and `%mate` until one succeeds.
391−
392−If none succeed, we merge Bob's desk into a scratch desk. Then,
393−we merge Alice's desk into the scratch desk with the `%meld`
394−option to force the merge. For each file in the produced set of
395−conflicting files, we call the `++mash` function for the
396−appropriate mark, which annotates the conflicts if we know how.
397−
398−Finally, we display a message to the user informing them of the
399−scratch desk's existence, which files have annotated conflicts,
400−and which files have unannotated conflicts. When the user has
401−resolved the conflicts, they can merge the scratch desk back into
402−Bob's desk. This will be a `%fine` merge since Bob's head is in
403−the ancestry of the scratch desk.
404−
405−### Autosync
406−
407−Tracking and staying in sync with another desk is another
408−fundamental operation. We call this "autosync". This doesn't mean
409−simply mirroring a desk, since that wouldn't allow local changes.
410−We simply want to apply changes as they are made upstream, as
411−long as there are no conflicts with local changes.
412−
413−This is implemented by watching the other desk, and, when it has
414−changes, merging these changes into our desk with the usual merge
415−strategies.
416−
417−Note that it's quite reasonable for two desks to be autosynced to
418−each other. This results in any change on one desk being mirrored
419−to the other and vice versa.
420−
421−Additionally, it's fine to set up an autosync even if one desk,
422−the other desk, or both desks do not exist. The sync will be
423−activated when the upstream desk comes into existence and will
424−create the downstream desk if needed.
learn/arvo/arvo-internals/clay/commentary.udondeleted−2196
@@ -1,2196 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− sort/'2'
4− title/'Clay commentary'
5− ==
6−;>
7−
8−# Clay commentary
9−
10−`%clay` is our filesystem.
11−
12−The first part of this will be reference documentation for the data
13−types used by our filesystem. In fact, as a general guide, we recommend
14−reading and attempting to understand the data structures used in any
15−Hoon code before you try to read the code itself. Although complete
16−understanding of the data structures is impossible without seeing them
17−used in the code, an 80% understanding greatly clarifies the code. As
18−another general guide, when reading Hoon, it rarely pays off to
19−understand every line of code when it appears. Try to get the gist of
20−it, and then move on. The next time you come back to it, it'll likely
21−make a lot more sense.
22−
23−After a description of the data models, we'll give an overview of the
24−interface that vanes and applications can use to interact with the
25−filesystem.
26−
27−Finally, we'll dive into the code and the algorithms themselves. You
28−know, the fun part.
29−
30−## Data Models
31−
32−As you're reading through this section, remember you can always come
33−back to this when you run into these types later on. You're not going to
34−remember everything the first time through, but it is worth reading, or
35−at least skimming, this so that you get a rough idea of how our state is
36−organized.
37−
38−The types that are certainly worth reading are `++raft`, `++room`,
39−`++dome`, `++ankh`, `++rung`, `++rang`, `++blob`, `++yaki`, and `++nori`
40−(possibly in that order). All in all, though, this section isn't too
41−long, so many readers may wish to quickly read through all of it. If you
42−get bored, though, just skip to the next section. You can always come
43−back when you need to.
44−
45−### `++raft`, formal state
46−
47−```
48− ++ raft :: filesystem
49− $: fat=(map ship room) :: domestic
50− hoy=(map ship rung) :: foreign
51− ran=rang :: hashes
52− == ::
53−```
54−
55−This is the state of our vane. Anything that must be remembered between
56−calls to clay is stored in this state.
57−
58−`fat` is the set of domestic servers. This stores all the information
59−that is specfic to a particular ship on this pier. The keys to this map
60−are the ships on the current pier. all the information that is specific
61−to a particular foreign ship. The keys to this map are all the ships
62−whose filesystems we have attempted to access through clay.
63−
64−`ran` is the store of all commits and deltas, keyed by hash. The is
65−where all the "real" data we know is stored; the rest is "just
66−bookkeeping".
67−
68−### `++room`, filesystem per domestic ship
69−
70−```
71− ++ room :: fs per ship
72− $: hun=duct :: terminal duct
73− hez=(unit duct) :: sync duch
74− dos=(map desk dojo) :: native desk
75− == ::
76−```
77−
78−This is the representation of the filesystem of a ship on our pier.
79−
80−`hun` is the duct we use to send messages to dill to display
81−notifications of filesystem changes. Only `%note` gifts should be
82−produced along this duct. This is set by the `%init` kiss.
83−
84−`hez`, if present, is the duct we use to send sync messages to unix so
85−that they end up in the pier unix directory. Only `%ergo` gifts should
86−be producd along this duct. This is set by `%into` and `%invo` kisses.
87−
88−`dos` is a well-known operating system released in 1981. It is also the
89−set of desks on this ship, mapped to their data.
90−
91−### `++desk`, filesystem branch
92−
93−```
94− ++ desk ,@tas :: ship desk case spur
95−```
96−
97−This is the name of a branch of the filesystem. The default desks are
98−"arvo", "main", and "try". More may be created by simply referencing
99−them. Desks have independent histories and states, and they may be
100−merged into each other.
101−
102−### `++dojo`, domestic desk state
103−
104−```
105− ++ dojo ,[p=cult q=dome] :: domestic desk state
106−```
107−
108−This is the all the data that is specific to a particular desk on a
109−domestic ship. `p` is the set of subscribers to this desk and `q` is the
110−data in the desk.
111−
112−### `++cult`, subscriptions
113−
114−```
115− ++ cult (map duct rave) :: subscriptions
116−```
117−
118−This is the set of subscriptions to a particular desk. The keys are the
119−ducts from where the subscriptions requests came. The results will be
120−produced along these ducts. The values are a description of the
121−requested information.
122−
123−### `++rave`, general subscription request
124−
125−```
126− ++ rave :: general request
127− $% [& p=mood] :: single request
128− [| p=moat] :: change range
129− == ::
130−```
131−
132−This represents a subscription request for a desk. The request can be
133−for either a single item in the desk or else for a range of changes on
134−the desk.
135−
136−### `++rove`, stored general subscription request
137−
138−```
139− ++ rove (each mood moot) :: stored request
140−```
141−
142−When we store a request, we store subscriptions with a little extra
143−information so that we can determine whether new versions actually
144−affect the path we're subscribed to.
145−
146−### `++mood`, single subscription request
147−
148−```
149− ++ mood ,[p=care q=case r=path] :: request in desk
150−```
151−
152−This represents a request for the state of the desk at a particular
153−commit, specfied by `q`. `p` specifies what kind of information is
154−desired, and `r` specifies the path we are requesting.
155−
156−### `++moat`, range subscription request
157−
158−```
159− ++ moat ,[p=case q=case r=path] :: change range
160−```
161−
162−This represents a request for all changes between `p` and `q` on path
163−`r`. You will be notified when a change is made to the node referenced
164−by the path or to any of its children.
165−
166−### `++moot`, stored range subscription request
167−
168−```
169− ++ moot ,[p=case q=case r=path s=(map path lobe)] ::
170−```
171−
172−This is just a `++moat` plus a map of paths to lobes. This map
173−represents the data at the node referenced by the path at case `p`, if
174−we've gotten to that case (else null). We only send a notification along
175−the subscription if the data at a new revision is different than it was.
176−
177−### `++care`, clay submode
178−
179−```
180− ++ care ?(%u %v %w %x %y %z) :: clay submode
181−```
182−
183−This specifies what type of information is requested in a subscription
184−or a scry.
185−
186−`%u` requests the `++rang` at the current moment. Because this
187−information is not stored for any moment other than the present, we
188−crash if the `++case` is not a `%da` for now.
189−
190−`%v` requests the `++dome` at the specified commit.
191−
192−`%w` requests the revsion number of the desk.
193−
194−`%x` requests the file at a specified path at the specified commit. If
195−there is no node at that path or if the node has no contents (that is,
196−if `q:ankh` is null), then this produces null.
197−
198−`%y` requests a `++arch` of the specfied commit at the specified path.
199−
200−`%z` requests the `++ankh` of the specified commit at the specfied path.
201−
202−### `++arch`, shallow filesystem node
203−
204−```
205− ++ arch ,[p=@uvI q=(unit ,@uvI) r=(map ,@ta ,~)] :: fundamental node
206−```
207−
208−This is analogous to `++ankh` except that the we have neither our
209−contents nor the ankhs of our children. The other fields are exactly the
210−same, so `p` is a hash of the associated ankh, `u.q`, if it exists, is a
211−hash of the contents of this node, and the keys of `r` are the names of
212−our children. `r` is a map to null rather than a set so that the
213−ordering of the map will be equivalent to that of `r:ankh`, allowing
214−efficient conversion.
215−
216−### `++case`, specifying a commit
217−
218−```
219− ++ case :: ship desk case spur
220− $% [%da p=@da] :: date
221− [%tas p=@tas] :: label
222− [%ud p=@ud] :: number
223− == ::
224−```
225−
226−A commit can be referred to in three ways: `%da` refers to the commit
227−that was at the head on date `p`, `%tas` refers to the commit labeled
228−`p`, and `%ud` refers to the commit numbered `p`. Note that since these
229−all can be reduced down to a `%ud`, only numbered commits may be
230−referenced with a `++case`.
231−
232−### `++dome`, desk data
233−
234−```
235− ++ dome :: project state
236− $: ang=agon :: pedigree
237− ank=ankh :: state
238− let=@ud :: top id
239− hit=(map ,@ud tako) :: changes by id
240− lab=(map ,@tas ,@ud) :: labels
241− == ::
242−```
243−
244−This is the data that is actually stored in a desk.
245−
246−`ang` is unused and should be removed.
247−
248−`ank` is the current state of the desk. Thus, it is the state of the
249−filesystem at revison `let`. The head of a desk is always a numbered
250−commit.
251−
252−`let` is the number of the most recently numbered commit. This is also
253−the total number of numbered commits.
254−
255−`hit` is a map of numerical ids to hashes of commits. These hashes are
256−mapped into their associated commits in `hut:rang`. In general, the keys
257−of this map are exactly the numbers from 1 to `let`, with no gaps. Of
258−course, when there are no numbered commits, `let` is 0, so `hit` is
259−null. Additionally, each of the commits is an ancestor of every commit
260−numbered greater than this one. Thus, each is a descendant of every
261−commit numbered less than this one. Since it is true that the date in
262−each commit (`t:yaki`) is no earlier than that of each of its parents,
263−the numbered commits are totally ordered in the same way by both
264−pedigree and date. Of course, not every commit is numbered. If that
265−sounds too complicated to you, don't worry about it. It basically
266−behaves exactly as you would expect.
267−
268−`lab` is a map of textual labels to numbered commits. Note that labels
269−can only be applied to numbered commits. Labels must be unique across a
270−desk.
271−
272−### `++ankh`, filesystem node
273−
274−```
275− ++ ankh :: fs node (new)
276− $: p=cash :: recursive hash
277− q=(unit ,[p=cash q=*]) :: file
278− r=(map ,@ta ankh) :: folders
279− == ::
280−```
281−
282−This is a single node in the filesystem. This may be file or a directory
283−or both. In earth filesystems, a node is a file xor a directory. On
284−mars, we're inclusive, so a node is a file ior a directory.
285−
286−`p` is a recursive hash that depends on the contents of the this file or
287−directory and on any children.
288−
289−`q` is the contents of this file, if any. `p.q` is a hash of the
290−contents while `q.q` is the data itself.
291−
292−`r` is the set of children of this node. In the case of a pure file,
293−this is empty. The keys are the names of the children and the values
294−are, recursively, the nodes themselves.
295−
296−### `++cash`, ankh hash
297−
298−```
299− ++ cash ,@uvH :: ankh hash
300−```
301−
302−This is a 128-bit hash of an ankh. These are mostly stored within ankhs
303−themselves, and they are used to check for changes in possibly-deep
304−hierarchies.
305−
306−### `++rung`, filesystem per neighbor ship
307−
308−```
309− ++ rung $: rus=(map desk rede) :: neighbor desks
310− == ::
311−```
312−
313−This is the filesystem of a neighbor ship. The keys to this map are all
314−the desks we know about on their ship.
315−
316−### `++rede`, desk state
317−
318−```
319− ++ rede :: universal project
320− $: lim=@da :: complete to
321− qyx=cult :: subscribers
322− ref=(unit rind) :: outgoing requests
323− dom=dome :: revision state
324− == ::
325−```
326−
327−This is our knowledge of the state of a desk, either foreign or
328−domestic.
329−
330−`lim` is the date of the last full update. We only respond to requests
331−for stuff before this time.
332−
333−`qyx` is the list of subscribers to this desk. For domestic desks, this
334−is simply `p:dojo`, all subscribers to the desk, while in foreign desks
335−this is all the subscribers from our ship to the foreign desk.
336−
337−`ref` is the request manager for the desk. For domestic desks, this is
338−null since we handle requests ourselves.
339−
340−`dom` is the actual data in the desk.
341−
342−### `++rind`, request manager
343−
344−```
345− ++ rind :: request manager
346− $: nix=@ud :: request index
347− bom=(map ,@ud ,[p=duct q=rave]) :: outstanding
348− fod=(map duct ,@ud) :: current requests
349− haw=(map mood (unit)) :: simple cache
350− == ::
351−```
352−
353−This is the request manager for a foreign desk.
354−
355−`nix` is one more than the index of the most recent request. Thus, it is
356−the next available request number.
357−
358−`bom` is the set of outstanding requests. The keys of this map are some
359−subset of the numbers between 0 and one less than `nix`. The members of
360−the map are exactly those requests that have not yet been fully
361−satisfied.
362−
363−`fod` is the same set as `bom`, but from a different perspective. In
364−particular, the values of `fod` are the same as the values of `bom`, and
365−the `p` out of the values of `bom` are the same as the keys of `fod`.
366−Thus, we can map ducts to their associated request number and `++rave`,
367−and we can map numbers to their associated duct and `++rave`.
368−
369−`haw` is a map from simple requests to their values. This acts as a
370−cache for requests that have already been made. Thus, the second request
371−for a particular `++mood` is nearly instantaneous.
372−
373−### `++rang`, data store
374−
375−```
376− ++ rang $: hut=(map tako yaki) ::
377− lat=(map lobe blob) ::
378− == ::
379−```
380−
381−This is a set of data keyed by hash. Thus, this is where the "real" data
382−is stored, but it is only meaningful if we know the hash of what we're
383−looking for.
384−
385−`hut` is a map from hashes to commits. We often get the hashes from
386−`hit:dome`, which keys them by logical id. Not every commit has an id.
387−
388−`lat` is a map from hashes to the actual data. We often get the hashes
389−from a `++yaki`, a commit, which references this map to get the data.
390−There is no `++blob` in any `++yaki`. They are only accessible through
391−this map.
392−
393−### `++tako`, commit reference
394−
395−```
396− ++ tako ,@ :: yaki ref
397−```
398−
399−This is a hash of a `++yaki`, a commit. These are most notably used as
400−the keys in `hut:rang`, where they are associated with the actual
401−`++yaki`, and as the values in `hit:dome`, where sequential ids are
402−associated with these.
403−
404−### `++yaki`, commit
405−
406−```
407− ++ yaki ,[p=(list tako) q=(map path lobe) r=tako t=@da] :: commit
408−```
409−
410−This is a single commit.
411−
412−`p` is a list of the hashes of the parents of this commit. In most
413−cases, this will be a single commit, but in a merge there may be more
414−parents. In theory, there may be an arbitrary number of parents, but in
415−practice merges have exactly two parents. This may change in the future.
416−For commit 1, there is no parent.
417−
418−`q` is a map of the paths on a desk to the data at that location. If you
419−understand what a `++lobe` and a `++blob` is, then the type signature
420−here tells the whole story.
421−
422−`r` is the hash associated with this commit.
423−
424−`t` is the date at which this commit was made.
425−
426−### `++lobe`, data reference
427−
428−```
429− ++ lobe ,@ :: blob ref
430−```
431−
432−This is a hash of a `++blob`. These are most notably used in `lat:rang`,
433−where they are associated with the actual `++blob`, and as the values in
434−`q:yaki`, where paths are associated with their data in a commit.
435−
436−### `++blob`, data
437−
438−```
439− ++ blob $% [%delta p=lobe q=lobe r=udon] :: delta on q
440− [%direct p=lobe q=* r=umph] ::
441− [%indirect p=lobe q=* r=udon s=lobe] ::
442− == ::
443−```
444−
445−This is a node of data. In every case, `p` is the hash of the blob.
446−
447−`%delta` is the case where we define the data by a delta on other data.
448−In practice, the other data is always the previous commit, but nothing
449−depends on this. `q` is the hash of the parent blob, and `r` is the
450−delta.
451−
452−`%direct` is the case where we simply have the data directly. `q` is the
453−data itself, and `r` is any preprocessing instructions. These almost
454−always come from the creation of a file.
455−
456−`%indirect` is both of the preceding cases at once. `q` is the direct
457−data, `r` is the delta, and `s` is the parent blob. It should always be
458−the case that applying `r` to `s` gives the same data as `q` directly
459−(with the prepreprocessor instructions in `p.r`). This exists purely for
460−performance reasons. This is unused, at the moment, but in general these
461−should be created when there are a long line of changes so that we do
462−not have to traverse the delta chain back to the creation of the file.
463−
464−### `++udon`, abstract delta
465−
466−```
467− ++ udon :: abstract delta
468− $: p=umph :: preprocessor
469− $= q :: patch
470− $% [%a p=* q=*] :: trivial replace
471− [%b p=udal] :: atomic indel
472− [%c p=(urge)] :: list indel
473− [%d p=upas q=upas] :: tree edit
474− == ::
475− == ::
476−```
477−
478−This is an abstract change to a file. This is a superset of what would
479−normally be called diffs. Diffs usually refer to changes in lines of
480−text while we have the ability to do more interesting deltas on
481−arbitrary data structures.
482−
483−`p` is any preprocessor instructions.
484−
485−`%a` refers to the trival delta of a complete replace of old data with
486−new data.
487−
488−`%b` refers to changes in an opaque atom on the block level. This has
489−very limited usefulness, and is not used at the moment.
490−
491−`%c` refers to changes in a list of data. This is often lines of text,
492−which is your classic diff. We, however, will work on any list of data.
493−
494−`%d` refers to changes in a tree of data. This is general enough to
495−describe changes to any hoon noun, but often more special-purpose delta
496−should be created for different content types. This is not used at the
497−moment, and may in fact be unimplemented.
498−
499−### `++urge`, list change
500−
501−```
502− ++ urge |*(a=_,* (list (unce a))) :: list change
503−```
504−
505−This is a parametrized type for list changes. For example, `(urge ,@t)`
506−is a list change for lines of text.
507−
508−### `++unce`, change part of a list.
509−
510−```
511− ++ unce |* a=_,* :: change part
512− $% [%& p=@ud] :: skip[copy]
513− [%| p=(list a) q=(list a)] :: p -> q[chunk]
514− == ::
515−```
516−
517−This is a single change in a list of elements of type `a`. For example,
518−`(unce ,@t)` is a single change in a lines of text.
519−
520−`%&` means the next `p` lines are unchanged.
521−
522−`%|` means the lines `p` have changed to `q`.
523−
524−### `++umph`, preprocessing information
525−
526−```
527− ++ umph :: change filter
528− $| $? %a :: no filter
529− %b :: jamfile
530− %c :: LF text
531− == ::
532− $% [%d p=@ud] :: blocklist
533− == ::
534−```
535−
536−This space intentionally left undocumented. This stuff will change once
537−we get a well-typed clay.
538−
539−### `++upas`, tree change
540−
541−```
542− ++ upas :: tree change (%d)
543− $& [p=upas q=upas] :: cell
544− $% [%0 p=axis] :: copy old
545− [%1 p=*] :: insert new
546− [%2 p=axis q=udon] :: mutate!
547− == ::
548−```
549−
550−This space intentionally left undocumented. This stuff is not known to
551−work, and will likely change when we get a well-typed clay. Also, this
552−is not a complicated type; it is not difficult to work out the meaning.
553−
554−### `++nori`, repository action
555−
556−```
557− ++ nori :: repository action
558− $% [& q=soba] :: delta
559− [| p=@tas] :: label
560− == ::
561−```
562−
563−This describes a change that we are asking clay to make to the desk.
564−There are two kinds of changes that may be made: we can modify files or
565−we can apply a label to a commit.
566−
567−In the `|` case, we will simply label the current commit with the given
568−label. In the `&` case, we will apply the given changes.
569−
570−### `++soba`, delta
571−
572−```
573− ++ soba ,[p=cart q=(list ,[p=path q=miso])] :: delta
574−```
575−
576−This describes a set of changes to make to a desk. The `cart` is simply
577−a pair of the old hash and the new hash of the desk. The list is a list
578−of changes keyed by the file they're changing. Thus, the paths are paths
579−to files to be changed while `miso` is a description of the change
580−itself.
581−
582−### `++miso`, ankh delta
583−
584−```
585− ++ miso :: ankh delta
586− $% [%del p=*] :: delete
587− [%ins p=*] :: insert
588− [%mut p=udon] :: mutate
589− == ::
590−```
591−
592−There are three kinds of changes that may be made to a node in a desk.
593−We can insert a file, in which case `p` is the contents of the new file.
594−We can delete a file, in which case `p` is the contents of the old file.
595−Finally, we can mutate that file, in which case the `udon` describes the
596−changes we are applying to the file.
597−
598−### `++mizu`, merged state
599−
600−```
601− ++ mizu ,[p=@u q=(map ,@ud tako) r=rang] :: new state
602−```
603−
604−This is the input to the `%merg` kiss, which allows us to perform a
605−merge. The `p` is the number of the new head commit. The `q` is a map
606−from numbers to commit hashes. This is all the new numbered commits that
607−are to be inserted. The keys to this should always be the numbers from
608−`let.dom` plus one to `p`, inclusive. The `r` is the maps of all the new
609−commits and data. Since these are merged into the current state, no old
610−commits or data need be here.
611−
612−### `++riff`, request/desist
613−
614−```
615− ++ riff ,[p=desk q=(unit rave)] :: request/desist
616−```
617−
618−This represents a request for data about a particular desk. If `q`
619−contains a `rave`, then this opens a subscription to the desk for that
620−data. If `q` is null, then this tells clay to cancel the subscription
621−along this duct.
622−
623−### `++riot`, response
624−
625−```
626− ++ riot (unit rant) :: response/complete
627−```
628−
629−A riot is a response to a subscription. If null, the subscription has
630−been completed, and no more responses will be sent. Otherwise, the
631−`rant` is the produced data.
632−
633−### `++rant`, response data
634−
635−```
636− ++ rant :: namespace binding
637− $: p=[p=care q=case r=@tas] :: clade release book
638− q=path :: spur
639− r=* :: data
640− == ::
641−```
642−
643−This is the data at a particular node in the filesystem. `p.p` specifies
644−the type of data that was requested (and is produced). `q.p` gives the
645−specific version reported (since a range of versions may be requested in
646−a subscription). `r.p` is the desk. `q` is the path to the filesystem
647−node. `r` is the data itself (in the format specified by `p.p`).
648−
649−### `++nako`, subscription response data
650−
651−```
652− ++ nako $: gar=(map ,@ud tako) :: new ids
653− let=@ud :: next id
654− lar=(set yaki) :: new commits
655− bar=(set blob) :: new content
656− == ::
657−```
658−
659−This is the data that is produced by a request for a range of revisions
660−of a desk. This allows us to easily keep track of a remote repository --
661−all the new information we need is contained in the `nako`.
662−
663−`gar` is a map of the revisions in the range to the hash of the commit
664−at that revision. These hashes can be used with `hut:rang` to find the
665−commit itself.
666−
667−`let` is either the last revision number in the range or the most recent
668−revision number, whichever is smaller.
669−
670−`lar` is the set of new commits, and `bar` is the set of new content.
671−
672−## Public Interface
673−
674−As with all vanes, there are exactly two ways to interact with clay.
675−`%clay` exports a namespace accessible through `.^`, which is described
676−above under `++care`. The primary way of interacting with clay, though,
677−is by sending kisses and receiving gifts.
678−
679−```
680− ++ gift :: out result <-$
681− $% [%ergo p=@p q=@tas r=@ud] :: version update
682− [%note p=@tD q=tank] :: debug message
683− [%writ p=riot] :: response
684− == ::
685− ++ kiss :: in request ->$
686− $% [%info p=@p q=@tas r=nori] :: internal edit
687− [%ingo p=@p q=@tas r=nori] :: internal noun edit
688− [%init p=@p] :: report install
689− [%into p=@p q=@tas r=nori] :: external edit
690− [%invo p=@p q=@tas r=nori] :: external noun edit
691− [%merg p=@p q=@tas r=mizu] :: internal change
692− [%wart p=sock q=@tas r=path s=*] :: network request
693− [%warp p=sock q=riff] :: file request
694− == ::
695−```
696−
697−There are only a small number of possible kisses, so it behooves us to
698−describe each in detail.
699−
700−```
701− $% [%info p=@p q=@tas r=nori] :: internal edit
702−
703− [%into p=@p q=@tas r=nori] :: external edit
704−```
705−
706−These two kisses are nearly identical. At a high level, they apply
707−changes to the filesystem. Whenever we add, remove, or edit a file, one
708−of these cards is sent. The `p` is the ship whose filesystem we're
709−trying to change, the `q` is the desk we're changing, and the `r` is the
710−request change. For the format of the requested change, see the
711−documentation for `++nori` above.
712−
713−When a file is changed in the unix filesystem, vere will send a `%into`
714−kiss. This tells clay that the duct over which the kiss was sent is the
715−duct that unix is listening on for changes. From within Arvo, though, we
716−should never send a `%into` kiss. The `%info` kiss is exactly identical
717−except it does not reset the duct.
718−
719−```
720− [%ingo p=@p q=@tas r=nori] :: internal noun edit
721−
722− [%invo p=@p q=@tas r=nori] :: external noun edit
723−```
724−
725−These kisses are currently identical to `%info` and `%into`, though this
726−will not always be the case. The intent is for these kisses to allow
727−typed changes to clay so that we may store typed data. This is currently
728−unimplemented.
729−
730−```
731− [%init p=@p] :: report install
732−```
733−
734−Init is called when a ship is started on our pier. This simply creates a
735−default `room` to go into our `raft`. Essentially, this initializes the
736−filesystem for a ship.
737−
738−```
739− [%merg p=@p q=@tas r=mizu] :: internal change
740−```
741−
742−This is called to perform a merge. This is most visibly called by
743−:update to update the filesystem of the current ship to that of its
744−sein. The `p` and `q` are as in `%info`, and the `r` is the description
745−of the merge. See `++mizu` above.
746−
747−XX
748−`XX [%wake ~] :: timer activate XX`
749−XX\
750−XX This card is sent by unix at the time specified by `++doze`. This
751−time is XX usually the closest time specified in a subscription request.
752−When `%wake` is XX called, we update our subscribers if there have been
753−any changes.
754−
755−```
756− [%wart p=sock q=@tas r=path s=*] :: network request
757−```
758−
759−This is a request that has come across the network for a particular
760−file. When another ship asks for a file from us, that request comes to
761−us in the form of a `%wart` kiss. This is handled by trivially turning
762−it into a `%warp`.
763−
764−```
765− [%warp p=sock q=riff] :: file request
766−```
767−
768−This is a request for information about a particular desk. This is, in
769−its most general form, a subscription, though in many cases it is the
770−trivial case of a subscription -- a read. See `++riff` for the format of
771−the request.
772−
773−## Lifecycle of a Local Read
774−
775−There are two real types of interaction with a filesystem: you can read,
776−and you can write. We'll describe each process, detailing both the flow
777−of control followed by the kernel and the algorithms involved. The
778−simpler case is that of the read, so we'll begin with that.
779−
780−When a vane or an application wishes to read a file from the filesystem,
781−it sends a `%warp` kiss, as described above. Of course, you may request
782−a file on another ship and, being a global filesystem, clay will happily
783−produce it for you. That code pathway will be described in another
784−section; here, we will restrict ourselves to examining the case of a
785−read from a ship on our own pier.
786−
787−The kiss can request either a single version of a file node or a range
788−of versions of a desk. Here, we'll deal only with a request for a single
789−version.
790−
791−As in all vanes, a kiss enters clay via a call to `++call`. Scanning
792−through the arm, we quickly see where `%warp` is handled.
793−
794−```
795− ?: =(p.p.q.hic q.p.q.hic)
796− =+ une=(un p.p.q.hic now ruf)
797− =+ wex=(di:une p.q.q.hic)
798− =+ ^= wao
799− ?~ q.q.q.hic
800− (ease:wex hen)
801− (eave:wex hen u.q.q.q.hic)
802− =+ ^= woo
803− abet:wao
804− [-.woo abet:(pish:une p.q.q.hic +.woo ran.wao)]
805−```
806−
807−We're following the familar patern of producing a list of moves and an
808−updated state. In this case, the state is `++raft`.
809−
810−We first check to see if the sending and receiving ships are the same.
811−If they're not, then this is a request for data on another ship. We
812−describe that process later. Here, we discuss only the case of a local
813−read.
814−
815−At a high level, the call to `++un` sets up the core for the domestic
816−ship that contains the files we're looking for. The call to `++di` sets
817−up the core for the particular desk we're referring to.
818−
819−After this, we perform the actual request. If there is no rave in the
820−riff, then that means we are cancelling a request, so we call
821−`++ease:de`. Otherwise, we start a subscription with `++eave:de`. We
822−call `++abet:de` to resolve our various types of output into actual
823−moves. We produce the moves we found above and the `++un` core resolved
824−with `++pish:un` (putting the modified desk in the room) and `++abet:un`
825−(putting the modified room in the raft).
826−
827−Much of this is fairly straightforward, so we'll only describe `++ease`,
828−`++eave`, and `++abet:de`. Feel free to look up the code to the other
829−steps -- it should be easy to follow.
830−
831−Although it's called last, it's usually worth examining `++abet` first,
832−since it defines in what ways we can cause side effects. Let's do that,
833−and also a few of the lines at the beginning of `++de`.
834−
835−```
836− =| yel=(list ,[p=duct q=gift])
837− =| byn=(list ,[p=duct q=riot])
838− =| vag=(list ,[p=duct q=gift])
839− =| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]])
840− =| tag=(list ,[p=duct q=path c=note])
841− |%
842− ++ abet
843− ^- [(list move) rede]
844− :_ red
845− ;: weld
846− %+ turn (flop yel)
847− |=([a=duct b=gift] [hun %give b])
848− ::
849− %+ turn (flop byn)
850− |=([a=duct b=riot] [a %give [%writ b]])
851− ::
852− %+ turn (flop vag)
853− |=([a=duct b=gift] [a %give b])
854− ::
855− %+ turn (flop say)
856− |= [a=duct b=path c=ship d=[p=@ud q=riff]]
857− :- a
858− [%pass b %a %want [who c] [%q %re p.q.d (scot %ud p.d) ~] q.d]
859− ::
860− %+ turn (flop tag)
861− |=([a=duct b=path c=note] [a %pass b c])
862− ==
863−```
864−
865−This is very simple code. We see there are exactly five different kinds
866−of side effects we can generate.
867−
868−In `yel` we put gifts that we wish to be sent along the `hun:room` duct
869−to dill. See the documentation for `++room` above. This is how we
870−display messages to the terminal.
871−
872−In `byn` we put riots that we wish returned to subscribers. Recall that
873−a riot is a response to a subscription. These are returned to our
874−subscribers in the form of a `%writ` gift.
875−
876−In `vag` we put gifts along with the ducts on which to send them. This
877−allows us to produce arbitrary gifts, but in practice this is only used
878−to produce `%ergo` gifts.
879−
880−In `say` we put messages we wish to pass to ames. These messages are
881−used to request information from clay on other piers. We must provide
882−not only the duct and the request (the riff), but also the return path,
883−the other ship to talk to, and the sequence number of the request.
884−
885−In `tag` we put arbitrary notes we wish to pass to other vanes. For now,
886−the only notes we pass here are `%wait` and `%rest` to the timer vane.
887−
888−Now that we know what kinds of side effects we may have, we can jump
889−into the handling of requests.
890−
891−```
892− ++ ease :: release request
893− |= hen=duct
894− ^+ +>
895− ?~ ref +>
896− =+ rov=(~(got by qyx) hen)
897− =. qyx (~(del by qyx) hen)
898− (mabe rov (cury best hen))
899− =. qyx (~(del by qyx) hen)
900− |- ^+ +>+.$
901− =+ nux=(~(get by fod.u.ref) hen)
902− ?~ nux +>+.$
903− %= +>+.$
904− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
905− fod.u.ref (~(del by fod.u.ref) hen)
906− bom.u.ref (~(del by bom.u.ref) u.nux)
907− ==
908−```
909−
910−This is called when we're cancelling a subscription. For domestic desks,
911−`ref` is null, so we're going to cancel any timer we might have created.
912−We first delete the duct from our map of requests, and then we call
913−`++mabe` with `++best` to send a `%rest` kiss to the timer vane if we
914−have started a timer. We'll describe `++best` and `++mabe` momentarily.
915−
916−Although we said we're not going to talk about foreign requests yet,
917−it's easy to see that for foreign desks, we cancel any outstanding
918−requests for this duct and send a message over ames to the other ship
919−telling them to cancel the subscription.
920−
921−```
922− ++ best
923− |= [hen=duct tym=@da]
924− %_(+> tag :_(tag [hen /tyme %t %rest tym]))
925−```
926−
927−This simply pushes a `%rest` note onto `tag`, from where it will be
928−passed back to arvo to be handled. This cancels the timer at the given
929−duct (with the given time).
930−
931−```
932− ++ mabe :: maybe fire function
933− |* [rov=rove fun=$+(@da _+>.^$)]
934− ^+ +>.$
935− %- fall :_ +>.$
936− %- bind :_ fun
937− ^- (unit ,@da)
938− ?- -.rov
939− %&
940− ?. ?=(%da -.q.p.rov) ~
941− `p.q.p.rov
942− %|
943− =* mot p.rov
944− %+ hunt
945− ?. ?=(%da -.p.mot) ~
946− ?.((lth now p.p.mot) ~ [~ p.p.mot])
947− ?. ?=(%da -.q.mot) ~
948− ?.((lth now p.q.mot) [~ now] [~ p.q.mot])
949− ==
950−```
951−
952−This decides whether the given request can only be satsified in the
953−future. In that case, we call the given function with the time in the
954−future when we expect to have an update to give to this request. This is
955−called with `++best` to cancel timers and with `++bait` to start them.
956−
957−For single requests, we have a time if the request is for a particular
958−time (which is assumed to be in the future). For ranges of requests, we
959−check both the start and end cases to see if they are time cases. If so,
960−we choose the earlier time.
961−
962−If any of those give us a time, then we call the given funciton with the
963−smallest time.
964−
965−The more interesting case is, of course, when we're not cancelling a
966−subscription but starting one.
967−
968−```
969− ++ eave :: subscribe
970− |= [hen=duct rav=rave]
971− ^+ +>
972− ?- -.rav
973− &
974− ?: &(=(p.p.rav %u) !=(p.q.p.rav now))
975− ~& [%clay-fail p.q.p.rav %now now]
976− !!
977− =+ ver=(aver p.rav)
978− ?~ ver
979− (duce hen rav)
980− ?~ u.ver
981− (blub hen)
982− (blab hen p.rav u.u.ver)
983−```
984−
985−There are two types of subscriptions -- either we're requesting a single
986−file or we're requesting a range of versions of a desk. We'll dicuss the
987−simpler case first.
988−
989−First, we check that we're not requesting the `rang` from any time other
990−than the present. Since we don't store that information for any other
991−time, we can't produce it in a referentially transparent manner for any
992−time other than the present.
993−
994−Then, we try to read the requested `mood` `p.rav`. If we can't access
995−the request data right now, we call `++duce` to put the request in our
996−queue to be satisfied when the information becomes available.
997−
998−This case occurs when we make a request for a case whose (1) date is
999−after the current date, (2) number is after the current number, or (3)
1000−label is not yet used.
1001−
1002−```
1003− ++ duce :: produce request
1004− |= [hen=duct rov=rove]
1005− ^+ +>
1006− =. qyx (~(put by qyx) hen rov)
1007− ?~ ref
1008− (mabe rov (cury bait hen))
1009− |- ^+ +>+.$ :: XX why?
1010− =+ rav=(reve rov)
1011− =+ ^= vaw ^- rave
1012− ?. ?=([%& %v *] rav) rav
1013− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
1014− =+ inx=nix.u.ref
1015− %= +>+.$
1016− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
1017− nix.u.ref +(nix.u.ref)
1018− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
1019− fod.u.ref (~(put by fod.u.ref) hen inx)
1020− ==
1021−```
1022−
1023−The code for `++duce` is nearly the exact inverse of `++ease`, which in
1024−the case of a domestic desk is very simple -- we simply put the duct and
1025−rave into `qyx` and possibly start a timer with `++mabe` and `++bait`.
1026−Recall that `ref` is null for domestic desks and that `++mabe` fires the
1027−given function with the time we need to be woken up at, if we need to be
1028−woken up at a particular time.
1029−
1030−```
1031− ++ bait
1032− |= [hen=duct tym=@da]
1033− %_(+> tag :_(tag [hen /tyme %t %wait tym]))
1034−```
1035−
1036−This sets an alarm by sending a `%wait` card with the given time to the
1037−timer vane.
1038−
1039−Back in `++eave`, if `++aver` returned `[~ ~]`, then we cancel the
1040−subscription. This occurs when we make (1) a `%x` request for a file
1041−that does not exist, (2) a `%w` request with a case that is not a
1042−number, or (3) a `%w` request with a nonempty path. The `++blub` is
1043−exactly what you would expect it to be.
1044−
1045−```
1046− ++ blub :: ship stop
1047− |= hen=duct
1048− %_(+> byn [[hen ~] byn])
1049−```
1050−
1051−We notify the duct that we're cancelling their subscription since it
1052−isn't satisfiable.
1053−
1054−Otherwise, we have received the desired information, so we send it on to
1055−the subscriber with `++blab`.
1056−
1057−```
1058− ++ blab :: ship result
1059− |= [hen=duct mun=mood dat=*]
1060− ^+ +>
1061− +>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn])
1062−```
1063−
1064−The most interesting arm called in `++eave` is, of course, `++aver`,
1065−where we actually try to read the data.
1066−
1067−```
1068− ++ aver :: read
1069− |= mun=mood
1070− ^- (unit (unit ,*))
1071− ?: &(=(p.mun %u) !=(p.q.mun now)) :: prevent bad things
1072− ~& [%clay-fail p.q.mun %now now]
1073− !!
1074− =+ ezy=?~(ref ~ (~(get by haw.u.ref) mun))
1075− ?^ ezy ezy
1076− =+ nao=(~(case-to-aeon ze lim dom ran) q.mun)
1077− ?~(nao ~ [~ (~(read-at-aeon ze lim dom ran) u.nao mun)])
1078−```
1079−
1080−We check immediately that we're not requesting the `rang` for any time
1081−other than the present.
1082−
1083−If this is a foreign desk, then we check our cache for the specific
1084−request. If either this is a domestic desk or we don't have the request
1085−in our cache, then we have to actually go read the data from our dome.
1086−
1087−We need to do two things. First, we try to find the number of the commit
1088−specified by the given case, and then we try to get the data there.
1089−
1090−Here, we jump into `arvo/zuse.hoon`, which is where much of the
1091−algorithmic code is stored, as opposed to the clay interface, which is
1092−stored in `arvo/clay.hoon`. We examine `++case-to-aeon:ze`.
1093−
1094−```
1095− ++ case-to-aeon :: case-to-aeon:ze
1096− |= lok=case :: act count through
1097− ^- (unit aeon)
1098− ?- -.lok
1099− %da
1100− ?: (gth p.lok lim) ~
1101− |- ^- (unit aeon)
1102− ?: =(0 let) [~ 0] :: avoid underflow
1103− ?: %+ gte p.lok
1104− =< t
1105− %- tako-to-yaki
1106− %- aeon-to-tako
1107− let
1108− [~ let]
1109− $(let (dec let))
1110− ::
1111− %tas (~(get by lab) p.lok)
1112− %ud ?:((gth p.lok let) ~ [~ p.lok])
1113− ==
1114−```
1115−
1116−We handle each type of `case` differently. The latter two types are
1117−easy.
1118−
1119−If we're requesting a revision by label, then we simply look up the
1120−requested label in `lab` from the given dome. If it exists, that is our
1121−aeon; else we produce null, indicating the requested revision does not
1122−yet exist.
1123−
1124−If we're requesting a revision by number, we check if we've yet reached
1125−that number. If so, we produce the number; else we produce null.
1126−
1127−If we're requesting a revision by date, we check first if the date is in
1128−the future, returning null if so. Else we start from the most recent
1129−revision and scan backwards until we find the first revision committed
1130−before that date, and we produce that. If we requested a date before any
1131−revisions were committed, we produce `0`.
1132−
1133−The definitions of `++aeon-to-tako` and `++tako-to-yaki` are trivial.
1134−
1135−```
1136− ++ aeon-to-tako ~(got by hit)
1137−
1138− ++ tako-to-yaki ~(got by hut) :: grab yaki
1139−```
1140−
1141−We simply look up the aeon or tako in their respective maps (`hit` and
1142−`hut`).
1143−
1144−Assuming we got a valid version number, `++aver` calls
1145−`++read-at-aeon:ze`, which reads the requested data at the given
1146−revision.
1147−
1148−```
1149− ++ read-at-aeon :: read-at-aeon:ze
1150− |= [oan=aeon mun=mood] :: seek and read
1151− ^- (unit)
1152− ?: &(?=(%w p.mun) !?=(%ud -.q.mun)) :: NB only for speed
1153− ?^(r.mun ~ [~ oan])
1154− (read:(rewind oan) mun)
1155−```
1156−
1157−If we're requesting the revision number with a case other than by
1158−number, then we go ahead and just produce the number we were given.
1159−Otherwise, we call `++rewind` to rewind our state to the given revision,
1160−and then we call `++read` to get the requested information.
1161−
1162−```
1163− ++ rewind :: rewind:ze
1164− |= oan=aeon :: rewind to aeon
1165− ^+ +>
1166− ?: =(let oan) +>
1167− ?: (gth oan let) !! :: don't have version
1168− +>(ank (checkout-ankh q:(tako-to-yaki (aeon-to-tako oan))), let oan)
1169−```
1170−
1171−If we're already at the requested version, we do nothing. If we're
1172−requesting a version later than our head, we are unable to comply.
1173−
1174−Otherwise, we get the hash of the commit at the number, and from that we
1175−get the commit itself (the yaki), which has the map of path to lobe that
1176−represents a version of the filesystem. We call `++checkout-ankh` to
1177−checkout the commit, and we replace `ank` in our context with the
1178−result.
1179−
1180−```
1181− ++ checkout-ankh :: checkout-ankh:ze
1182− |= hat=(map path lobe) :: checkout commit
1183− ^- ankh
1184− %- cosh
1185− %+ roll (~(tap by hat) ~)
1186− |= [[pat=path bar=lobe] ank=ankh]
1187− ^- ankh
1188− %- cosh
1189− ?~ pat
1190− =+ zar=(lobe-to-noun bar)
1191− ank(q [~ (sham zar) zar])
1192− =+ nak=(~(get by r.ank) i.pat)
1193− %= ank
1194− r %+ ~(put by r.ank) i.pat
1195− $(pat t.pat, ank (fall nak _ankh))
1196− ==
1197−```
1198−
1199−Twice we call `++cosh`, which hashes a commit, updating `p` in an
1200−`ankh`. Let's jump into that algorithm before we describe
1201−`++checkout-ankh`.
1202−
1203−```
1204− ++ cosh :: locally rehash
1205− |= ank=ankh :: NB v/unix.c
1206− ank(p rehash:(zu ank))
1207−```
1208−
1209−We simply replace `p` in the hash with the `cash` we get from a call to
1210−`++rehash:zu`.
1211−
1212−```
1213− ++ zu !: :: filesystem
1214− |= ank=ankh :: filesystem state
1215− =| myz=(list ,[p=path q=miso]) :: changes in reverse
1216− =| ram=path :: reverse path into
1217− |%
1218− ++ rehash :: local rehash
1219− ^- cash
1220− %+ mix ?~(q.ank 0 p.u.q.ank)
1221− =+ axe=1
1222− |- ^- cash
1223− ?~ r.ank _@
1224− ;: mix
1225− (shaf %dash (mix axe (shaf %dush (mix p.n.r.ank p.q.n.r.ank))))
1226− $(r.ank l.r.ank, axe (peg axe 2))
1227− $(r.ank r.r.ank, axe (peg axe 3))
1228− ==
1229−```
1230−
1231−`++zu` is a core we set up with a particular filesystem node to traverse
1232−a checkout of the filesystem and access the actual data inside it. One
1233−of the things we can do with it is to create a recursive hash of the
1234−node.
1235−
1236−In `++rehash`, if this node is a file, then we xor the remainder of the
1237−hash with the hash of the contents of the file. The remainder of the
1238−hash is `0` if we have no children, else we descend into our children.
1239−Basically, we do a half SHA-256 of the xor of the axis of this child and
1240−the half SHA-256 of the xor of the name of the child and the hash of the
1241−child. This is done for each child and all the results are xored
1242−together.
1243−
1244−Now we return to our discussion of `++checkout-ankh`.
1245−
1246−We fold over every path in this version of the filesystem and create a
1247−great ankh out of them. First, we call `++lobe-to-noun` to get the raw
1248−data referred to be each lobe.
1249−
1250−```
1251− ++ lobe-to-noun :: grab blob
1252− |= p=lobe :: ^- *
1253− %- blob-to-noun
1254− (lobe-to-blob p)
1255−```
1256−
1257−This converts a lobe into the raw data it refers to by first getting the
1258−blob with `++lobe-to-blob` and converting that into data with
1259−`++blob-to-noun`.
1260−
1261−```
1262− ++ lobe-to-blob ~(got by lat) :: grab blob
1263−```
1264−
1265−This just grabs the blob that the lobe refers to.
1266−
1267−```
1268− ++ blob-to-noun :: grab blob
1269− |= p=blob
1270− ?- -.p
1271− %delta (lump r.p (lobe-to-noun q.p))
1272− %direct q.p
1273− %indirect q.p
1274− ==
1275−```
1276−
1277−If we have either a direct or an indirect blob, then the data is stored
1278−right in the blob. Otherwise, we have to reconstruct it from the diffs.
1279−We do this by calling `++lump` on the diff in the blob with the data
1280−obtained by recursively calling the parent of this blob.
1281−
1282−```
1283− ++ lump :: apply patch
1284− |= [don=udon src=*]
1285− ^- *
1286− ?+ p.don ~|(%unsupported !!)
1287− %a
1288− ?+ -.q.don ~|(%unsupported !!)
1289− %a q.q.don
1290− %c (lurk ((hard (list)) src) p.q.don)
1291− %d (lure src p.q.don)
1292− ==
1293− ::
1294− %c
1295− =+ dst=(lore ((hard ,@) src))
1296− %- roly
1297− ?+ -.q.don ~|(%unsupported !!)
1298− %a ((hard (list ,@t)) q.q.don)
1299− %c (lurk dst p.q.don)
1300− ==
1301− ==
1302−```
1303−
1304−This is defined in `arvo/hoon.hoon` for historical reasons which are
1305−likely no longer applicable. Since the `++umph` structure will likely
1306−change we convert clay to be a typed filesystem, we'll only give a
1307−high-level description of this process. If we have a `%a` udon, then
1308−we're performing a trivial replace, so we produce simply `q.q.don`. If
1309−we have a `%c` udon, then we're performing a list merge (as in, for
1310−example, lines of text). The merge is performed by `++lurk`.
1311−
1312−```
1313− ++ lurk :: apply list patch
1314− |* [hel=(list) rug=(urge)]
1315− ^+ hel
1316− =+ war=`_hel`~
1317− |- ^+ hel
1318− ?~ rug (flop war)
1319− ?- -.i.rug
1320− &
1321− %= $
1322− rug t.rug
1323− hel (slag p.i.rug hel)
1324− war (weld (flop (scag p.i.rug hel)) war)
1325− ==
1326− ::
1327− |
1328− %= $
1329− rug t.rug
1330− hel =+ gur=(flop p.i.rug)
1331− |- ^+ hel
1332− ?~ gur hel
1333− ?>(&(?=(^ hel) =(i.gur i.hel)) $(hel t.hel, gur t.gur))
1334− war (weld q.i.rug war)
1335− ==
1336− ==
1337−```
1338−
1339−We accumulate our final result in `war`. If there's nothing more in our
1340−list of merge instructions (unces), we just reverse `war` and produce
1341−it. Otherwise, we process another unce. If the unce is of type `&`, then
1342−we have `p.i.rug` lines of no changes, so we just copy them over from
1343−`hel` to `war`. If the unice is of type `|`, then we verify that the
1344−source lines (in `hel`) are what we expect them to be (`p.i.rug`),
1345−crashing on failure. If they're good, then we append the new lines in
1346−`q.i.rug` onto `war`.
1347−
1348−And that's really it. List merges are pretty easy. Anyway, if you
1349−recall, we were discussing `++checkout-ankh`.
1350−
1351−```
1352− ++ checkout-ankh :: checkout-ankh:ze
1353− |= hat=(map path lobe) :: checkout commit
1354− ^- ankh
1355− %- cosh
1356− %+ roll (~(tap by hat) ~)
1357− |= [[pat=path bar=lobe] ank=ankh]
1358− ^- ankh
1359− %- cosh
1360− ?~ pat
1361− =+ zar=(lobe-to-noun bar)
1362− ank(q [~ (sham zar) zar])
1363− =+ nak=(~(get by r.ank) i.pat)
1364− %= ank
1365− r %+ ~(put by r.ank) i.pat
1366− $(pat t.pat, ank (fall nak _ankh))
1367− ==
1368−```
1369−
1370−If the path is null, then we calculate `zar`, the raw data at the path
1371−`pat` in this version. We produce the given ankh with the correct data.
1372−
1373−Otherwise, we try to get the child we're looking at from our parent
1374−ankh. If it's already been created, this succeeds; otherwise, we simply
1375−create a default blank ankh. We place ourselves in our parent after
1376−recursively computing our children.
1377−
1378−This algorithm really isn't that complicated, but it may not be
1379−immediately obvious why it works. An example should clear everything up.
1380−
1381−Suppose `hat` is a map of the following information.
1382−
1383−```
1384− /greeting --> "customary upon meeting"
1385− /greeting/english --> "hello"
1386− /greeting/spanish --> "hola"
1387− /greeting/russian/short --> "привет"
1388− /greeting/russian/long --> "Здравствуйте"
1389− /farewell/russian --> "до свидания"
1390−```
1391−
1392−Furthermore, let's say that we process them in this order:
1393−
1394−```
1395− /greeting/english
1396− /greeting/russian/short
1397− /greeting/russian/long
1398− /greeting
1399− /greeting/spanish
1400− /farewell/russian
1401−```
1402−
1403−Then, the first path we process is `/greeting/english` . Since our path
1404−is not null, we try to get `nak`, but because our ankh is blank at this
1405−point it doesn't find anything. Thus, update our blank top-level ankh
1406−with a child `%greeting`. and recurse with the blank `nak` to create the
1407−ankh of the new child.
1408−
1409−In the recursion, we our path is `/english` and our ankh is again blank.
1410−We try to get the `english` child of our ankh, but this of course fails.
1411−Thus, we update our blank `/greeting` ankh with a child `english`
1412−produced by recursing.
1413−
1414−Now our path is null, so we call `++lobe-to-noun` to get the actual
1415−data, and we place it in the brand-new ankh.
1416−
1417−Next, we process `/greeting/russian/short`. Since our path is not null,
1418−we try to get the child named `%greeting`, which does exist since we
1419−created it earlier. We put modify this child by recursing on it. Our
1420−path is now `/russian/short`, so we look for a `%russian` child in our
1421−`/greeting` ankh. This doesn't exist, so we add it by recursing. Our
1422−path is now `/short`, so we look for a `%short` child in our
1423−`/greeting/russian` ankh. This doesn't exist, so we add it by recursing.
1424−Now our path is null, so we set the contents of this node to `"привет"`,
1425−and we're done processing this path.
1426−
1427−Next, we process `/greeting/russian/long`. This proceeds similarly to
1428−the previous except that now the ankh for `/greeting/russian` already
1429−exists, so we simply reuse it rather than creating a new one. Of course,
1430−we still must create a new `/greeting/russian/long` ankh.
1431−
1432−Next, we process `/greeting`. This ankh already exists, so after we've
1433−recursed once, our path is null, and our ankh is not blank -- it already
1434−has two children (and two grandchildren). We don't touch those, though,
1435−since a node may be both a file and a directory. We just add the
1436−contents of the file -- "customary upon meeting" -- to the existing
1437−ankh.
1438−
1439−Next, we process `/greeting/spanish`. Of course, the `/greeting` ankh
1440−already exists, but it doesn't have a `%spanish` child, so we create
1441−that, taking care not to disturb the contents of the `/greeting` file.
1442−We put "hola" into the ankh and call it good.
1443−
1444−Finally, we process `/farewell/russian`. Here, the `/farewell` ankh
1445−doesn't exist, so we create it. Clearly the newly-created ankh doesn't
1446−have any children, so we have to add a `%russian` child, and in this
1447−child we put our last content -- "до свидания".
1448−
1449−We hope it's fairly obvious that the order we process the paths doesn't
1450−affect the final ankh tree. The tree will be constructed in a very
1451−different order depending on what order the paths come in, but the
1452−resulting tree is independent of order.
1453−
1454−At any rate, we were talking about something important, weren't we? If
1455−you recall, that concludes our discussion of `++rewind`, which was
1456−called from `++read-at-aeon`. In summary, `++rewind` returns a context
1457−in which our current state is (very nearly) as it was when the specified
1458−version of the desk was the head. This allows `++read-at-aeon` to call
1459−`++read` to read the requested information.
1460−
1461−```
1462− ++ read :: read:ze
1463− |= mun=mood :: read at point
1464− ^- (unit)
1465− ?: ?=(%v p.mun)
1466− [~ `dome`+<+<.read]
1467− ?: &(?=(%w p.mun) !?=(%ud -.q.mun))
1468− ?^(r.mun ~ [~ let])
1469− ?: ?=(%w p.mun)
1470− =+ ^= yak
1471− %- tako-to-yaki
1472− %- aeon-to-tako
1473− let
1474− ?^(r.mun ~ [~ [t.yak (forge-nori yak)]])
1475− ::?> ?=(^ hit) ?^(r.mun ~ [~ i.hit]) :: what do?? need [@da nori]
1476− (query(ank ank:(descend-path:(zu ank) r.mun)) p.mun)
1477−```
1478−
1479−If we're requesting the dome, then we just return that immediately.
1480−
1481−If we're requesting the revision number of the desk and we're not
1482−requesting it by number, then we just return the current number of this
1483−desk. Note of course that this was really already handled in
1484−`++read-at-aeon`.
1485−
1486−If we're requesting a `%w` with a specific revision number, then we do
1487−something or other with the commit there. It's kind of weird, and it
1488−doesn't seem to work, so we'll ignore this case.
1489−
1490−Otherwise, we descend into the ankh tree to the given path with
1491−`++descend-path:zu`, and then we handle specific request in `++query`.
1492−
1493−```
1494− ++ descend-path :: descend recursively
1495− |= way=path
1496− ^+ +>
1497− ?~(way +> $(way t.way, +> (descend i.way)))
1498−```
1499−
1500−This is simple recursion down into the ankh tree. `++descend` descends
1501−one level, so this will eventually get us down to the path we want.
1502−
1503−```
1504− ++ descend :: descend
1505− |= lol=@ta
1506− ^+ +>
1507− =+ you=(~(get by r.ank) lol)
1508− +>.$(ram [lol ram], ank ?~(you [*cash ~ ~] u.you))
1509−```
1510−
1511−`ram` is the path that we're at, so to descend one level we push the
1512−name of this level onto that path. We update the ankh with the correct
1513−one at that path if it exists; else we create a blank one.
1514−
1515−Once we've decscended to the correct level, we need to actually deal
1516−with the request.
1517−
1518−```
1519− ++ query :: query:ze
1520− |= ren=?(%u %v %x %y %z) :: endpoint query
1521− ^- (unit ,*)
1522− ?- ren
1523− %u [~ `rang`+<+>.query]
1524− %v [~ `dome`+<+<.query]
1525− %x ?~(q.ank ~ [~ q.u.q.ank])
1526− %y [~ as-arch]
1527− %z [~ ank]
1528− ==
1529−```
1530−
1531−Now that everything's set up, it's really easy. If they're requesting
1532−the rang, dome, or ankh, we give it to them. If the contents of a file,
1533−we give it to them if it is in fact a file. If the `arch`, then we
1534−calculate it with `++as-arch`.
1535−
1536−```
1537− ++ as-arch :: as-arch:ze
1538− ^- arch :: arch report
1539− :+ p.ank
1540− ?~(q.ank ~ [~ p.u.q.ank])
1541− |- ^- (map ,@ta ,~)
1542− ?~ r.ank ~
1543− [[p.n.r.ank ~] $(r.ank l.r.ank) $(r.ank r.r.ank)]
1544−```
1545−
1546−This very simply strips out all the "real" data and returns just our own
1547−hash, the hash of the file contents (if we're a file), and a map of the
1548−names of our immediate children.
1549−
1550−## Lifecycle of a Local Subscription
1551−
1552−A subscription to a range of revisions of a desk initially follows the
1553−same path that a single read does. In `++aver`, we checked the head of
1554−the given rave. If the head was `&`, then it was a single request, so we
1555−handled it above. If `|`, then we handle it with the following code.
1556−
1557−```
1558− =+ nab=(~(case-to-aeon ze lim dom ran) p.p.rav)
1559− ?~ nab
1560− ?> =(~ (~(case-to-aeon ze lim dom ran) q.p.rav))
1561− (duce hen (rive rav))
1562− =+ huy=(~(case-to-aeon ze lim dom ran) q.p.rav)
1563− ?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab))))
1564− (blub hen)
1565− =+ top=?~(huy let.dom u.huy)
1566− =+ sar=(~(lobes-at-path ze lim dom ran) u.nab r.p.rav)
1567− =+ ear=(~(lobes-at-path ze lim dom ran) top r.p.rav)
1568− =. +>.$
1569− ?: =(sar ear) +>.$
1570− =+ fud=(~(make-nako ze lim dom ran) u.nab top)
1571− (bleb hen u.nab fud)
1572− ?^ huy
1573− (blub hen)
1574− =+ ^= ptr ^- case
1575− [%ud +(let.dom)]
1576− (duce hen `rove`[%| ptr q.p.rav r.p.rav ear])
1577− ==
1578−```
1579−
1580−Recall that `++case-to-aeon:ze` produces the revision number that a case
1581−corresponds to, if it corresponds to any. If it doesn't yet correspond
1582−to a revision, then it produces null.
1583−
1584−Thus, we first check to see if we've even gotten to the beginning of the
1585−range of revisions requested. If not, then we assert that we haven't yet
1586−gotten to the end of the range either, because that would be really
1587−strange. If not, then we immediately call `++duce`, which, if you
1588−recall, for a local request, simply puts this duct and rove into our
1589−cult `qyx`, so that we know who to respond to when the revision does
1590−appear.
1591−
1592−If we've already gotten to the first revision, then we can produce some
1593−content immediately. If we've also gotten to the final revision, and
1594−that revision is earlier than the start revision, then it's a bad
1595−request and we call `++blub`, which tells the subscriber that his
1596−subscription will not be satisfied.
1597−
1598−Otherwise, we find the data at the given path at the beginning of the
1599−subscription and at the last available revision in the subscription. If
1600−they're the same, then we don't send a notification. Otherwise, we call
1601−`++gack`, which creates the `++nako` we need to produce. We call
1602−`++bleb` to actually produce the information.
1603−
1604−If we already have the last requested revision, then we also tell the
1605−subscriber with `++blub` that the subscription will receive no further
1606−updates.
1607−
1608−If there will be more revisions in the subscription, then we call
1609−`++duce`, adding the duct to our subscribers. We modify the rove to
1610−start at the next revision since we've already handled all the revisions
1611−up to the present.
1612−
1613−We glossed over the calls to `++lobes-at-path`, `++make-nako`, and
1614−`++bleb`, so we'll get back to those right now. `++bleb` is simple, so
1615−we'll start with that.
1616−
1617−```
1618− ++ bleb :: ship sequence
1619− |= [hen=duct ins=@ud hip=nako]
1620− ^+ +>
1621− (blab hen [%w [%ud ins] ~] hip)
1622−```
1623−
1624−We're given a duct, the beginning revision number, and the nako that
1625−contains the updates since that revision. We use `++blab` to produce
1626−this result to the subscriber. The case is `%w` with a revision number
1627−of the beginning of the subscription, and the data is the nako itself.
1628−
1629−We call `++lobes-at-path:ze` to get the data at the particular path.
1630−
1631−```
1632− ++ lobes-at-path :: lobes-at-path:ze
1633− |= [oan=aeon pax=path] :: data at path
1634− ^- (map path lobe)
1635− ?: =(0 oan) ~
1636− %- mo
1637− %+ skim
1638− %. ~
1639− %~ tap by
1640− =< q
1641− %- tako-to-yaki
1642− %- aeon-to-tako
1643− oan
1644− |= [p=path q=lobe]
1645− ?| ?=(~ pax)
1646− ?& !?=(~ p)
1647− =(-.pax -.p)
1648− $(p +.p, pax +.pax)
1649− == ==
1650−```
1651−
1652−At revision zero, the theoretical common revision between all
1653−repositories, there is no data, so we produce null.
1654−
1655−We get the list of paths (paired with their lobe) in the revision
1656−referred to by the given number and we keep only those paths which begin
1657−with `pax`. Converting to a map, we now have a map from the subpaths at
1658−the given path to the hash of their data. This is simple and efficient
1659−to calculate and compare to later revisions. This allows us to easily
1660−tell if a node or its children have changed.
1661−
1662−Finally, we will describe `++make-nako:ze`.
1663−
1664−```
1665− ++ make-nako :: gack a through b
1666− |= [a=aeon b=aeon]
1667− ^- [(map aeon tako) aeon (set yaki) (set blob)]
1668− :_ :- b
1669− =- [(takos-to-yakis -<) (lobes-to-blobs ->)]
1670− %+ reachable-between-takos
1671− (~(get by hit) a) :: if a not found, a=0
1672− (aeon-to-tako b)
1673− ^- (map aeon tako)
1674− %- mo %+ skim (~(tap by hit) ~)
1675− |= [p=aeon *]
1676− &((gth p a) (lte p b))
1677−```
1678−
1679−We need to produce four things -- the numbers of the new commits, the
1680−number of the latest commit, the new commits themselves, and the new
1681−data itself.
1682−
1683−The first is fairly easy to produce. We simply go over our map of
1684−numbered commits and produce all those numbered greater than `a` and not
1685−greater than `b`.
1686−
1687−The second is even easier to produce -- `b` is clearly our most recent
1688−commit.
1689−
1690−The third and fourth are slightly more interesting, though not too
1691−terribly difficult. First, we call `++reachable-between-takos`.
1692−
1693−```
1694− ++ reachable-between-takos
1695− |= [a=(unit tako) b=tako] :: pack a through b
1696− ^- [(set tako) (set lobe)]
1697− =+ ^= sar
1698− ?~ a ~
1699− (reachable-takos r:(tako-to-yaki u.a))
1700− =+ yak=`yaki`(tako-to-yaki b)
1701− %+ new-lobes-takos (new-lobes ~ sar) :: get lobes
1702− |- ^- (set tako) :: walk onto sar
1703− ?: (~(has in sar) r.yak)
1704− ~
1705− =+ ber=`(set tako)`(~(put in `(set tako)`~) `tako`r.yak)
1706− %- ~(uni in ber)
1707− ^- (set tako)
1708− %+ roll p.yak
1709− |= [yek=tako bar=(set tako)]
1710− ^- (set tako)
1711− ?: (~(has in bar) yek) :: save some time
1712− bar
1713− %- ~(uni in bar)
1714− ^$(yak (tako-to-yaki yek))
1715−```
1716−
1717−We take a possible starting commit and a definite ending commit, and we
1718−produce the set of commits and the set of data between them.
1719−
1720−We let `sar` be the set of commits reachable from `a`. If `a` is null,
1721−then obviously no commits are reachable. Otherwise, we call
1722−`++reachable-takos` to calculate this.
1723−
1724−```
1725− ++ reachable-takos :: reachable
1726− |= p=tako :: XX slow
1727− ^- (set tako)
1728− =+ y=(tako-to-yaki p)
1729− =+ t=(~(put in _(set tako)) p)
1730− %+ roll p.y
1731− |= [q=tako s=_t]
1732− ?: (~(has in s) q) :: already done
1733− s :: hence skip
1734− (~(uni in s) ^$(p q)) :: otherwise traverse
1735−```
1736−
1737−We very simply produce the set of the given tako plus its parents,
1738−recursively.
1739−
1740−Back in `++reachable-between-takos`, we let `yak` be the yaki of `b`,
1741−the ending commit. With this, we create a set that is the union of `sar`
1742−and all takos reachable from `b`.
1743−
1744−We pass `sar` into `++new-lobes` to get all the lobes referenced by any
1745−tako referenced by `a`. The result is passed into `++new-lobes-takos` to
1746−do the same, but not recomputing those in already calculated last
1747−sentence. This produces the sets of takos and lobes we need.
1748−
1749−```
1750− ++ new-lobes :: object hash set
1751− |= [b=(set lobe) a=(set tako)] :: that aren't in b
1752− ^- (set lobe)
1753− %+ roll (~(tap in a) ~)
1754− |= [tak=tako bar=(set lobe)]
1755− ^- (set lobe)
1756− =+ yak=(tako-to-yaki tak)
1757− %+ roll (~(tap by q.yak) ~)
1758− |= [[path lob=lobe] far=_bar]
1759− ^- (set lobe)
1760− ?~ (~(has in b) lob) :: don't need
1761− far
1762− =+ gar=(lobe-to-blob lob)
1763− ?- -.gar
1764− %direct (~(put in far) lob)
1765− %delta (~(put in $(lob q.gar)) lob)
1766− %indirect (~(put in $(lob s.gar)) lob)
1767− ==
1768−```
1769−
1770−Here, we're creating a set of lobes referenced in a commit in `a`. We
1771−start out with `b` as the initial set of lobes, so we don't need to
1772−recompute any of the lobes referenced in there.
1773−
1774−The algorithm is pretty simple, so we won't bore you with the details.
1775−We simply traverse every commit in `a`, looking at every blob referenced
1776−there, and, if it's not already in `b`, we add it to `b`. In the case of
1777−a direct blob, we're done. For a delta or an indirect blob, we
1778−recursively add every blob referenced within the blob.
1779−
1780−```
1781− ++ new-lobes-takos :: garg & repack
1782− |= [b=(set lobe) a=(set tako)]
1783− ^- [(set tako) (set lobe)]
1784− [a (new-lobes b a)]
1785−```
1786−
1787−Here, we just update the set of lobes we're given with the commits we're
1788−given and produce both sets.
1789−
1790−This concludes our discussion of a local subscription.
1791−
1792−## Lifecycle of a Foreign Read or Subscription
1793−
1794−Foreign reads and subscriptions are handled in much the same way as
1795−local ones. The interface is the same -- a vane or app sends a `%warp`
1796−kiss with the request. The difference is simply that the `sock` refers
1797−to the foreign ship.
1798−
1799−Thus, we start in the same place -- in `++call`, handling `%warp`.
1800−However, since the two side of the `sock` are different, we follow a
1801−different path.
1802−
1803−```
1804− =+ wex=(do now p.q.hic p.q.q.hic ruf)
1805− =+ ^= woo
1806− ?~ q.q.q.hic
1807− abet:(ease:wex hen)
1808− abet:(eave:wex hen u.q.q.q.hic)
1809− [-.woo (posh q.p.q.hic p.q.q.hic +.woo ruf)]
1810−```
1811−
1812−If we compare this to how the local case was handled, we see that it's
1813−not all that different. We use `++do` rather than `++un` and `++de` to
1814−set up the core for the foreign ship. This gives us a `++de` core, so we
1815−either cancel or begin the request by calling `++ease` or `++eave`,
1816−exactly as in the local case. In either case, we call `++abet:de` to
1817−resolve our various types of output into actual moves, as described in
1818−the local case. Finally, we call `++posh` to update our raft, putting
1819−the modified rung into the raft.
1820−
1821−We'll first trace through `++do`.
1822−
1823−```
1824− ++ do
1825− |= [now=@da [who=ship him=ship] syd=@tas ruf=raft]
1826− =+ ^= rug ^- rung
1827− =+ rug=(~(get by hoy.ruf) him)
1828− ?^(rug u.rug *rung)
1829− =+ ^= red ^- rede
1830− =+ yit=(~(get by rus.rug) syd)
1831− ?^(yit u.yit `rede`[~2000.1.1 ~ [~ *rind] *dome])
1832− ((de now ~ ~) [who him] syd red ran.ruf)
1833−```
1834−
1835−If we already have a rung for this foreign ship, then we use that.
1836−Otherwise, we create a new blank one. If we already have a rede in this
1837−rung, then we use that, otherwise we create a blank one. An important
1838−point to note here is that we let `ref` in the rede be `[~ *rind]`.
1839−Recall, for domestic desks `ref` is null. We use this to distinguish
1840−between foreign and domestic desks in `++de`.
1841−
1842−With this information, we create a `++de` core as usual.
1843−
1844−Although we've already covered `++ease` and `++eave`, we'll go through
1845−them quickly again, highlighting the case of foreign request.
1846−
1847−```
1848− ++ ease :: release request
1849− |= hen=duct
1850− ^+ +>
1851− ?~ ref +>
1852− =+ rov=(~(got by qyx) hen)
1853− =. qyx (~(del by qyx) hen)
1854− (mabe rov (cury best hen))
1855− =. qyx (~(del by qyx) hen)
1856− |- ^+ +>+.$
1857− =+ nux=(~(get by fod.u.ref) hen)
1858− ?~ nux +>+.$
1859− %= +>+.$
1860− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
1861− fod.u.ref (~(del by fod.u.ref) hen)
1862− bom.u.ref (~(del by bom.u.ref) u.nux)
1863− ==
1864−```
1865−
1866−Here, we still remove the duct from our cult (we maintain a cult even
1867−for foreign desks), but we also need to tell the foreign desk to cancel
1868−our subscription. We do this by sending a request (by appending to
1869−`say`, which gets resolved in `++abet:de` to a `%want` kiss to ames) to
1870−the foreign ship to cancel the subscription. Since we don't anymore
1871−expect a response on this duct, we remove it from `fod` and `bom`, which
1872−are the maps between ducts, raves, and request sequence numbers.
1873−Basically, we remove every trace of the subscription from our request
1874−manager.
1875−
1876−In the case of `++eave`, where we're creating a new request, everything
1877−is exactly identical to the case of the local request except `++duce`.
1878−We said that `++duce` simply puts the request into our cult. This is
1879−true for a domestic request, but distinctly untrue for foreign requests.
1880−
1881−```
1882− ++ duce :: produce request
1883− |= [hen=duct rov=rove]
1884− ^+ +>
1885− =. qyx (~(put by qyx) hen rov)
1886− ?~ ref +>.$
1887− |- ^+ +>+.$ :: XX why?
1888− =+ rav=(reve rov)
1889− =+ ^= vaw ^- rave
1890− ?. ?=([%& %v *] rav) rav
1891− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
1892− =+ inx=nix.u.ref
1893− %= +>+.$
1894− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
1895− nix.u.ref +(nix.u.ref)
1896− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
1897− fod.u.ref (~(put by fod.u.ref) hen inx)
1898− ==
1899−```
1900−
1901−If we have a request manager (i.e. this is a foreign desk), then we do
1902−the approximate inverse of `++ease`. We create a rave out of the given
1903−request and send it off to the foreign desk by putting it in `say`. Note
1904−that the rave is created to request the information starting at the next
1905−revision number. Since this is a new request, we put it into `fod` and
1906−`bom` to associate the request with its duct and its sequence number.
1907−Since we're using another sequence number, we must increment `nix`,
1908−which represents the next available sequence number.
1909−
1910−And that's really it for this side of the request. Requesting foreign
1911−information isn't that hard. Let's see what it looks like on the other
1912−side. When we get a request from another ship for information on our
1913−ship, that comes to us in the form of a `%wart` from ames.
1914−
1915−We handle a `%wart` in `++call`, right next to where we handle the
1916−`%warp` case.
1917−
1918−```
1919− %wart
1920− ?> ?=(%re q.q.hic)
1921− =+ ryf=((hard riff) s.q.hic)
1922− :_ ..^$
1923− :~ :- hen
1924− :^ %pass [(scot %p p.p.q.hic) (scot %p q.p.q.hic) r.q.hic]
1925− %c
1926− [%warp [p.p.q.hic p.p.q.hic] ryf]
1927− ==
1928−```
1929−
1930−Every request we receive should be of type `riff`, so we coerce it into
1931−that type. We just convert this into a new `%warp` kiss that we pass to
1932−ourself. This gets handled like normal, as a local request. When the
1933−request produces a value, it does so like normal as a `%writ`, which is
1934−returned to `++take` along the path we just sent it on.
1935−
1936−```
1937− %writ
1938− ?> ?=([@ @ *] tea)
1939− =+ our=(need (slaw %p i.tea))
1940− =+ him=(need (slaw %p i.t.tea))
1941− :_ ..^$
1942− :~ :- hen
1943− [%pass ~ %a [%want [our him] [%r %re %c t.t.tea] p.+.q.hin]]
1944− ==
1945−```
1946−
1947−Since we encoded the ship we need to respond to in the path, we can just
1948−pass our `%want` back to ames, so that we tell the requesting ship about
1949−the new data.
1950−
1951−This comes back to the original ship as a `%waft` from ames, which comes
1952−into `++take`, right next to where we handled `%writ`.
1953−
1954−```
1955− %waft
1956− ?> ?=([@ @ ~] tea)
1957− =+ syd=(need (slaw %tas i.tea))
1958− =+ inx=(need (slaw %ud i.t.tea))
1959− =+ ^= zat
1960− =< wake
1961− (knit:(do now p.+.q.hin syd ruf) [inx ((hard riot) q.+.q.hin)])
1962− =^ mos ruf
1963− =+ zot=abet.zat
1964− [-.zot (posh q.p.+.q.hin syd +.zot ruf)]
1965− [mos ..^$(ran.ruf ran.zat)] :: merge in new obj
1966−```
1967−
1968−This gets the desk and sequence number from the path the request was
1969−sent over. This determines exactly which request is being responded to.
1970−We call `++knit:de` to apply the changes to our local desk, and we call
1971−`++wake` to update our subscribers. Then we call `++abet:de` and
1972−`++posh` as normal (like in `++eave`).
1973−
1974−We'll examine `++knit` and `++wake`, in that order.
1975−
1976−```
1977− ++ knit :: external change
1978− |= [inx=@ud rot=riot]
1979− ^+ +>
1980− ?> ?=(^ ref)
1981− |- ^+ +>+.$
1982− =+ ruv=(~(get by bom.u.ref) inx)
1983− ?~ ruv +>+.$
1984− => ?. |(?=(~ rot) ?=(& -.q.u.ruv)) .
1985− %_ .
1986− bom.u.ref (~(del by bom.u.ref) inx)
1987− fod.u.ref (~(del by fod.u.ref) p.u.ruv)
1988− ==
1989− ?~ rot
1990− =+ rav=`rave`q.u.ruv
1991− %= +>+.$
1992− lim
1993− ?.(&(?=(| -.rav) ?=(%da -.q.p.rav)) lim `@da`p.q.p.rav)
1994− ::
1995− haw.u.ref
1996− ?. ?=(& -.rav) haw.u.ref
1997− (~(put by haw.u.ref) p.rav ~)
1998− ==
1999− ?< ?=(%v p.p.u.rot)
2000− =. haw.u.ref
2001− (~(put by haw.u.ref) [p.p.u.rot q.p.u.rot q.u.rot] ~ r.u.rot)
2002− ?. ?=(%w p.p.u.rot) +>+.$
2003− |- ^+ +>+.^$
2004− =+ nez=[%w [%ud let.dom] ~]
2005− =+ nex=(~(get by haw.u.ref) nez)
2006− ?~ nex +>+.^$
2007− ?~ u.nex +>+.^$ :: should never happen
2008− =. +>+.^$ =+ roo=(edis ((hard nako) u.u.nex))
2009− ?>(?=(^ ref.roo) roo)
2010− %= $
2011− haw.u.ref (~(del by haw.u.ref) nez)
2012− ==
2013−```
2014−
2015−This is kind of a long gate, but don't worry, it's not bad at all.
2016−
2017−First, we assert that we're not a domestic desk. That wouldn't make any
2018−sense at all.
2019−
2020−Since we have the sequence number of the request, we can get the duct
2021−and rave from `bom` in our request manager. If we didn't actually
2022−request this data (or the request was canceled before we got it), then
2023−we do nothing.
2024−
2025−Else, we remove the request from `bom` and `fod` unless this was a
2026−subscription request and we didn't receive a null riot (which would
2027−indicate the last message on the subscription).
2028−
2029−Now, if we received a null riot, then if this was a subscription request
2030−by date, then we update `lim` in our request manager (representing the
2031−latest time at which we have complete information for this desk) to the
2032−date that was requested. If this was a single read request, then we put
2033−the result in our simple cache `haw` to make future requests faster.
2034−Then we're done.
2035−
2036−If we received actual data, then we put it into our cache `haw`. Unless
2037−it's a `%w` request, we're done.
2038−
2039−If it is a `%w` request, then we try to get the `%w` at our current head
2040−from the cache. In general, that should be the thing we just put in a
2041−moment ago, but that is not guaranteed. The most common case where this
2042−is different is when we receive desk updates out of order. At any rate,
2043−since we now have new information, we need to apply it to our local copy
2044−of the desk. We do so in `++edis`, and then we remove the stuff we just
2045−applied from the cache, since it's not really a true "single read", like
2046−what should really be in the cache.
2047−
2048−```
2049− ++ edis :: apply subscription
2050− |= nak=nako
2051− ^+ +>
2052− %= +>
2053− hit.dom (~(uni by hit.dom) gar.nak)
2054− let.dom let.nak
2055− lat.ran %+ roll (~(tap in bar.nak) ~)
2056− =< .(yeb lat.ran)
2057− |= [sar=blob yeb=(map lobe blob)]
2058− =+ zax=(blob-to-lobe sar)
2059− %+ ~(put by yeb) zax sar
2060− hut.ran %+ roll (~(tap in lar.nak) ~)
2061− =< .(yeb hut.ran)
2062− |= [sar=yaki yeb=(map tako yaki)]
2063− %+ ~(put by yeb) r.sar sar
2064− ==
2065−```
2066−
2067−This shows, of course, exactly why nako is defined the way it is. To
2068−become completely up to date with the foreign desk, we need to merge
2069−`hit` with the foreign one so that we have all the revision numbers. We
2070−update `let` so that we know which revision is the head.
2071−
2072−We merge the new blobs in `lat`, keying them by their hash, which we get
2073−from a call to `++blob-to-lobe`. Recall that the hash is stored in the
2074−actual blob itself. We do the same thing to the new yakis, putting them
2075−in `hut`, keyed by their hash.
2076−
2077−Now, our local dome should be exactly the same as the foreign one.
2078−
2079−This concludes our discussion of `++knit`. Now the changes have been
2080−applied to our local copy of the desk, and we just need to update our
2081−subscribers. We do so in `++wake:de`.
2082−
2083−```
2084− ++ wake :: update subscribers
2085− ^+ .
2086− =+ xiq=(~(tap by qyx) ~)
2087− =| xaq=(list ,[p=duct q=rove])
2088− |- ^+ ..wake
2089− ?~ xiq
2090− ..wake(qyx (~(gas by *cult) xaq))
2091− ?- -.q.i.xiq
2092− &
2093− =+ cas=?~(ref ~ (~(get by haw.u.ref) `mood`p.q.i.xiq))
2094− ?^ cas
2095− %= $
2096− xiq t.xiq
2097− ..wake ?~ u.cas (blub p.i.xiq)
2098− (blab p.i.xiq p.q.i.xiq u.u.cas)
2099− ==
2100− =+ nao=(~(case-to-aeon ze lim dom ran) q.p.q.i.xiq)
2101− ?~ nao $(xiq t.xiq, xaq [i.xiq xaq])
2102− $(xiq t.xiq, ..wake (balk p.i.xiq u.nao p.q.i.xiq))
2103− ::
2104− |
2105− =+ mot=`moot`p.q.i.xiq
2106− =+ nab=(~(case-to-aeon ze lim dom ran) p.mot)
2107− ?~ nab
2108− $(xiq t.xiq, xaq [i.xiq xaq])
2109− =+ huy=(~(case-to-aeon ze lim dom ran) q.mot)
2110− ?~ huy
2111− =+ ptr=[%ud +(let.dom)]
2112− %= $
2113− xiq t.xiq
2114− xaq [[p.i.xiq [%| ptr q.mot r.mot s.mot]] xaq]
2115− ..wake =+ ^= ear
2116− (~(lobes-at-path ze lim dom ran) let.dom r.p.q.i.xiq)
2117− ?: =(s.p.q.i.xiq ear) ..wake
2118− =+ fud=(~(make-nako ze lim dom ran) u.nab let.dom)
2119− (bleb p.i.xiq let.dom fud)
2120− ==
2121− %= $
2122− xiq t.xiq
2123− ..wake =- (blub:- p.i.xiq)
2124− =+ ^= ear
2125− (~(lobes-at-path ze lim dom ran) u.huy r.p.q.i.xiq)
2126− ?: =(s.p.q.i.xiq ear) (blub p.i.xiq)
2127− =+ fud=(~(make-nako ze lim dom ran) u.nab u.huy)
2128− (bleb p.i.xiq +(u.nab) fud)
2129− ==
2130− ==
2131− --
2132−```
2133−
2134−This is even longer than `++knit`, but it's pretty similar to `++eave`.
2135−We loop through each of our subscribers `xiq`, processing each in turn.
2136−When we're done, we just put the remaining subscribers back in our
2137−subscriber list.
2138−
2139−If the subscriber is a single read, then, if this is a foreign desk
2140−(note that `++wake` is called from other arms, and not only on foreign
2141−desks). Obviously, if we find an identical request there, then we can
2142−produce the result immediately. Referential transparency for the win. We
2143−produce the result with a call to `++blab`. If this is a foreign desk
2144−but the result is not in the cache, then we produce `++blub` (canceled
2145−subscription with no data) for reasons entirely opaque to me. Seriously,
2146−it seems like we should wait until we get an actual response to the
2147−request. If someone figures out why this is, let me know. At any rate,
2148−it seems to work.
2149−
2150−If this is a domestic desk, then we check to see if the case exists yet.
2151−If it doesn't, then we simply move on to the next subscriber, consing
2152−this one onto `xaq` so that we can check again the next time around. If
2153−it does exist, then we call `++balk` to fulfill the request and produce
2154−it.
2155−
2156−`++balk` is very simple, so we'll describe it here before we get to the
2157−subscription case.
2158−
2159−```
2160− ++ balk :: read and send
2161− |= [hen=duct oan=@ud mun=mood]
2162− ^+ +>
2163− =+ vid=(~(read-at-aeon ze lim dom ran) oan mun)
2164− ?~ vid (blub hen) (blab hen mun u.vid)
2165−```
2166−
2167−We call `++read-at-aeon` on the given request and aeon. If you recall,
2168−this processes a `mood` at a particular aeon and produces the result, if
2169−there is one. If there is data at the requested location, then we
2170−produce it with `++blab`. Else, we call `++blub` to notify the
2171−subscriber that no data can ever come over this subscriptioin since it
2172−is now impossible for there to ever be data for the given request.
2173−Because referential transparency.
2174−
2175−At any rate, back to `++wake`. If the given rave is a subscription
2176−request, then we proceed similarly to how we do in `++eave`. We first
2177−try to get the aeon referred to by the starting case. If it doesn't
2178−exist yet, then we can't do anything interesting with this subscription,
2179−so we move on to the next one.
2180−
2181−Otherwise, we try to get the aeon referred to by the ending case. If it
2182−doesn't exist yet, then we produce all the information we can. We call
2183−`++lobes-at-path` at the given aeon and path to see if the requested
2184−path has actually changed. If it hasn't, then we don't produce anything;
2185−else, we produce the correct nako by calling `++bleb` on the result of
2186−`++make-nako`, as in `++eave`. At any rate, we move on to the next
2187−subscription, putting back into our cult the current subscription with a
2188−new start case of the next aeon after the present.
2189−
2190−If the aeon referred to by the ending case does exist, then we drop this
2191−subscriber from our cult and satisfy its request immediately. This is
2192−the same as before -- we check to see if the data at the path has
2193−actually changed, producing it if it has; else, we call `++blub` since
2194−no more data can be produced over this subscription.
2195−
2196−This concludes our discussion of foreign requests.
learn/arvo/arvo-internals/eyre.udon+717−1
@@ -21,4 +21,720 @@ essentially stateless, like functional publishing with `%ford`.
2121Additionally, there's a fairly significant component that handles
2222`%gall` messaging and subscriptions, which must be stateful.
2323
24−;list;
24+;=
25+ ;h2
26+ ;div(id "reference"): Reference
27+ ==
28+==
29+
30+### State
31+
32+Stored
33+
34+- `++bolo`
35+- `++cyst`
36+- `++stem`
37+
38+Runtime
39+
40+- `perk`
41+ + `perk-auth`
42+- `pest`
43+- `even`
44+
45+### Cores
46+
47+- `++handle`
48+ + `++parse`
49+ - `++as...`
50+- `++ya`
51+- `++ix`
52+
53+;=
54+ ;h2
55+ ;div(id "commentary"): Commentary
56+ ==
57+==
58+
59+
60+Let us follow the loading of a simple cli app, as it bounces from
61+browser to server to browser and back.
62+
63+### Initial request ;a(id "init");
64+
65+An http request for `http://sampel-sipnym.urbit.org/cli` will be [redirected](dns)
66+to the `%eyre` on ~sampel-sipnym, and come in as a `%this` kiss.
67+
68+From arvo, requests enter `++call`, which after some type reification are passed
69+along to `++apex:ye`. In the case of a `%this` kiss, its components are
70+parsed(see `++zest:epur`, `++eat-headers`) and handed off to `++handle`, wrapped
71+in `++emule` to produce a `++fail` page in case of error. `++apex:handle` will
72+`++process` the request to a `pest` or a `++done` core, and in the former case
73+`++resolve` the pest into an outgoing card.
74+
75+XX it also seems to affect the current ship, test that serving ship name is consistently correct
76+
77+The pest is produced by `++process`, which will first further `++parse` the
78+request, and if this does not make the response immediately obvious,
79+`++process-parsed` the resulting `perk`.
80+
81+`++parse` produces the `perk`, by attempting to interpret the `pork`(url path)
82+[`++as-magic-filename`](#mage), `++as-beam`, and `++as-aux-request`. In this
83+case, `/cli` is parsed by the second case as a `%beam` query to `/=cli=`: a path
84+which starts with a valid ship name is expected to be a full clay(well, ford)
85+path, and one starting with a term implies the current serving ship and a case
86+of `0`, the current revision.
87+
88+XX spur: when the desks are merged, `/cli` shall point to `/=main=/pub/cli`
89+
90+The parsed `perk` generates a `%f %boil` note, `mark`ed as its extension(here
91+defaulting to `%urb`) and `wire`d with `~` to return unaltered to the client. It
92+goes on to `++resolve` by being passed to `++ford-get-beam`, which translates
93+the perk it into a `%boil` `++ford-req`, adding an `++fcgi` path-segment
94+containing query string and `++fcgi-cred:for-client` auth information.
95+
96+`%ford`s translation of `/=cli=/hymn/hook` to a self-refreshing `%urb` html page
97+[deserves its own commentary](/docs/learn/arvo/arvo-internals/ford#commentary), but
98+we resume in `%eyre` when the `%made` sign arrives in `++take`, and soon after
99+`++axon:ye`. There the `wire`, or rather the `whir` it has been verified to be,
100+determines that the response should be served immediately. However, as the mark
101+is not `%mime`, another trip to `%ford` is required to encode it, on the same
102+wire; afterwards, the value of the `%mime` cage is verified to be of the correct type, and finally
103+delivered back up the requesting duct as a successful `%thou` HTTP response.
104+
105+XX `%cast %mime` used to be in ford-get-beam, is there a reason it was removed?
106+
107+## Back into the breach, or: auxilary requests
108+
109+Now, it was mentioned that this result is self-refreshing: the `%urb`
110+translation door injects a `;script@"/~/on/{deps}.js"` into every page, `deps`
111+is a ford-readable hash of the set of resources that page construction depended
112+on.
113+
114+This triggers another `%this` request. Its handling is identical to that of
115+`/cli` up until `++parse`, where it is seen not `++as-beam` but
116+`++as-aux-request`(auxillary requests starting with `/~/` or `/~~/`).
117+`/on/[hash]` is a long-`%poll`, which `++process-parsed`, for a `.js` mark,
118+answers with a direct `%js`. Its contents are the static `++poll:js`, which
119+initiates the long-polling loop, run against an injected `urb.js` of
120+`{poll:[hash]}`.
121+
122+A `%js` `pest` is `resolve`d as a `text/javascript` success `%this`.
123+
124+When `poll.js` is received by the client, it opens an `XMLHttpRequest` for
125+`/~/on/{window.urb.poll}.json`, bringing us back to `%poll:process`.
126+
127+In the case of a non-`%js` `/~/on/`, `%poll:process-parsed` turns into a
128+`++new-dependency`, which stores the listening duct, and `pass-note`s a `%wasp`
129+with the deps-hash back to `%ford` whence it came. While this occured, the page
130+has loaded.
131+
132+Some indeterminate amount of time afterwards, with dropped `/~/on/{...}.json`s
133+being retried upon expiring and also being stored, a `%news` sign arrives in
134+`++axon`, and the hash in question is retrieved from the wire, and the listening
135+long-polls retrieved by the hash. Each receives a 205 "Reload parent view" HTTP
136+response, which `poll.js` dutifully executes, and a fixed typo of markdown is
137+rendered.
138+
139+## Authentication
140+
141+Now, while this accurately reflects the presentation of e.g. a markdown file,
142+`/cli` is an application front-end, and one that permits only owner access. Its
143+second script is `@"/~~/~/at/main/lib/urb.js"`, semantically equivalent to
144+`/~/as/own/~/at/main/lib/urb.js`, and handled as follows.
145+
146+In `++as-aux-request`, `%as %own` becomes `%auth %get our` perk, which
147+`++process` passes to `++process-parsed` passes to `++process-auth`. There, a
148+`yac` "ya" core is built `++for-client`: a `++cookie-prefix`, which is just the
149+serving ship name, is used to get a `++session-from-cookies`, here nil as the
150+client has no cookie set. In lieu of a cookie, a `++new-ya` is constructed, with
151+a random token `hole` and a `++new-cyst` which fills out `cyst` session state
152+from request data.
153+
154+Returning to `++process-auth`, `%get` checks if the yac is authenticated with
155+the requested credentials(`anon` requests are always granted), which for the
156+fresh new `cyst` is not the case (more on success [later](#auth-ok)). Unless
157+authentiacting as a [foreign ship](#xeno), the only thing left is to
158+`++show-login-page`, which detects that the requested resource is not `%html`,
159+and produces a `%red` pest. For `%js`, `%red`irections `++resolve` to
160+`++auth-redir:js`, a line of javascript which prepends `/~~` to the url path.
161+
162+The owner-authenticated main page request similarly ends in `++show-login-page`,
163+which for the empty session is an `[%htme ++login-page:xml]`, `resolve`d to
164+`++give-html` with a 401 "unathorized".
165+
166+The login page shows a simple prompt, and requests `/~/at/auth.js` to handle the
167+submission. And so we are, once again, attempting to divine if what we're doing
168+makes sense `++as-aux-request`.
169+
170+To understand `/~/at`, there will first be a brief diversion to `~/auth.json`.
171+`auth.json`, perk `[%auth %json]`, in `++process-auth` serves `++stat-json:ya`,
172+containing such information as the serving ship, which identities are associated
173+with this session, and `oryx`, a CSRF token. An oryx must be present on all
174+stateful requests, in this case executing a log in. It also saves the new/old
175+session using `abet`.
176+
177+XX explain `ixor` here and not [later](#ixor)?
178+
179+`/~/at` is an alternate interface, which injects `auth.json` data into the
180+requested file. `/~/at/auth.js`, then, is a request for the built-in `auth:js`
181+(parsed to and processed from an `[%auth %js ~]` perk), with session data added
182+as `window.urb`. And indeed, ``[`%js /~/at/auth]`` is parsed to
183+``[%auth at [`%js /auth]``, which in `++process-auth` is re-`process`ed to
184+`[%js ++auth:js]`, which is `++resolve`d after an `++add-json` of
185+the relevant data. The yac cookies are also passed to `resolve`, which
186+`++add-cookies` injects into the `httr`.
187+
188+It is at this point that there is first occasion for user input, namely the password.
189+
190+The `auth:js` script sends a `PUT` request, also to `/~/auth.json`. In `parse`,
191+the first nontrivial `++check-oryx` occurs, `++grab-body` the request oryx and
192+ensuring it is recorded for the session. The request parsed with `++need-body`
193+to a `[%auth %try {password}]` perk. `%get:process-auth` checks it against
194+`++load-secret`, upon success updates the session with `++logon:ya`, and
195+serves a fresh `auth.json` which reflects the changed `user`. Upon receiving
196+this, the page is refreshed to retry the original request.
197+
198+### Post-authentication: app communication. <a id="auth-ok"/>
199+
200+Upon refresh, `/~~/cli` brings us for the third time to `%get:process-auth`, but
201+this time the cookie is set, and the `yac` fetched contains the serving ship as
202+authenticated. The `++handle` sample is updated to reflect the requesting ship,
203+and the `process` continues for the rest of the pork, once again serving the
204+ford page.
205+
206+The `/~/on/[deps].json` poll starts anew, and `/~~/~/at/main/lib/urb.js` we now
207+know to serve the window.urb necessary to make requests, and the `urb.js`
208+standard library which extends it with a number of wrappers to them and other
209+useful functions.
210+
211+One of those functions is `urb.bind`, which is used to subscribe to application
212+data. Userspace javascript sets `urb.appl` to `/tic`, and binds `lines` to a
213+`;pre;` text display, using a callback.
214+
215+This triggers a `PUT` to `/~/is/{ixor}/cli/lines.json`, where `ixor` is a hash
216+of `oryx` that identifies the connection. `++as-aux-request`, an `%is` is a
217+`%subs` subscription update update, which for `%put` forwards to
218+`++add-subs:ix`, the ix core fetched `++for-view` by hashing the request
219+`++oryx-to-ixor`.
220+
221+<a id="ixor"/> A view has all the state associated with a client that must be
222+remembered between events. In this case, this is what app/path the request duct
223+is associated with; but mainly, `++add-subs:ix` will `pass-note` to `%gall` so
224+it `%show`s the data on the path, current and future.
225+
226+This will immediately(assuming the ship is local) result in a `%nice` by the
227+`/cli` app, returning `{ok:true}` `++nice-json` to `urb.bind`'s second callback
228+as `{ok:true}`. The initial `%rush` results also arrive, and in `++axon` are
229+converted to json using `++back`(ford `%cast` wrapper), and when `%made` get
230+passed to `++get-rush:ix`. There the source application/path are decoded by
231+duct, and then the full event goes to `++get-even`; `++add-even` inserts it to
232+the queue, and as there is no long poll it simply stays there.
233+
234+Upon receipt, the client realizes the long-poll isn't actually running, so that
235+is started using `urb.poll`. At `/~/of/{ixor}`, perk
236+`[%view ixor ~ {sequence-number}]`, it is `process`ed by `++poll:ix` (the cyst
237+is retrieved by `++ire-ix` form global state, using the perk `ixor`): the
238+sequence number is in the past, so the previously received `%rush` is
239+`++give-even`. After deleting the previous message in the queue and invoking
240+`++pass-took` to signal `%gall` of this occurrence, the data is annotated with
241+the source app+path `++subs-to-json`, and returned to the polling duct.
242+
243+On the client, the user callback receives the `/cli` history, and displays it on
244+the page. The `/~/of` long poll is continued, this time reaching `++poll:ix`
245+with the "pending" sequence number, and being stored in the `cyst` for its troubles.
246+
247+Its next update proceeds idenitcally, but first it must be triggered, which
248+happens when the user enters "(add 2 2)\n", firing an `urb.send` from the event
249+handler. This sends a `POST` request to `/~/to/cli/json.json`, perk `%mess`,
250+`++process`ed to a `%g %mess`. Were the mark not `%json`, a `%ford` conversion
251+would occur first, and `%made:axon` would send the gall message proper. In
252+either case, eventually a `%mean` or `%nice` arrives, is encoded as json, and
253+sent to the client callback.
254+
255+## A path not taken: magic filenames <a id="mage"/>
256+
257+The `/robots.txt` and `/favicon.(ico|png)` files are static, and served
258+immediately when caught by a `++parse`.
259+
260+XX index.html?
261+
262+## A path not taken: foreign auth <a id="xeno"/>
263+
264+While this example details a login `/~/as/own`, it is possible to be
265+authenticated as any ship on the network. A request for such seen in
266+`%get:process-auth` is passed to `++foreign-auth:ya`, which sends an
267+`%ames /lon` message to the ship in question. The foreign ship stores the
268+inquiry, calculates(the local) `++our-host` and responds with a `/hat`,
269+containing the redirection host, which is stored by `++foreign-hat`; it is later
270+used to send the client to a `/~/am` url on the foreign client, which acts as a
271+normal login page but later sends the client back. XX expand, basically the
272+status quo is you're logged in and `/~/as/foo` is ignored, just setting your
273+`urb.user` XX
274+
275+
276+### A path not taken: deauthentication
277+
278+`/~/away`, perk `[%away ~]`, produces a static `++logout-page:xml`, which also
279+uses `/~/at/auth.js`, to send a `DELETE /~/auth.json`, perk `[%auth %del]`. This
280+executes `++logoff:ya` for the cookie session, resolving to `++abut` to wipe it
281+from memory.
282+
283+### A path not taken: unsubscription
284+
285+`DELETE /~/is/app/path/within` works much like `PUT /~/is/app/path/within`,
286+`++del-subs:ix` acting as reverse of `++add-subs` by deleting the duct binding
287+and sending `%g %nuke`.
288+
289+
290+XX unmentioned arms: abet, add-poll, adit, ames-gram, anon, ares-to-json, bolo, cyst, doze, even, ford-kill, get-mean, gift, give-json, give-thou, gram, hapt, hasp, host-to-ship, ix, ixor, js, kiss, load, mean-json, move, note, pass-note, perk, perk-auth, pest, poke-test, print-subs, render-tang, resp, root-beak, scry, ses-authed, ses-ya, sign, silk, sine, stay, stem, teba, titl, to-oryx, urb, wait-era, wake, whir, wush, xml, ya, ye
291+
292+### Appendix A: DNS <a id="dns"/>
293+
294+The `*.urbit.org` domain can be used to access destroyers and cruisers. In the
295+common case oh hosted ships, this is done by dynamic DNS directly to the hosting
296+instance. We do not speak of the uncommon case. When ports are blocked and
297+infrastructure crumbles around you, only imported martian networking can be
298+trusted: the `%get` and `%got` [gram]()s are used to proxy [`%this` requests]() and
299+[`%thou` responses]() respectively.
300+
301+;=
302+ ;h2
303+ ;div(id "specification"): Specification
304+ ==
305+==
306+
307+The `%eyre` vane serves one purpose: receiving inbound HTTP requests from browsers and clients pretending to be browsers. To facilitate this communication, `%eyre` does two things: 1. provide an API for traditional clients to talk to; and 2. provide a mechanism for saving state that allows the server to keep track of identities/sessions, subscription data, and active connections.
308+
309+This document outlines the following:
310+
311+1. [`perk`](#perk), a `pork` subset that defines what URLs the client can send to `%eyre`.
312+
313+2. [the values stored on the client](#client), both statically in cookies and dynamically as the `window.urb` object, which facilitate this transaction.
314+
315+3. [`kiss`](#kiss), the requests `%eyre` will accept.
316+
317+4. [`gift`](#gift), the responses it will give to those requests.
318+
319+5. [`note`](#note), the set of arvo requests that %eyre makes to the other vanes.
320+
321+6. [`whir`](#whir), a `wire` subset, the associated dynamic state
322+
323+7. [`sign`](#sign), the responses `%eyre` accepts
324+
325+8. [`bolo`](#bolo), the state stored between separate events.
326+
327+## 1. URL structure
328+
329+There exist several URL forms accepted by `%eyre`.
330+
331+### 1.1 Functional request
332+
333+The simplest of them is a static `%f` functional publish request:
334+
335+```
336+ GET /[ship]/[desk]/[case]/path/to/file.[mark]
337+```
338+e.g.
339+
340+```
341+ /~pittyp-pittyp/main/5/lib/urb.js
342+```
343+A `case` of 0 signifies the most recent version.
344+
345+If no file extension is provided, the default `mark` is `%urb`, which consists of `%html` injected with an auto-refresh script.
346+
347+A shorter form:
348+
349+```
350+ /path/to.[mark]
351+```
352+is prepended with the [default request path](#prefix). For example, if `%eyre`
353+is configured with a root of `/<our>/main/0/pub`, then `/doc/arvo` is
354+interpreted as a request for `/=main=/pub/doc/arvo.urb`.
355+
356+Auxiliary paths start with `/~/`, and provide other functionality, such as:
357+
358+### 1.2 Auto-reload
359+
360+When a new version of a page becomes available, it is useful to propagate it to the client. The `%f` vane manages the particulars, and provides an update token along with all published pages. The `/~/on` long-polling endpoint makes use of that token, which is a hash of the server-stored dependency set.
361+- `/~/on/[hash].json` retuns `true` when a page may require updating.
362+- `/~/on/[hash].js` is a lightweight script that polls for the above. It is primarily used in error messages.
363+
364+;a(id "auth");
365+## 1.3 Authentication
366+
367+Authenticated requests are accomplished through sessions, tracked with cookies which are set on the first such request.
368+- `/~/as/[user]/...` is an authenticated request to `...`, where `user` can be a `@p` ship, `'own'`, `'any'`, or `'anon'`.
369+ + `'anon'` is a randomly-generated per-session submarine, and requires no further authentication.
370+ + `'own'` represents the serving ship. The short form of `/~/as/own/` is `/~~/`
371+ + `'any'` requires a network ship, chosen with a prompt if unknown. The short form of `/~/as/any/` is `/_/`
372+ + Auth requests are handled in three ways:
373+ + I. If the session is associated with the `ship`, serve `...`, storing the ship as the session's default ship. For example, `/~/as/sivtyv-barnel/main/pub/test.html` is an authenticated request of `/main/pub/test.html` with the identity of `~sivtyv-barnel`.
374+ + II. If the session is not associated with the `ship` in the path, the client is redirected to a login page, where a password can be entered. Successful authentication results in a page refresh to the requested path.
375+ + III. otherwise, [send a message](#foreign) to the claimed ship, and redirect the user to `https://[foreign-host]/~/am/[ses]/...#[current-host]&?code=[code]`
376+- `/~/am/[ses]/...#original-host` similarly serves a login page. Upon success, inform the `ship` of the success and redirect it back to `http://[original-host]/~/as/<this-ship>/...`
377+- `/~/away.html` is a log-out page.
378+- `/~/auth.json` returns `{ship,oryx,user,auth}`: the serving ship, a CSRF token, active user, and all allowed users respectively.
379+- `/~/at/{...}.js` is an alternate form of `/~/auth.json`, which injects a line into the served js file that sets `{ship, oryx, user, auth}` on the `window.urb` object.
380+
381+So far, all the paths specified have been GET requests. Authentication, however, requires sending data. This is also done at the `/~/auth.json` endpoint.
382+- `POST {oryx,ship,code} /~/auth.json?PUT` is used by the login script to authorize a user, and returns the same result as `GET`, additionally containing either`{ok:true}` or `{fail:'type',mess:"Error message"}`
383+- `POST {oryx,ship?} /~/auth.json?DELETE` revokes authorization. Response as above.
384+
385+### 1.4 Messaging
386+
387+- `POST {oryx, wire, xyro} /~/to/[app]/[mark].json`, where `xyro` is data that will be converted to the `mark`. In the simplest case, `/~/to/hello/json.json` will pass `xyro` through verbatim, sending `[%json xyro]` to the `++poke` arm of app `%hello`.
388+- `POST {oryx, wire, xyro} /~/to/<ship>/[app]/[mark].json` is a foreign message send, as above.
389+
390+;a(id "subs");
391+### 1.5 Subscriptions
392+
393+;a(id "of-ixor");
394+
395+- `/~/of/[ixor]` is an `EventSource`: a conceptually infinite file containing a stream of events. By default, it sends a newline every 30 seconds serving to signal that the connection is alive to both the server and IP middleware.
396+ + `/~/of/[ixor]?poll={n}` is a long-polling fallback interface. Produces event number `{n}`, blocking until it occurs. Its contexts can be affected by `POST` requests with a body of `{oryx, wire}`, and a query string of `PUT` or `DELETE`. They return either `{mark}`(which may be `null`), or [`{fail, mess}`](#mean-json)
397+- `/~/in/[hash].json` is a dual to [`/~/on`](#on-change). It binds `mod` events, which echo the requesting token.
398+- `/~/is/[app]/path/to.[mark]` binds `rush` events, formatted with a first line of `[app] /path/to`, and the rest containing subscription data. Additionally, `mean` events formatted similarly may arrive, also converted to the relevant mark.
399+
400+
401+
402+;a(id "temp");
403+### 1.6 Ablative
404+
405+These interfaces will temporarily exist to aid development, and are to be considered unstable.
406+- `/~/debug/...` access normally inaccessible pages. For example, `/~/debug/as.html` will present the login page, regardless of current session status.
407+
408+
409+## 2. Client state ;a(id "client");
410+
411+Some information is stored on, and provided to, browser clients
412+
413+### 2.1 Cookies
414+
415+Authenticated users receive a cookie on the domain of `*.urbit.org`. The cookie contains a client session token, keyed by the serving ship.
416+
417+### 2.2 Authentication ;a(id "auth-json");
418+
419+It is common(e.g. by the `%urb` mark) to set window.urb to the contents of `/~/auth.json`:
420+- `ship` is the serving ship
421+- `oryx` is a unique CSRF token that identifies this view, bound to the session cookie
422+- `ixor` is a hash of `oryx`, used as an insecure view identifier
423+- `user` is the authenticated/generated ship name
424+- `auth` is a list of identities usable by this session
425+
426+### 2.3 Client library
427+
428+To this object, `/main/lib/urb.js` adds helpers:
429+- `app` is an optional app name to send messages to by default
430+- `send({data,mark?='json',app?=urb.app,ship?}, cb?)` delivers messages
431+- `bind({path,app?=urb.app}, cb)` subscribes by path
432+- `drop({path,app?=urb.app}, cb?)` pulls the subscription
433+- `util` is an object containing methods for converting between JavaScript types and Hoon atom odors.
434+
435+## 3. Requests ;a(id "kiss");
436+
437+## `[%born port=@ud]`, unix init
438+
439+When the `vere` process is re/started, a TCP port is bound, HTTP requests on which are the scope of this document. The `%born` gift informs eyre of this occurrence, which in turn updates [its state.](#bolo)
440+
441+*Gifts given in response:* none.
442+
443+## `[%hiss p=mark q=cage]`, outbound http
444+
445+Userspace http request, converted by `%ford` into an actual `hiss`.
446+
447+*Gifts given in response:* a [`%sigh`]()
448+
449+### 3.1 `[%this httq]`, inbound http
450+
451+The primary `%eyre` request type comes from the host system, and constitutes an inbound http request. It consists of five parts:
452+
453+I. `p=[? @if]`: a loobean determining whether the request is being made over https, and the client source, an IPv6 address possibly encoding an IPv4 one as `.0.0.0.0.0.ffff.wwxx.yyzz`
454+
455+II. `q=meth`, an http method
456+
457+III. `r=@t`, the unparsed URL
458+
459+IV. `s=mess`, an associative list of header keys/values
460+
461+V. `t=(unit octs)`, the request body, if any.
462+
463+After `r` is parsed to a `purl`, the `pork`(relative path) determines the resource being served. The first step in handling an http request is [classifying its intent](#perk).
464+
465+- A ford request results in a [`%boil` note](#boil).
466+- `/~/[name].js` is generated from [session](#sink) or [view](#stem) state, and [served](#mime) as `%js`.
467+- `/~/am` generates a login page.
468+- `/~/as` is resolved further if authenticated, generates a similar login page if the claimed ship is local, and otherwise is saved to [session state](#sink) and sends a ["login" `%a` message](#lon) to the foreign ship.
469+- `/~/at` and `/~/auth.json` generate a new `oryx` and store it in the [session state](#sink).
470+- `/~/in` and `/~/is` affect [view state](#stem), possibly sending subscriptions or unsubscriptions to `%f` and `%g` respectively, and are generated from view state.
471+- `/~/on` is saved to the `bolo` by `hash`, and translated to a [`%wasp` note](#wasp).
472+- `/~/of` fails if the `ixor` is unknown, and otherwise is stored in the `ixor`, receiving a partial response and all events after its [last-seen header](#). If it has a `poll` parameter, the response is full, and only occurs if the body is non-empty. Otherwise the oryx is saved as a [live](#live) request in case of cancellation.
473+- `/~/to` transforms into a [`%g` message](#mess).
474+
475+*Gifts given in response:* a [`%thou`](), or a [`%that`](#that) followed by multiple [`%thar`]()s.
476+
477+### 3.2 `[%thud ~]`, inbound close
478+
479+Sent when an unresponded-to request is cancelled. The [live](#live) effect of the request is looked up, and
480+- `%exec` ford boil requests are cancelled with `[%exec ~]`
481+- `%wasp` ford deps requests are cancelled with `[%wasp |]`
482+- `%poll` session polls `%rest` the session heartbeat timeout
483+
484+### 3.3 `[%thin p=@ud]`, delivery failure
485+
486+Sent when a partial [response](#that) or [body](#thar) fails to arrive. Its `duct` is the same as that of the original request. This is handled by [waiting](#wait) for the client to reconnect, and if this not occur, unwinding all subscription state.
487+
488+
489+*Gifts given in response:* None.
490+
491+### 3.4 ``[%wart sock [path *]]``, inbound message
492+
493+Sometimes, messages are received from other ships. They are expected to take the from of a [`gram`]().
494+
495+*Gifts given in response:* [`%nice` or `%mean`](#ack).
496+
497+#### 3.4.1 `gram` <a id="gram"/>
498+
499+There are three messages of note, all concerning authentication <a id="foreign"/>
500+- `[/lon ses]` <a id="lon"/> is a login request, which contains the session wishing to authenticate.
501+- if the session is already authorized, a reply of `[/aut ses]` from (%eyre on) a foreign ship prescribes that the session is henceforth allowed to act on its behalf. All waiting `/~/as` are resolved as successful.
502+- otherwise, `[/hat ses hart]` contains the ship's preferred hostname. This can then be used to redirect the client. All waiting `/~/as` are given `307 Redirect`s to `/~/am` on the provided host.
503+
504+*Gifts given in response:* nice?
505+
506+## 4. Responses ;a(id "gift");
507+
508+### 4.1 `[%nice ~]`, `[%mean ares]`, network acknowledgement ;a(id "ack");
509+
510+A `%nice` is given upon receiving an [ames message](#gram), indicating succesful receipt. `%mean` is currently unused directly, but reserved for error conditions.
511+
512+## `[%sigh p=cage]`, inbound http response
513+
514+An HTTP response gets converted to the requested mark, or `%tang` in case of error.
515+
516+### 4.2 `[%thou httr]`, full HTTP response
517+
518+Most requests are served with one coherent response, consisting of
519+- `p=@ud`, an HTTP status code
520+- `q=mess`, response headers
521+- `r=(unit octs)`, an optional body
522+
523+### 4.3 `[%that httr]`, partial HTTP response ;a(id "that");
524+
525+[EventStream responses](#of-ixor) consist of multiple sequential chunks. Treated as `%thou`, except the request is kept open.
526+
527+### 4.4 `[%thar (unit octs)]`, partial HTTP body ;a(id "thar");
528+
529+Complementing `%that`, `%thar` is a body chunk, containing an event. An empty `%thar` signals for the connection to be closed.
530+
531+Body chunks, besides `[1 '\0a']`(a heartbeat newline), are encoded from `even` events. The stem becomes the [`event` field](#eventsource), and the content, `data` lines.
532+
533+#### 4.4.1 `even`, event types ;a(id "even");
534+
535+There are three events that a [client subscription](#subs) will be given.
536+
537+- `[%news hash]`;a(id "even-news"); is a `%f` update, and contains the relevant dependency token.
538+- `[%rush [term path] wain]` ;a(id "even-rush"); is sourced subscription data.
539+- `[%mean [term path] ares]` is a sourced subscription error.
540+
541+## 5. Vane requests ;a(id "note");
542+
543+### 5.1 ``[%a %wont sock `[path *]`gram]``, outbound message
544+
545+The `%a` interface provides conveyance of [messages](#gram) over UDP.
546+
547+Signs a `%woot` upon message arrival.
548+
549+### 5.2 `[%b ?(%wait %rest) time]`, timeout set/unset ;a(id "wait");
550+
551+All open [subscriptions](#of-ixor) require a "heartbeat" newline every `~s30`. When this fails to arrive, a complementary timer is set for `~m1`, after which the client is considered to have departed.
552+The `%b` timer interface is used to schedule the next such event, or cancel past scheduled ones when a connection closes.
553+
554+Signs a `%wake` upon timer activation.
555+
556+### 5.3 `[%f %wasp @uvI]`, dependency listen ;a(id "wasp");
557+
558+Knowledge of filesystem changes, requested by `/~/on` and `/~/in`, is requested the `%wasp` note. It contains the hash token which identifies a set of dependencies to query. Saved as a (live[live](#live)#live] request in case of cancellation when caused by `/~/on`.
559+
560+Signs a `%writ` upon change.
561+
562+### 5.4 `[%f %exec (unit silk)]`, functional transformations
563+
564+The `%f` interface converts nouns from one form to another. An empty unit represents cancellation.
565+
566+Signs a `%made` containing the computation result.
567+
568+The `silk`s used are as follows:
569+
570+### `[%cast %mime %boil mark beam [%web span ~]]`, file load
571+
572+The simplest functional request is the construction of a page. Saved as a [live](#live) request in case of cancellation.
573+- The `mark` is the request extension, defaulting to `%html`.
574+- A `beam`(path in `%clay`) is decoded from the request path.
575+- A `/web/<nyp ced quy>` virtual path is appended, span-encoding method, auth, and query string.
576+
577+### `[%cast mark %done ~ cage]`, convert ;a(id "done");
578+
579+This is used when communicating with apps, in both directions.
580+- Client messages are encoded as JSON objects, but can contain many different marks. Ones sent to non-`json.json` endpoints are `%cast` to he relevant mark, with a `cage` of `[%json p:!>(*json) jon]`, prior to being sent onwards to applications with `[%g %mess]`.
581+- Subscription responses also come in arbitrary marks, but are required to be sent as whichever mark an endpoint is subscribed to. They get `%cast` prior to being sent back as a `%that` EventSource segment.
582+
583+### 5.5 `%g`, app actions
584+
585+The end goal of many a userspace `hymn.hook` is to provide UI for a `%gall` app. To accommodate this, various functionality needs to be interfaced with.
586+
587+### `[%mess hapt ship cage]`, app message ;a(id "mess");
588+
589+After a `/~/to` POST has been received, and possibly converted to the correct mark, it is sent to `%g` for processing. The `hapt` is the destination, the `ship` is the source, the `cage` is the marked message data.
590+
591+Signs a `%nice` or `%mean`, in userspace or upon crashing.
592+
593+### `[%show hapt ship path]`, app subscription ;a(id "show");
594+
595+An `/~/is` PUT, if not already registered, results in a new subscription. A request for such contains the destination `hapt`, requesting `ship`, and app-internal `path`.
596+
597+Signs a `%nice` on init, `%rush` on data, and a `%mean` in subscription termination.
598+
599+### `[%took hapt ship]`, %rush confirmation
600+
601+A `%took` must be sent to acknowledge the receipt of subscription data, which in this case occurs automatically.
602+
603+Causes no signs.
604+
605+### `[%nuke hapt $|(ship [ship path])]`, subscription cancel
606+
607+An `/~/is` DELETE is used to remove a subscription, and is converted straightforwardly to a `%nuke`. Additionally, when a client disconnects, all of its subscriptions are `%nuke`d to reflect their expiration.
608+
609+Signs an empty `%mean` for each open subscription that is closed.
610+
611+## 6. In-flight metadata ;a(id "whir");
612+
613+Various state can be associated with requests, but not necessarily be returned in responses to them.
614+
615+### 6.1 `~`, dropthrough ;a(id "wire-drop");
616+
617+If the response should be sent statelessly further up the duct, the `wire` is empty. This is used in `%f` pure functional page generation.
618+
619+### 6.2 `[?(%y %n) ...]`, stability ;a(id "wire-live");
620+
621+The first element of a [`%b` timer](#wait) path distinguishes between live(%y) and dying(%n) channels.
622+
623+### 6.3 `/of/[ixor]`, view
624+
625+Designates which stream to act upon. Present on `%b` timer cards.
626+
627+### 6.4 `/on/<deps>`
628+
629+Present on `%f` dependency news. Looked up in [the state](#bolo) to see if any response is necessary.
630+
631+### 6.5 `/to/<hasp>/<ship>`, app ;a(id "wire-to");
632+
633+Present on `%f` translations of message marks
634+
635+### 6.6 `/is/[ixor]/{hasp path}`, subscription ;a(id "wire-is");
636+
637+Subscription requests. Present on `%g` subscription requests, and `%f` translations of [`%rush` subscription data](#show).
638+
639+## 7. Vane responses ;a(id "sign");
640+
641+The goal of requests is to cause some manner of result. Specifically,
642+
643+### 7.1 `[%a %woot ship coop]`, acknowledgement
644+
645+A [message](#mess) which has been acknowledged remotely.
646+
647+### 7.2 `[%b %wake ~]`, timer
648+
649+Timer activate. If this is a `%y` [timer](#wire-live), send a newline to each `/~/of/[oryx]`; if `%n` and the `oryx` still has no listeners, wipe its state/subscriptions.
650+
651+### 7.3 `[%f %news ~]`, dependency update
652+
653+This message signifies a `hash` has changed, and listeners to it should be updated. Results in [`%news` events](#even-news) to concerned streams, and [full responses](#thou) to relevant long-polls.
654+
655+### 7.4 `[%f %made (each bead (list tank))]`, compute result
656+
657+Further action depends on the [`wire`](#whir). It can:
658+- Be empty, designating direct request data, which is [served](#mime) back up the `duct`.
659+- Contain [app and requester identities](#wire-to), which designates an app message has been converted to the correct `mark`, and can now be [sent to the app](#mess) with an empty `wire`.
660+- Contain an `oryx`, app, and `path`, designating subscription data. If the subscription is active in the relevant `stem`, it is acknowledged with a `%took` and given as a [`%rush` event](#even-rush) to all listeners. Otherwise, the subscription is `%nuke`d.
661+
662+### 7.5 `%g`, applications
663+
664+The `%g` interface sends several responses.
665+
666+### `[%nice ~]` and `[%mean ares]`, acknowledgment
667+
668+These are given as a response to `%mess`, with an empty wire, and `%show`s, with a [subscription wire](#wire-is).
669+The former is [served](#mime) back to the requester(i.e. the remaining duct), and the latter returned to the client.
670+
671+#### 7.5 `[%rush cage]`, subscription data
672+
673+A `%rush` arrives on a [subscription wire](#wire-is), and is then sent [for conversion](#done) to the correct mark. An unexpected `%rush` is `%nuke`d.
674+
675+## 8. Server state ;a(id "bolo");
676+
677+There is a quantity of data that persists between events.
678+
679+### 8.1 Global
680+
681+- `path` ;a(id "prefix"); the default path which is prepended to relative plain requests. Initialized to `/<our>`, the serving ship; this interprets the first element of requests as a desk, and injects a `case` of `0`.
682+- `(jar ship hart)` remembered hostnames in order of preference, made accessible through `.^`
683+ + The default values(for self) are `http://<ship>.urbit.org:80` if not on a fake network, followed by `https://0.0.0.0:[port]`.
684+- `(jug deps (each duct oryx))`, `/~/on` and `/~/in` endpoints listening to `%c` updates.
685+- `(map duct live)`, inbound request state
686+- `(map ixor oryx)`, open `/~/of` streams.
687+- `(map oryx stem)`, open view state.
688+- `(map hole sink)`, session state.
689+- `(map hole ,[ship ?])`, foreign session names, along with their origin ships and whether they are authorized to act on our behalf.
690+
691+### 8.2 `live`, per-request state ;a(id "live");
692+
693+To honor request cancellations, each unserved request must track which effect it is causing.
694++ `[%exec whir]` if it is a ford data request
695++ `[%wasp (list @uvH)]` if it is a ford dependency poll
696++ `[%xeno ship]` if this is a proxied request
697++ `[%poll ixor]` if this is a session long-poll
698+
699+### 8.3 `sink`, per-session state ;a(id "sink");
700+
701+Each `hole` has associated authentication state.
702+- `priv`, a random secret that verifies the session, stored in cookie.
703+- `[ship (set ship)]`, the `ship` a session is acting as and any others it has been authorized with.
704+- `(jug ship ,[path duct])`, authentication `/~/as` requests waiting on foreign ships.
705+- `(set oryx)`, views associated with this session. Dual of `hole` in `stem`.
706+
707+### 8.4 `stem`, per-view state ;a(id "stem");
708+
709+Each `oryx` has active subscription state.
710+- `hole`, session in which this view resides. Dual of `(set oryx)` in `sink`.
711+- `ixor` ;a(id "ixor"); , a cached hash of the `oryx` that is used as a subscription id, by the `/~/of` EventStream.
712+- `[,@u (map ,@u even)]`, queued [events](#even). Has a maximum size.
713+- `(unit ,[duct @u ?])`, http connection, its last received event, and whether it is a long-poll request.
714+- `(set deps)`, subscribed `/~/in` points. Mirrored in `bolo`.
715+- `(map ,[hasp path] mark)`, subscribed `/~/is` points
716+- `(que duct)`, where any `%nice`/`%mean
717+
718+## Appendix A: Glossary
719+
720+- An `oryx` is a CSRF token used for [authenticated requests](#auth)
721+- `mean.json` ;a(id "mean-json"); is a rendering of hoon `ares`: an error message formatted as `{fail:'type',mess:"Error message"}`
722+- `urb.js` ;a(id "urb-js"); is the standard client-side implementation of the `%eyre` protocols, normally found in `/=main=/lib`
723+- The act of "serving" ;a(id "mime"); , refers to the wrapping of a `%mime` cage in an HTTP `200 Success` response, and errors or other marks being [sent to ford](#done) for conversion. Inside a `sign`, this conversion occurs along the same [`wire`](#wire); otherwise, the `wire` is [empty](#wire-drop).
724+
725+## Appendix B: EventSource ;a(id "eventsource");
726+
727+UNIMPLEMENTED
728+
729+For more information, see <http://dev.w3.org/html5/eventsource/>
730+
731+An EventSource is a stream of events, encoded in a conceptually infinite `GET` request. Each event is formatted as
732+```
733+ http
734+ id: {number}
735+ event: {type}
736+ data: {contents}
737+ data: {more-contents}
738+```
739+
740+Data lines are joined by ASCII `10` newline characters; multiple newlines signify separate events. The `id` is used in a `Last-Event-ID` HTTP request header upon reconnection.
learn/arvo/arvo-internals/eyre/commentary.udondeleted−274
@@ -1,274 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− sort/'1'
4− title/'Eyre commentary'
5− ==
6−;>
7−
8−# Eyre: Reference
9−
10−## State
11−
12−Stored
13−
14−- `++bolo`
15−- `++cyst`
16−- `++stem`
17−
18−Runtime
19−
20−- `perk`
21− + `perk-auth`
22−- `pest`
23−- `even`
24−
25−## Cores
26−
27−- `++handle`
28− + `++parse`
29− - `++as...`
30−- `++ya`
31−- `++ix`
32−
33−## Eyre: Commentary
34−
35−Let us follow the loading of a simple cli app, as it bounces from
36−browser to server to browser and back.
37−
38−## Initial request ;a(id "init");
39−
40−An http request for `http://sampel-sipnym.urbit.org/cli` will be [redirected](dns)
41−to the `%eyre` on ~sampel-sipnym, and come in as a `%this` kiss.
42−
43−From arvo, requests enter `++call`, which after some type reification are passed
44−along to `++apex:ye`. In the case of a `%this` kiss, its components are
45−parsed(see `++zest:epur`, `++eat-headers`) and handed off to `++handle`, wrapped
46−in `++emule` to produce a `++fail` page in case of error. `++apex:handle` will
47−`++process` the request to a `pest` or a `++done` core, and in the former case
48−`++resolve` the pest into an outgoing card.
49−
50−XX it also seems to affect the current ship, test that serving ship name is consistently correct
51−
52−The pest is produced by `++process`, which will first further `++parse` the
53−request, and if this does not make the response immediately obvious,
54−`++process-parsed` the resulting `perk`.
55−
56−`++parse` produces the `perk`, by attempting to interpret the `pork`(url path)
57−[`++as-magic-filename`](#mage), `++as-beam`, and `++as-aux-request`. In this
58−case, `/cli` is parsed by the second case as a `%beam` query to `/=cli=`: a path
59−which starts with a valid ship name is expected to be a full clay(well, ford)
60−path, and one starting with a term implies the current serving ship and a case
61−of `0`, the current revision.
62−
63−XX spur: when the desks are merged, `/cli` shall point to `/=main=/pub/cli`
64−
65−The parsed `perk` generates a `%f %boil` note, `mark`ed as its extension(here
66−defaulting to `%urb`) and `wire`d with `~` to return unaltered to the client. It
67−goes on to `++resolve` by being passed to `++ford-get-beam`, which translates
68−the perk it into a `%boil` `++ford-req`, adding an `++fcgi` path-segment
69−containing query string and `++fcgi-cred:for-client` auth information.
70−
71−`%ford`s translation of `/=cli=/hymn/hook` to a self-refreshing `%urb` html page
72−[deserves its own commentary](../ford/commentary), but we resume in `%eyre`
73−when the `%made` sign arrives in `++take`, and soon after `++axon:ye`. There the
74−`wire`, or rather the `whir` it has been verified to be, determines that the
75−response should be served immediately. However, as the mark is not `%mime`,
76−another trip to `%ford` is required to encode it, on the same wire; afterwards,
77−the value of the `%mime` cage is verified to be of the correct type, and finally
78−delivered back up the requesting duct as a succesful `%thou` HTTP response.
79−
80−XX `%cast %mime` used to be in ford-get-beam, is there a reason it was removed?
81−
82−## Back into the breach, or: auxilary requests
83−
84−Now, it was mentioned that this result is self-refreshing: the `%urb`
85−translation door injects a `;script@"/~/on/{deps}.js"` into every page, `deps`
86−is a ford-readable hash of the set of resources that page construction depended
87−on.
88−
89−This triggers another `%this` request. Its handling is identical to that of
90−`/cli` up until `++parse`, where it is seen not `++as-beam` but
91−`++as-aux-request`(auxillary requests starting with `/~/` or `/~~/`).
92−`/on/[hash]` is a long-`%poll`, which `++process-parsed`, for a `.js` mark,
93−answers with a direct `%js`. Its contents are the static `++poll:js`, which
94−initiates the long-polling loop, run against an injected `urb.js` of
95−`{poll:[hash]}`.
96−
97−A `%js` `pest` is `resolve`d as a `text/javascript` success `%this`.
98−
99−When `poll.js` is received by the client, it opens an `XMLHttpRequest` for
100−`/~/on/{window.urb.poll}.json`, bringing us back to `%poll:process`.
101−
102−In the case of a non-`%js` `/~/on/`, `%poll:process-parsed` turns into a
103−`++new-dependency`, which stores the listening duct, and `pass-note`s a `%wasp`
104−with the deps-hash back to `%ford` whence it came. While this occured, the page
105−has loaded.
106−
107−Some indeterminate amount of time afterwards, with dropped `/~/on/{...}.json`s
108−being retried upon expiring and also being stored, a `%news` sign arrives in
109−`++axon`, and the hash in question is retrieved from the wire, and the listening
110−long-polls retrieved by the hash. Each receives a 205 "Reload parent view" HTTP
111−response, which `poll.js` dutifully executes, and a fixed typo of markdown is
112−rendered.
113−
114−## Authentication.
115−
116−Now, while this accurately reflects the presentation of e.g. a markdown file,
117−`/cli` is an application front-end, and one that permits only owner access. Its
118−second script is `@"/~~/~/at/main/lib/urb.js"`, semantically equivalent to
119−`/~/as/own/~/at/main/lib/urb.js`, and handled as follows.
120−
121−In `++as-aux-request`, `%as %own` becomes `%auth %get our` perk, which
122−`++process` passes to `++process-parsed` passes to `++process-auth`. There, a
123−`yac` "ya" core is built `++for-client`: a `++cookie-prefix`, which is just the
124−serving ship name, is used to get a `++session-from-cookies`, here nil as the
125−client has no cookie set. In lieu of a cookie, a `++new-ya` is constructed, with
126−a random token `hole` and a `++new-cyst` which fills out `cyst` session state
127−from request data.
128−
129−Returning to `++process-auth`, `%get` checks if the yac is authenticated with
130−the requested credentials(`anon` requests are always granted), which for the
131−fresh new `cyst` is not the case (more on success [later](#auth-ok)). Unless
132−authentiacting as a [foreign ship](#xeno), the only thing left is to
133−`++show-login-page`, which detects that the requested resource is not `%html`,
134−and produces a `%red` pest. For `%js`, `%red`irections `++resolve` to
135−`++auth-redir:js`, a line of javascript which prepends `/~~` to the url path.
136−
137−The owner-authenticated main page request similarly ends in `++show-login-page`,
138−which for the empty session is an `[%htme ++login-page:xml]`, `resolve`d to
139−`++give-html` with a 401 "unathorized".
140−
141−The login page shows a simple prompt, and requests `/~/at/auth.js` to handle the
142−submission. And so we are, once again, attempting to divine if what we're doing
143−makes sense `++as-aux-request`.
144−
145−To understand `/~/at`, there will first be a brief diversion to `~/auth.json`.
146−`auth.json`, perk `[%auth %json]`, in `++process-auth` serves `++stat-json:ya`,
147−containing such information as the serving ship, which identities are associated
148−with this session, and `oryx`, a CSRF token. An oryx must be present on all
149−stateful requests, in this case executing a log in. It also saves the new/old
150−session using `abet`.
151−
152−XX explain `ixor` here and not [later](#ixor)?
153−
154−`/~/at` is an alternate interface, which injects `auth.json` data into the
155−requested file. `/~/at/auth.js`, then, is a request for the built-in `auth:js`
156−(parsed to and processed from an `[%auth %js ~]` perk), with session data added
157−as `window.urb`. And indeed, ``[`%js /~/at/auth]`` is parsed to
158−``[%auth at [`%js /auth]``, which in `++process-auth` is re-`process`ed to
159−`[%js ++auth:js]`, which is `++resolve`d after an `++add-json` of
160−the relevant data. The yac cookies are also passed to `resolve`, which
161−`++add-cookies` injects into the `httr`.
162−
163−It is at this point that there is first occasion for user input, namely the password.
164−
165−The `auth:js` script sends a `PUT` request, also to `/~/auth.json`. In `parse`,
166−the first nontrivial `++check-oryx` occurs, `++grab-body` the request oryx and
167−ensuring it is recorded for the session. The request parsed with `++need-body`
168−to a `[%auth %try {password}]` perk. `%get:process-auth` checks it against
169−`++load-secret`, upon success updates the session with `++logon:ya`, and
170−serves a fresh `auth.json` which reflects the changed `user`. Upon receiving
171−this, the page is refreshed to retry the original request.
172−
173−## Post-authentication: app communication. <a id="auth-ok"/>
174−
175−Upon refresh, `/~~/cli` brings us for the third time to `%get:process-auth`, but
176−this time the cookie is set, and the `yac` fetched contains the serving ship as
177−authenticated. The `++handle` sample is updated to reflect the requesting ship,
178−and the `process` continues for the rest of the pork, once again serving the
179−ford page.
180−
181−The `/~/on/[deps].json` poll starts anew, and `/~~/~/at/main/lib/urb.js` we now
182−know to serve the window.urb necessary to make requests, and the `urb.js`
183−standard library which extends it with a number of wrappers to them and other
184−useful functions.
185−
186−One of those functions is `urb.bind`, which is used to subscribe to application
187−data. Userspace javascript sets `urb.appl` to `/tic`, and binds `lines` to a
188−`;pre;` text display, using a callback.
189−
190−This triggers a `PUT` to `/~/is/{ixor}/cli/lines.json`, where `ixor` is a hash
191−of `oryx` that identifies the connection. `++as-aux-request`, an `%is` is a
192−`%subs` subscription update update, which for `%put` forwards to
193−`++add-subs:ix`, the ix core fetched `++for-view` by hashing the request
194−`++oryx-to-ixor`.
195−
196−<a id="ixor"/> A view has all the state associated with a client that must be
197−remembered between events. In this case, this is what app/path the request duct
198−is associated with; but mainly, `++add-subs:ix` will `pass-note` to `%gall` so
199−it `%show`s the data on the path, current and future.
200−
201−This will immediately(assuming the ship is local) result in a `%nice` by the
202−`/cli` app, returning `{ok:true}` `++nice-json` to `urb.bind`'s second callback
203−as `{ok:true}`. The initial `%rush` results also arrive, and in `++axon` are
204−converted to json using `++back`(ford `%cast` wrapper), and when `%made` get
205−passed to `++get-rush:ix`. There the source application/path are decoded by
206−duct, and then the full event goes to `++get-even`; `++add-even` inserts it to
207−the queue, and as there is no long poll it simply stays there.
208−
209−Upon receipt, the client realizes the long-poll isn't actually running, so that
210−is started using `urb.poll`. At `/~/of/{ixor}`, perk
211−`[%view ixor ~ {sequence-number}]`, it is `process`ed by `++poll:ix` (the cyst
212−is retrieved by `++ire-ix` form global state, using the perk `ixor`): the
213−sequence number is in the past, so the previously received `%rush` is
214−`++give-even`. After deleting the previous message in the queue and invoking
215−`++pass-took` to signal `%gall` of this occurrence, the data is annotated with
216−the source app+path `++subs-to-json`, and returned to the polling duct.
217−
218−On the client, the user callback receives the `/cli` history, and displays it on
219−the page. The `/~/of` long poll is continued, this time reaching `++poll:ix`
220−with the "pending" sequence number, and being stored in the `cyst` for its troubles.
221−
222−Its next update proceeds idenitcally, but first it must be triggered, which
223−happens when the user enters "(add 2 2)\n", firing an `urb.send` from the event
224−handler. This sends a `POST` request to `/~/to/cli/json.json`, perk `%mess`,
225−`++process`ed to a `%g %mess`. Were the mark not `%json`, a `%ford` conversion
226−would occur first, and `%made:axon` would send the gall message proper. In
227−either case, eventually a `%mean` or `%nice` arrives, is encoded as json, and
228−sent to the client callback.
229−
230−## A path not taken: magic filenames <a id="mage"/>
231−
232−The `/robots.txt` and `/favicon.(ico|png)` files are static, and served
233−immediately when caught by a `++parse`.
234−
235−XX index.html?
236−
237−## A path not taken: foreign auth <a id="xeno"/>
238−
239−While this example details a login `/~/as/own`, it is possible to be
240−authenticated as any ship on the network. A request for such seen in
241−`%get:process-auth` is passed to `++foreign-auth:ya`, which sends an
242−`%ames /lon` message to the ship in question. The foreign ship stores the
243−inquiry, calculates(the local) `++our-host` and responds with a `/hat`,
244−containing the redirection host, which is stored by `++foreign-hat`; it is later
245−used to send the client to a `/~/am` url on the foreign client, which acts as a
246−normal login page but later sends the client back. XX expand, basically the
247−status quo is you're logged in and `/~/as/foo` is ignored, just setting your
248−`urb.user` XX
249−
250−
251−## A path not taken: deauthentication
252−
253−`/~/away`, perk `[%away ~]`, produces a static `++logout-page:xml`, which also
254−uses `/~/at/auth.js`, to send a `DELETE /~/auth.json`, perk `[%auth %del]`. This
255−executes `++logoff:ya` for the cookie session, resolving to `++abut` to wipe it
256−from memory.
257−
258−## A path not taken: unsubscription
259−
260−`DELETE /~/is/app/path/within` works much like `PUT /~/is/app/path/within`,
261−`++del-subs:ix` acting as reverse of `++add-subs` by deleting the duct binding
262−and sending `%g %nuke`.
263−
264−
265−XX unmentioned arms: abet, add-poll, adit, ames-gram, anon, ares-to-json, bolo, cyst, doze, even, ford-kill, get-mean, gift, give-json, give-thou, gram, hapt, hasp, host-to-ship, ix, ixor, js, kiss, load, mean-json, move, note, pass-note, perk, perk-auth, pest, poke-test, print-subs, render-tang, resp, root-beak, scry, ses-authed, ses-ya, sign, silk, sine, stay, stem, teba, titl, to-oryx, urb, wait-era, wake, whir, wush, xml, ya, ye
266−
267−## Appendix A: DNS <a id="dns"/>
268−
269−The `*.urbit.org` domain can be used to access destroyers and cruisers. In the
270−common case oh hosted ships, this is done by dynamic DNS directly to the hosting
271−instance. We do not speak of the uncommon case. When ports are blocked and
272−infrastructure crumbles around you, only imported martian networking can be
273−trusted: the `%get` and `%got` [gram]()s are used to proxy [`%this` requests]() and
274−[`%thou` responses]() respectively.
learn/arvo/arvo-internals/eyre/specification.udondeleted−444
@@ -1,444 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− sort/'2'
4− title/'Eyre specification'
5− ==
6−;>
7−
8−# Specification
9−
10−The `%eyre` vane serves one purpose: receiving inbound HTTP requests from browsers and clients pretending to be browsers. To facilitate this communication, `%eyre` does two things: 1. provide an API for traditional clients to talk to; and 2. provide a mechanism for saving state that allows the server to keep track of identities/sessions, subscription data, and active connections.
11−
12−This document outlines the following:
13−
14−1. [`perk`](#perk), a `pork` subset that defines what URLs the client can send to `%eyre`.
15−
16−2. [the values stored on the client](#client), both statically in cookies and dynamically as the `window.urb` object, which facilitate this transaction.
17−
18−3. [`kiss`](#kiss), the requests `%eyre` will accept.
19−
20−4. [`gift`](#gift), the responses it will give to those requests.
21−
22−5. [`note`](#note), the set of arvo requests that %eyre makes to the other vanes.
23−
24−6. [`whir`](#whir), a `wire` subset, the associated dynamic state
25−
26−7. [`sign`](#sign), the responses `%eyre` accepts
27−
28−8. [`bolo`](#bolo), the state stored between separate events.
29−
30−;a(id "perk");
31−# 1. URL structure
32−
33−There exist several URL forms accepted by `%eyre`.
34−
35−## 1.1 Functional request
36−
37−The simplest of them is a static `%f` functional publish request:
38−
39−```
40− GET /[ship]/[desk]/[case]/path/to/file.[mark]
41−```
42−e.g.
43−
44−```
45− /~pittyp-pittyp/main/5/lib/urb.js
46−```
47−A `case` of 0 signifies the most recent version.
48−
49−If no file extension is provided, the default `mark` is `%urb`, which consists of `%html` injected with an auto-refresh script.
50−
51−A shorter form:
52−
53−```
54− /path/to.[mark]
55−```
56−is prepended with the [default request path](#prefix). For example, if `%eyre`
57−is configured with a root of `/<our>/main/0/pub`, then `/doc/arvo` is
58−interpreted as a request for `/=main=/pub/doc/arvo.urb`.
59−
60−Auxiliary paths start with `/~/`, and provide other functionality, such as:
61−
62−## 1.2 Auto-reload
63−
64−When a new version of a page becomes available, it is useful to propagate it to the client. The `%f` vane manages the particulars, and provides an update token along with all published pages. The `/~/on` long-polling endpoint makes use of that token, which is a hash of the server-stored dependency set.
65−- `/~/on/[hash].json` retuns `true` when a page may require updating.
66−- `/~/on/[hash].js` is a lightweight script that polls for the above. It is primarily used in error messages.
67−
68−;a(id "auth");
69−## 1.3 Authentication
70−
71−Authenticated requests are accomplished through sessions, tracked with cookies which are set on the first such request.
72−- `/~/as/[user]/...` is an authenticated request to `...`, where `user` can be a `@p` ship, `'own'`, `'any'`, or `'anon'`.
73− + `'anon'` is a randomly-generated per-session submarine, and requires no further authentication.
74− + `'own'` represents the serving ship. The short form of `/~/as/own/` is `/~~/`
75− + `'any'` requires a network ship, chosen with a prompt if unknown. The short form of `/~/as/any/` is `/_/`
76− + Auth requests are handled in three ways:
77− + I. If the session is associated with the `ship`, serve `...`, storing the ship as the session's default ship. For example, `/~/as/sivtyv-barnel/main/pub/test.html` is an authenticated request of `/main/pub/test.html` with the identity of `~sivtyv-barnel`.
78− + II. If the session is not associated with the `ship` in the path, the client is redirected to a login page, where a password can be entered. Successful authentication results in a page refresh to the requested path.
79− + III. otherwise, [send a message](#foreign) to the claimed ship, and redirect the user to `https://[foreign-host]/~/am/[ses]/...#[current-host]&?code=[code]`
80−- `/~/am/[ses]/...#original-host` similarly serves a login page. Upon success, inform the `ship` of the success and redirect it back to `http://[original-host]/~/as/<this-ship>/...`
81−- `/~/away.html` is a log-out page.
82−- `/~/auth.json` returns `{ship,oryx,user,auth}`: the serving ship, a CSRF token, active user, and all allowed users respectively.
83−- `/~/at/{...}.js` is an alternate form of `/~/auth.json`, which injects a line into the served js file that sets `{ship, oryx, user, auth}` on the `window.urb` object.
84−
85−So far, all the paths specified have been GET requests. Authentication, however, requires sending data. This is also done at the `/~/auth.json` endpoint.
86−- `POST {oryx,ship,code} /~/auth.json?PUT` is used by the login script to authorize a user, and returns the same result as `GET`, additionally containing either`{ok:true}` or `{fail:'type',mess:"Error message"}`
87−- `POST {oryx,ship?} /~/auth.json?DELETE` revokes authorization. Response as above.
88−
89−## 1.4 Messaging
90−
91−- `POST {oryx, wire, xyro} /~/to/[app]/[mark].json`, where `xyro` is data that will be converted to the `mark`. In the simplest case, `/~/to/hello/json.json` will pass `xyro` through verbatim, sending `[%json xyro]` to the `++poke` arm of app `%hello`.
92−- `POST {oryx, wire, xyro} /~/to/<ship>/[app]/[mark].json` is a foreign message send, as above.
93−
94−;a(id "subs");
95−## 1.5 Subscriptions
96−
97−;a(id "of-ixor");
98−
99−- `/~/of/[ixor]` is an `EventSource`: a conceptually infinite file containing a stream of events. By default, it sends a newline every 30 seconds serving to signal that the connection is alive to both the server and IP middleware.
100− + `/~/of/[ixor]?poll={n}` is a long-polling fallback interface. Produces event number `{n}`, blocking until it occurs. Its contexts can be affected by `POST` requests with a body of `{oryx, wire}`, and a query string of `PUT` or `DELETE`. They return either `{mark}`(which may be `null`), or [`{fail, mess}`](#mean-json)
101−- `/~/in/[hash].json` is a dual to [`/~/on`](#on-change). It binds `mod` events, which echo the requesting token.
102−- `/~/is/[app]/path/to.[mark]` binds `rush` events, formatted with a first line of `[app] /path/to`, and the rest containing subscription data. Additionally, `mean` events formatted similarly may arrive, also converted to the relevant mark.
103−
104−
105−
106−;a(id "temp");
107−## 1.6 Ablative
108−
109−These interfaces will temporarily exist to aid development, and are to be considered unstable.
110−- `/~/debug/...` access normally inaccessible pages. For example, `/~/debug/as.html` will present the login page, regardless of current session status.
111−
112−
113−# 2. Client state ;a(id "client");
114−
115−Some information is stored on, and provided to, browser clients
116−
117−## 2.1 Cookies
118−
119−Authenticated users receive a cookie on the domain of `*.urbit.org`. The cookie contains a client session token, keyed by the serving ship.
120−
121−## 2.2 Authentication ;a(id "auth-json");
122−
123−It is common(e.g. by the `%urb` mark) to set window.urb to the contents of `/~/auth.json`:
124−- `ship` is the serving ship
125−- `oryx` is a unique CSRF token that identifies this view, bound to the session cookie
126−- `ixor` is a hash of `oryx`, used as an insecure view identifier
127−- `user` is the authenticated/generated ship name
128−- `auth` is a list of identities usable by this session
129−
130−## 2.3 Client library
131−
132−To this object, `/main/lib/urb.js` adds helpers:
133−- `app` is an optional app name to send messages to by default
134−- `send({data,mark?='json',app?=urb.app,ship?}, cb?)` delivers messages
135−- `bind({path,app?=urb.app}, cb)` subscribes by path
136−- `drop({path,app?=urb.app}, cb?)` pulls the subscription
137−- `util` is an object containing methods for converting between JavaScript types and Hoon atom odors.
138−
139−# 3. Requests ;a(id "kiss");
140−
141−## `[%born port=@ud]`, unix init
142−
143−When the `vere` process is re/started, a TCP port is bound, HTTP requests on which are the scope of this document. The `%born` gift informs eyre of this occurrence, which in turn updates [its state.](#bolo)
144−
145−*Gifts given in response:* none.
146−
147−## `[%hiss p=mark q=cage]`, outbound http
148−
149−Userspace http request, converted by `%ford` into an actual `hiss`.
150−
151−*Gifts given in response:* a [`%sigh`]()
152−
153−## 3.1 `[%this httq]`, inbound http
154−
155−The primary `%eyre` request type comes from the host system, and constitutes an inbound http request. It consists of five parts:
156−
157−I. `p=[? @if]`: a loobean determining whether the request is being made over https, and the client source, an IPv6 address possibly encoding an IPv4 one as `.0.0.0.0.0.ffff.wwxx.yyzz`
158−
159−II. `q=meth`, an http method
160−
161−III. `r=@t`, the unparsed URL
162−
163−IV. `s=mess`, an associative list of header keys/values
164−
165−V. `t=(unit octs)`, the request body, if any.
166−
167−After `r` is parsed to a `purl`, the `pork`(relative path) determines the resource being served. The first step in handling an http request is [classifying its intent](#perk).
168−
169−- A ford request results in a [`%boil` note](#boil).
170−- `/~/[name].js` is generated from [session](#sink) or [view](#stem) state, and [served](#mime) as `%js`.
171−- `/~/am` generates a login page.
172−- `/~/as` is resolved further if authenticated, generates a similar login page if the claimed ship is local, and otherwise is saved to [session state](#sink) and sends a ["login" `%a` message](#lon) to the foreign ship.
173−- `/~/at` and `/~/auth.json` generate a new `oryx` and store it in the [session state](#sink).
174−- `/~/in` and `/~/is` affect [view state](#stem), possibly sending subscriptions or unsubscriptions to `%f` and `%g` respectively, and are generated from view state.
175−- `/~/on` is saved to the `bolo` by `hash`, and translated to a [`%wasp` note](#wasp).
176−- `/~/of` fails if the `ixor` is unknown, and otherwise is stored in the `ixor`, receiving a partial response and all events after its [last-seen header](#). If it has a `poll` parameter, the response is full, and only occurs if the body is non-empty. Otherwise the oryx is saved as a [live](#live) request in case of cancellation.
177−- `/~/to` transforms into a [`%g` message](#mess).
178−
179−*Gifts given in response:* a [`%thou`](), or a [`%that`](#that) followed by multiple [`%thar`]()s.
180−
181−## 3.2 `[%thud ~]`, inbound close
182−
183−Sent when an unresponded-to request is cancelled. The [live](#live) effect of the request is looked up, and
184−- `%exec` ford boil requests are cancelled with `[%exec ~]`
185−- `%wasp` ford deps requests are cancelled with `[%wasp |]`
186−- `%poll` session polls `%rest` the session heartbeat timeout
187−
188−## 3.3 `[%thin p=@ud]`, delivery failure
189−
190−Sent when a partial [response](#that) or [body](#thar) fails to arrive. Its `duct` is the same as that of the original request. This is handled by [waiting](#wait) for the client to reconnect, and if this not occur, unwinding all subscription state.
191−
192−
193−*Gifts given in response:* None.
194−
195−## 3.4 ``[%wart sock [path *]]``, inbound message
196−
197−Sometimes, messages are received from other ships. They are expected to take the from of a [`gram`]().
198−
199−*Gifts given in response:* [`%nice` or `%mean`](#ack).
200−
201−### 3.4.1 `gram` <a id="gram"/>
202−
203−There are three messages of note, all concerning authentication <a id="foreign"/>
204−- `[/lon ses]` <a id="lon"/> is a login request, which contains the session wishing to authenticate.
205−- if the session is already authorized, a reply of `[/aut ses]` from (%eyre on) a foreign ship prescribes that the session is henceforth allowed to act on its behalf. All waiting `/~/as` are resolved as successful.
206−- otherwise, `[/hat ses hart]` contains the ship's preferred hostname. This can then be used to redirect the client. All waiting `/~/as` are given `307 Redirect`s to `/~/am` on the provided host.
207−
208−*Gifts given in response:* nice?
209−
210−# 4. Responses ;a(id "gift");
211−
212−## 4.1 `[%nice ~]`, `[%mean ares]`, network acknowledgement ;a(id "ack");
213−
214−A `%nice` is given upon receiving an [ames message](#gram), indicating succesful receipt. `%mean` is currently unused directly, but reserved for error conditions.
215−
216−## `[%sigh p=cage]`, inbound http response
217−
218−An HTTP response gets converted to the requested mark, or `%tang` in case of error.
219−
220−## 4.2 `[%thou httr]`, full HTTP response
221−
222−Most requests are served with one coherent response, consisting of
223−- `p=@ud`, an HTTP status code
224−- `q=mess`, response headers
225−- `r=(unit octs)`, an optional body
226−
227−## 4.3 `[%that httr]`, partial HTTP response ;a(id "that");
228−
229−[EventStream responses](#of-ixor) consist of multiple sequential chunks. Treated as `%thou`, except the request is kept open.
230−
231−## 4.4 `[%thar (unit octs)]`, partial HTTP body ;a(id "thar");
232−
233−Complementing `%that`, `%thar` is a body chunk, containing an event. An empty `%thar` signals for the connection to be closed.
234−
235−Body chunks, besides `[1 '\0a']`(a heartbeat newline), are encoded from `even` events. The stem becomes the [`event` field](#eventsource), and the content, `data` lines.
236−
237−### 4.4.1 `even`, event types ;a(id "even");
238−
239−There are three events that a [client subscription](#subs) will be given.
240−
241−- `[%news hash]`;a(id "even-news"); is a `%f` update, and contains the relevant dependency token.
242−- `[%rush [term path] wain]` ;a(id "even-rush"); is sourced subscription data.
243−- `[%mean [term path] ares]` is a sourced subscription error.
244−
245−# 5. Vane requests ;a(id "note");
246−
247−## 5.1 ``[%a %wont sock `[path *]`gram]``, outbound message
248−
249−The `%a` interface provides conveyance of [messages](#gram) over UDP.
250−
251−Signs a `%woot` upon message arrival.
252−
253−## 5.2 `[%b ?(%wait %rest) time]`, timeout set/unset ;a(id "wait");
254−
255−All open [subscriptions](#of-ixor) require a "heartbeat" newline every `~s30`. When this fails to arrive, a complementary timer is set for `~m1`, after which the client is considered to have departed.
256−The `%b` timer interface is used to schedule the next such event, or cancel past scheduled ones when a connection closes.
257−
258−Signs a `%wake` upon timer activation.
259−
260−## 5.3 `[%f %wasp @uvI]`, dependency listen ;a(id "wasp");
261−
262−Knowledge of filesystem changes, requested by `/~/on` and `/~/in`, is requested the `%wasp` note. It contains the hash token which identifies a set of dependencies to query. Saved as a (live[live](#live)#live] request in case of cancellation when caused by `/~/on`.
263−
264−Signs a `%writ` upon change.
265−
266−## 5.4 `[%f %exec (unit silk)]`, functional transformations
267−
268−The `%f` interface converts nouns from one form to another. An empty unit represents cancellation.
269−
270−Signs a `%made` containing the computation result.
271−
272−The `silk`s used are as follows:
273−
274−### `[%cast %mime %boil mark beam [%web span ~]]`, file load
275−
276−The simplest functional request is the construction of a page. Saved as a [live](#live) request in case of cancellation.
277−- The `mark` is the request extension, defaulting to `%html`.
278−- A `beam`(path in `%clay`) is decoded from the request path.
279−- A `/web/<nyp ced quy>` virtual path is appended, span-encoding method, auth, and query string.
280−
281−### `[%cast mark %done ~ cage]`, convert ;a(id "done");
282−
283−This is used when communicating with apps, in both directions.
284−- Client messages are encoded as JSON objects, but can contain many different marks. Ones sent to non-`json.json` endpoints are `%cast` to he relevant mark, with a `cage` of `[%json p:!>(*json) jon]`, prior to being sent onwards to applications with `[%g %mess]`.
285−- Subscription responses also come in arbitrary marks, but are required to be sent as whichever mark an endpoint is subscribed to. They get `%cast` prior to being sent back as a `%that` EventSource segment.
286−
287−## 5.5 `%g`, app actions
288−
289−The end goal of many a userspace `hymn.hook` is to provide UI for a `%gall` app. To accommodate this, various functionality needs to be interfaced with.
290−
291−### `[%mess hapt ship cage]`, app message ;a(id "mess");
292−
293−After a `/~/to` POST has been received, and possibly converted to the correct mark, it is sent to `%g` for processing. The `hapt` is the destination, the `ship` is the source, the `cage` is the marked message data.
294−
295−Signs a `%nice` or `%mean`, in userspace or upon crashing.
296−
297−### `[%show hapt ship path]`, app subscription ;a(id "show");
298−
299−An `/~/is` PUT, if not already registered, results in a new subscription. A request for such contains the destination `hapt`, requesting `ship`, and app-internal `path`.
300−
301−Signs a `%nice` on init, `%rush` on data, and a `%mean` in subscription termination.
302−
303−### `[%took hapt ship]`, %rush confirmation
304−
305−A `%took` must be sent to acknowledge the receipt of subscription data, which in this case occurs automatically.
306−
307−Causes no signs.
308−
309−### `[%nuke hapt $|(ship [ship path])]`, subscription cancel
310−
311−An `/~/is` DELETE is used to remove a subscription, and is converted straightforwardly to a `%nuke`. Additionally, when a client disconnects, all of its subscriptions are `%nuke`d to reflect their expiration.
312−
313−Signs an empty `%mean` for each open subscription that is closed.
314−
315−# 6. In-flight metadata ;a(id "whir");
316−
317−Various state can be associated with requests, but not necessarily be returned in responses to them.
318−
319−## 6.1 `~`, dropthrough ;a(id "wire-drop");
320−
321−If the response should be sent statelessly further up the duct, the `wire` is empty. This is used in `%f` pure functional page generation.
322−
323−## 6.2 `[?(%y %n) ...]`, stability ;a(id "wire-live");
324−
325−The first element of a [`%b` timer](#wait) path distinguishes between live(%y) and dying(%n) channels.
326−
327−## 6.3 `/of/[ixor]`, view
328−
329−Designates which stream to act upon. Present on `%b` timer cards.
330−
331−## 6.4 `/on/<deps>`
332−
333−Present on `%f` dependency news. Looked up in [the state](#bolo) to see if any response is necessary.
334−
335−## 6.5 `/to/<hasp>/<ship>`, app ;a(id "wire-to");
336−
337−Present on `%f` translations of message marks
338−
339−## 6.6 `/is/[ixor]/{hasp path}`, subscription ;a(id "wire-is");
340−
341−Subscription requests. Present on `%g` subscription requests, and `%f` translations of [`%rush` subscription data](#show).
342−
343−# 7. Vane responses ;a(id "sign");
344−
345−The goal of requests is to cause some manner of result. Specifically,
346−
347−## 7.1 `[%a %woot ship coop]`, acknowledgement
348−
349−A [message](#mess) which has been acknowledged remotely.
350−
351−## 7.2 `[%b %wake ~]`, timer
352−
353−Timer activate. If this is a `%y` [timer](#wire-live), send a newline to each `/~/of/[oryx]`; if `%n` and the `oryx` still has no listeners, wipe its state/subscriptions.
354−
355−## 7.3 `[%f %news ~]`, dependency update
356−
357−This message signifies a `hash` has changed, and listeners to it should be updated. Results in [`%news` events](#even-news) to concerned streams, and [full responses](#thou) to relevant long-polls.
358−
359−## 7.4 `[%f %made (each bead (list tank))]`, compute result
360−
361−Further action depends on the [`wire`](#whir). It can:
362−- Be empty, designating direct request data, which is [served](#mime) back up the `duct`.
363−- Contain [app and requester identities](#wire-to), which designates an app message has been converted to the correct `mark`, and can now be [sent to the app](#mess) with an empty `wire`.
364−- Contain an `oryx`, app, and `path`, designating subscription data. If the subscription is active in the relevant `stem`, it is acknowledged with a `%took` and given as a [`%rush` event](#even-rush) to all listeners. Otherwise, the subscription is `%nuke`d.
365−
366−## 7.5 `%g`, applications
367−
368−The `%g` interface sends several responses.
369−
370−### `[%nice ~]` and `[%mean ares]`, acknowledgment
371−
372−These are given as a response to `%mess`, with an empty wire, and `%show`s, with a [subscription wire](#wire-is).
373−The former is [served](#mime) back to the requester(i.e. the remaining duct), and the latter returned to the client.
374−
375−### 7.5 `[%rush cage]`, subscription data
376−
377−A `%rush` arrives on a [subscription wire](#wire-is), and is then sent [for conversion](#done) to the correct mark. An unexpected `%rush` is `%nuke`d.
378−
379−# 8. Server state ;a(id "bolo");
380−
381−There is a quantity of data that persists between events.
382−
383−## 8.1 Global
384−
385−- `path` ;a(id "prefix"); the default path which is prepended to relative plain requests. Initialized to `/<our>`, the serving ship; this interprets the first element of requests as a desk, and injects a `case` of `0`.
386−- `(jar ship hart)` remembered hostnames in order of preference, made accessible through `.^`
387− + The default values(for self) are `http://<ship>.urbit.org:80` if not on a fake network, followed by `https://0.0.0.0:[port]`.
388−- `(jug deps (each duct oryx))`, `/~/on` and `/~/in` endpoints listening to `%c` updates.
389−- `(map duct live)`, inbound request state
390−- `(map ixor oryx)`, open `/~/of` streams.
391−- `(map oryx stem)`, open view state.
392−- `(map hole sink)`, session state.
393−- `(map hole ,[ship ?])`, foreign session names, along with their origin ships and whether they are authorized to act on our behalf.
394−
395−## 8.2 `live`, per-request state ;a(id "live");
396−
397−To honor request cancellations, each unserved request must track which effect it is causing.
398−+ `[%exec whir]` if it is a ford data request
399−+ `[%wasp (list @uvH)]` if it is a ford dependency poll
400−+ `[%xeno ship]` if this is a proxied request
401−+ `[%poll ixor]` if this is a session long-poll
402−
403−## 8.3 `sink`, per-session state ;a(id "sink");
404−
405−Each `hole` has associated authentication state.
406−- `priv`, a random secret that verifies the session, stored in cookie.
407−- `[ship (set ship)]`, the `ship` a session is acting as and any others it has been authorized with.
408−- `(jug ship ,[path duct])`, authentication `/~/as` requests waiting on foreign ships.
409−- `(set oryx)`, views associated with this session. Dual of `hole` in `stem`.
410−
411−## 8.4 `stem`, per-view state ;a(id "stem");
412−
413−Each `oryx` has active subscription state.
414−- `hole`, session in which this view resides. Dual of `(set oryx)` in `sink`.
415−- `ixor` ;a(id "ixor"); , a cached hash of the `oryx` that is used as a subscription id, by the `/~/of` EventStream.
416−- `[,@u (map ,@u even)]`, queued [events](#even). Has a maximum size.
417−- `(unit ,[duct @u ?])`, http connection, its last received event, and whether it is a long-poll request.
418−- `(set deps)`, subscribed `/~/in` points. Mirrored in `bolo`.
419−- `(map ,[hasp path] mark)`, subscribed `/~/is` points
420−- `(que duct)`, where any `%nice`/`%mean
421−
422−# Appendix A: Glossary
423−
424−- An `oryx` is a CSRF token used for [authenticated requests](#auth)
425−- `mean.json` ;a(id "mean-json"); is a rendering of hoon `ares`: an error message formatted as `{fail:'type',mess:"Error message"}`
426−- `urb.js` ;a(id "urb-js"); is the standard client-side implementation of the `%eyre` protocols, normally found in `/=main=/lib`
427−- The act of "serving" ;a(id "mime"); , refers to the wrapping of a `%mime` cage in an HTTP `200 Success` response, and errors or other marks being [sent to ford](#done) for conversion. Inside a `sign`, this conversion occurs along the same [`wire`](#wire); otherwise, the `wire` is [empty](#wire-drop).
428−
429−# Appendix B: EventSource ;a(id "eventsource");
430−
431−UNIMPLEMENTED
432−
433−For more information, see <http://dev.w3.org/html5/eventsource/>
434−
435−An EventSource is a stream of events, encoded in a conceptually infinite `GET` request. Each event is formatted as
436−```
437− http
438− id: {number}
439− event: {type}
440− data: {contents}
441− data: {more-contents}
442−```
443−
444−Data lines are joined by ASCII `10` newline characters; multiple newlines signify separate events. The `id` is used in a `Last-Event-ID` HTTP request header upon reconnection.
learn/arvo/arvo-internals/filesystem.udon+2−3
@@ -2,11 +2,11 @@
22 navuptwo/'true'
33 next/'true'
44 sort/'7'
5− title/'Filesystem (Clay)'
5+ title/'Introduction to the Filesystem'
66 ==
77;>
88
9−# Filesystem (Clay)
9+# Introduction to the Filesystem
1010
1111
1212Urbit has its own revision-controlled filesystem, Clay. Clay is a typed, global,
@@ -18,7 +18,6 @@ Urbit process will watch this directory and automatically record edits as
1818changes, Dropbox style. The mounted directory is always at the root of your
1919pier directory.
2020
21−
2221## Quickstart
2322
2423This quick-start guide will walk you through some common commands. Follow along
learn/arvo/arvo-internals/ford.udon+470−3
@@ -24,9 +24,7 @@ while `%gall` uses `%ford` to control the execution of applications.
2424`%clay` is intended to use `%ford` to managed marked data, but this is
2525not yet reality.
2626
27−;list;
28−
29−# Cards
27+## Cards
3028
3129`%ford` accepts just one card, `%exec`. This is misleading, however,
3230since there are fourteen different `silk`s that may be used with it. In
@@ -110,3 +108,472 @@ Slaps a hoon against a subject silk. The mark of the result is `%noun`.
110108
111109Validates untyped data from a ship against a given mark. This is an
112110extremely useful function.
111+
112+;=
113+ ;h2
114+ ;div(id "runes"): Ford runes
115+ ==
116+==
117+
118+One of the most common ways to use ford is through ford's runes, all of which begin with `/` ("net"). A ford rune runs a step of a ford build and places the result in the subject. There are various kinds of build steps, some of which take other build steps as parameters. The most common pattern is to have a sequence of ford runes at the top of a hoon source file that import the results of evaluating other hoon files. This is how we "import a library" in urbit: we add the result of compiling another hoon file into the current subject, possibly renaming it by wrapping a face around it.
119+
120+Another common use case is assembling and rendering markdown templates into a single HTML file, to be sent as an HTTP response in urbit's web server `%eyre`. It's important to keep in mind that %ford is quite flexible and generic, and is used in other parts of urbit -- such as the dojo -- that would not traditionally fall under the purview of a build system.
121+
122+### `/+` import from lib/
123+
124+The `/+` rune accepts a filename as an argument. It interprets that filename
125+as a hoon source file within the `lib` directory. This is how we import a shared
126+library in urbit.
127+
128+To run this example, put this code in your desk at `gen/faslus.hoon` and run
129+`+faslus` in your dojo. This example is a generator. For more information on
130+generators, see the [generator docs](https://urbit.org/docs/arvo/generators).
131+
132+```
133+/+ time-to-id
134+::
135+:- %say
136+|= {{now/@da * *} $~ $~}
137+:- %noun
138+(time-to-id now)
139+```
140+
141+produces: `"c.314d"` (or something similar depending on when you run it)
142+
143+You can import multiple libraries with a single `/+` rune by separating them
144+with commas.
145+
146+Replace the code in `gen/faslus.hoon` with the following:
147+
148+```
149+/+ time-to-id, hep-to-cab
150+::
151+:- %say
152+|= {{now/@da * *} $~ $~}
153+:- %noun
154+=/ id (time-to-id now)
155+=/ str "my-id-is-{id}"
156+(hep-to-cab (crip str))
157+```
158+
159+This should print something like `my_id_is_c.3588`.
160+
161+Another feature of the
162+`/+ and`/-`runes is the ability to specify the`ship`and`case\` from which to
163+load the library.
164+
165+Example:
166+
167+```
168+/+ time-to-id, hep-to-cab/4/~zod
169+```
170+
171+will load the `hep-to-cab` library from `~zod` at `%clay` revision `4`.
172+
173+### `/-` import from sur/
174+
175+The `/-` rune accepts a filename as an argument. It interprets that filename as
176+a hoon source file within the `sur` directory. The `sur` directory contains
177+shared structures that can be used by other parts of urbit. This is somewhat
178+similar to including a header file in C.
179+
180+Example:
181+
182+```
183+/- talk
184+::
185+*serial:talk
186+```
187+
188+produces: `0v0`
189+
190+`/-` can also take multiple files as arguments, and the ship and case of those
191+arguments can be specified. See the `/+` docs for more details about the syntax
192+for those features.
193+
194+### `/~` twig by hand
195+
196+`/~ <twig>` produces a "horn" that evaluates a twig and places the product in
197+the subject. Arbitrary hoon can be in the twig. A
198+horn is a data
199+structure representing a `%ford` static resource.
200+
201+Example:
202+
203+```
204+/~ [a=0 b=1]
205+[a b]
206+```
207+
208+produces: `[0 1]`
209+
210+In wide-form, `/~` always takes a tuple (which may be a degenerate tuple of one element), and produces it.
211+
212+Example:
213+```
214+/~[%something]
215+```
216+produces: `%something`
217+
218+```
219+/~[%a %b]
220+```
221+produces: `[%a %b]`
222+
223+### `//` include a file by relative path
224+
225+`// <rel-path>` parses `rel-path` as a hoon twig, and then adds the resulting
226+twig to the subject. Note that the result type of this rune is not a horn, but
227+just a hoon twig, so its result can't be used as an argument to other runes
228+that expect a horn. There is no wide-form for this rune.
229+
230+Example:
231+```
232+// %/file-to-include
233+::
234+(frobnicate:file-to-include %.n)
235+
236+:: contents of file-to-include.hoon
237+|%
238+++ frobnicate
239+ |= a/? ^+ a
240+ !a
241+--
242+```
243+produces: `%.y`
244+
245+_Note: `%` means current directory, which in a hoon file will resolve to the
246+"directory" containing that file. Also, %clay doesn't have first-class
247+directories the way unix filesystems do. Whereas in unix, a directory is a
248+special kind of file, in %clay it's just a path prefix, and there is no file
249+stored at that path._
250+
251+### `/=` wrap a face around an included horn
252+
253+`/=` runs a horn (usually produced by another ford rune), takes the result of
254+that horn, and wraps a face around it.
255+
256+Example:
257+```
258+/= foo /~ [a=0 b=1]
259+::
260+[a.foo b.foo]
261+```
262+produces: `[0 1]`
263+
264+In wide-form, `/=` uses `=` as a delimiter: `/=foo=/~[a=0 b=1]`
265+
266+### `/:` evaluate at path, and `/<mark>/` render mark at current path
267+
268+`/:` takes a path and a horn, and evaluates the horn with the current path set to the supplied path.
269+`/mar/` renders the mark 'mar' at the current path.
270+
271+Example:
272+```
273+/= hoo-source /: /path/to/hoon-file /hoon/
274+::
275+`@t`hoo-source
276+```
277+
278+produces the text of the hoon file at "/path/to/hoon-file/hoon".
279+
280+`/hoon/` renders the current path using the `%hoon` mark, which in this case
281+passes the contents through unchanged. In general, rendering a file with a
282+mark will potentially run the contents through a series of conversion
283+operations. For details on marks, see the
284+[marks docs](https://urbit.org/docs/arvo/marks).
285+
286+Here's an example that includes a mark conversion:
287+```
288+/= page /: /path/to/html/file /mime/
289+::
290+page
291+
292+:: contents of /path/to/html/file:
293+<html><head><title>My Fascinating Blog</title></head></html>
294+```
295+produces:
296+`[[%text %html ~] 60 '<html><head><title>My Fascinating Blog</title></head></html>']`
297+
298+This result includes the MIME type ('text/html'), the content length in bytes,
299+and the HTML itself.
300+
301+In wide-form, `/:` uses `:` as a delimiter: `/=page=/:/path/to/html/file:/mime/`
302+
303+### `/!mark/` evaluate as hoon, then pass through mark
304+
305+Example:
306+```
307+/= mime /: /%/some-hoon-file /!mime/
308+::
309+mime
310+
311+:: contents of /%/some-hoon-file:
312+%produces-a-cord
313+```
314+produces: `[[%text %plain ~] 15 'produces-a-cord']`
315+
316+### `/&` pass through a series of marks
317+
318+`/&` passes a horn through multiple marks, right-to-left. It has both a
319+wide-form and a tall-form syntax. In wide-form, it takes a series of mark
320+arguments followed by a horn. In tall-form, it takes a single mark followed by
321+a horn.
322+
323+```
324+/= some-text /: /%/text-file /&mime&/txt/
325+::
326+some-text
327+```
328+produces: `[[%text %plain ~] p=17 q='Hi I\'m some text\0a']`
329+
330+This example shows two of the ways marks are used. The first way is what
331+happens with the `/txt/` mark: we use it to find a file in clay with that
332+extension, without performing any conversions. Since this file is stored with
333+the `%txt` mark in `%clay`, its type is a `wain`: a list of cords, where each
334+cord is a single line. Once we've read the file, the `%mime` mark converts the
335+`wain` to a triple that includes the MIME type ("text/plain"), the content
336+length in bytes, and the content itself as a cord.
337+
338+```
339+/= page /&html&elem&/~[;div.foo;]
340+::
341+page
342+```
343+produces: `'<html><head></head><body><div class="foo"></div></body></html>'`
344+
345+This runs the sail expression `;div.foo;` through the `%elem` mark, then
346+through the `%html` mark. The `/~` rune produces an item of mark `noun`. The
347+`%elem` mark converts the mark of the expression from `noun` to `elem` by
348+checking that the type fits in `manx` (a hoon/sail type indicating an XML
349+element). The `%html` mark recognizes the `%elem` and converts it to an HTML
350+string with enclosing `<html>`, `<head>`, and `<body>` tags.
351+
352+It's possible to use wide-form `/&` with more than two marks, by using `&` as a
353+delimiter between marks and adding a `/` before the last mark, like:
354+`/&d&c&b&/a/`. The last argument here can actually be any arbitrary horn, not
355+just a mark: `/&c&b&/:path:/mark/`
356+
357+Tall-form `/&` takes only two arguments: a mark and a horn. The mark does not
358+need to be enclosed in `/`'s: `/& html /elem/`
359+
360+### `/|` short-circuiting 'or'
361+
362+`/|` takes a series of horns and produces the first one (left-to-right) that
363+succeeds. If none succeed, it produces stack traces from all of its arguments.
364+
365+Example:
366+```
367+/= res /: /%/path/to/file
368+/|
369+ /!elem/
370+ /elem/
371+==
372+::
373+res
374+```
375+tries to parse the file at `/%/path/to/file` as a hoon expression and evaluate
376+it (`/!elem/`), and then if that fails, tries to convert the file to an HTML
377+element directly (`/elem/`). This is used in urbit's `tree` publishing system
378+to enable a user to place either a hoon file or a static file in a directory,
379+and have them both result in webpages, with preference given to treating the
380+file as hoon to be evaluated.
381+
382+Wide-form `/|` encloses its arguments in parentheses, with a single space as a delimiter:
383+`/|(/!elem/ /elem/)`
384+
385+### `/_` unfiltered: run a horn on each file in the current directory
386+
387+`/_` can be used in two ways: filtered and unfiltered.
388+
389+Unfiltered `/_` takes a horn as an argument. It produces a new horn representing the
390+result of mapping the supplied horn over the list of files in the current
391+directory. The keys in the resulting map are the basenames of the files in the
392+directory, and each value is the result of running that horn on the contents of
393+the file.
394+
395+Example:
396+```
397+/= kids /_ /hoon/
398+::
399+`(map term cord)`kids
400+```
401+
402+produces a value of type `(map term cord)`, where each key is the basename (the
403+filename without the prefix), and each value is the result of running the
404+contents of the file through the `%hoon` mark, which validates that it's valid
405+hoon code and returns it unmodified. So, the resulting map associates basenames
406+with file contents.
407+
408+Wide-form unfiltered `/_` doesn't need a delimiter: `/= kids /_/hoon/`
409+
410+### `/_` filtered: run a horn on each file in the directory matching an aura
411+
412+Filtered `/_` takes an aura and a horn, and filters the list of files in the
413+current directory by whether their filenames can be parsed to an atom of that
414+aura. It then produces a map where each key is the filename after parsing into
415+that atom type, and each value is the result of running the horn on the
416+contents of that file.
417+
418+Example:
419+```
420+/= timed-posts /_ @da /md/
421+`(map @da @t)`timed-posts
422+```
423+produces a map from dates to cords. This product will only contain files whose
424+names are parsable into `@da` dates. The values are the file contents converted
425+to a cord of markdown-formatted text.
426+
427+Wide-form filtered `/_` uses `_` as a delimiter: `/= timed-posts /_@da_/md/`
428+
429+### `/;` operate on
430+
431+`/;` takes a twig and a horn. The twig should evaluate to a gate, which is then slammed
432+with the result of the horn as its sample.
433+
434+Example:
435+```
436+/= goo
437+ /; |=({a/@ b/@} +(b))
438+ /~ [a=0 b=1]
439+::
440+goo
441+```
442+
443+produces: `2`
444+
445+Here's a slightly more complex example with runes that use the filesystem:
446+```
447+/= file-length
448+ /; |=(a/@t (lent (crip a)))
449+ /: /%/path/to/hoon/file /hoon/
450+::
451+file-length
452+```
453+produces the number of bytes in the file "/%/path/to/hoon/file."
454+
455+### `/,` switch by path
456+
457+`/,` is a switch statement, which picks a branch to evaluate based on
458+whether the current path matches the path in the switch statement.
459+Takes a sequence of pairs of (path, horn) terminated by a `==`. No wide-form.
460+
461+Example:
462+```
463+/= just-right
464+ /: /===/right-path :: set path to /%/right-path
465+ /,
466+ /wrong-path /~ ~
467+ /another-wrong-path /~ ~
468+ /right-path /~ %evaluate-me :: only evaluate this horn
469+ ==
470+::
471+`@t`just-right
472+```
473+
474+produces: `'evaluate-me'`
475+
476+### `/.` list
477+
478+Produce a null-terminated list from a sequence of horns, terminated by a `==`. No wide-form.
479+
480+Example:
481+```
482+/= vanes
483+ /.
484+ /~ %ames
485+ /~ %behn
486+ /~ %clay
487+ /~ %dill
488+ /~ %eyre
489+ /~ %ford
490+ /~ %gall
491+ ==
492+::
493+vanes
494+```
495+produces: `[%ames %behn %clay %dill %eyre %ford %gall ~]`.
496+
497+### `/*` heterogeneous map
498+
499+_DEPRECATED_
500+TODO: remove
501+
502+### `/^` cast
503+
504+`/^` takes a mold and a horn, and casts the result of the horn to the mold.
505+
506+Example:
507+```
508+/= liz /^ (list @) :: cast to real list
509+ /~ ~[1 2 3] :: no 'i' or 't' faces
510+::
511+?< ?=($~ liz) :: prevent find-fork
512+i.liz
513+```
514+
515+produces: `1`
516+
517+Without the cast, we wouldn't be able to access the 'i' face of the list.
518+
519+Wide-form `/^` uses `^` as a delimiter: `/^(list @)^/~[1 2 3 ~]`
520+
521+### `/#` insert dephash
522+
523+`/#` takes a horn and produces a cell of the dependency
524+hash of the result of the horn, and the result itself.
525+
526+Example:
527+```
528+/= inline /^ {dep/@uvH txt/@t} /# /: /%/my-script /js/
529+::
530+;= ;script: (trip txt.inline) :: set script contents
531+ ;script@"/~/on/{<dep.inline>}.js"; :: set script src
532+==
533+```
534+produces two `<script>` tags. The first has its contents set to the contents
535+of the JavaScript file we loaded from clay. The second is an auto-update
536+script that polls the server to check whether the dependency hash has changed.
537+This pattern is used in urbit's `tree` web publishing system.
538+
539+Wide-form `/#` does not need a delimiter:
540+`/= inline /^ {dep/@uvH txt/@t} /#/:/%/my-script:/js/`
541+
542+### `/$` process extra arguments
543+
544+`/$` will slam a gate on whatever extra arguments have been supplied to this build.
545+At the moment, only HTTP requests forwarded by `%eyre` contain any extra arguments,
546+and using this rune outside of that context will cause an error. Requests from `%eyre`
547+contain an argument representing the query string, which can be parsed using the
548+standard library gate `++fuel`.
549+
550+Example:
551+```
552+/= gas /$ fuel
553+::
554+:*
555+ %who {<(~(get ju aut.ced.gas) 0)>}
556+ %where {(spud s.bem.gas)}
557+ %case {(scow %ud p.r.bem.gas)}
558+==
559+```
560+produces: [%who '~zod' %where /ford/pages/web %case 60]
561+
562+Wide-form `/$` takes its arguments inside brackets, like `/~`:
563+`/=gas=/$[fuel]`
564+
565+### `/%` propagate extra arguments into renderers
566+
567+`/%` will forward extra arguments (usually from `%eyre`) on to any enclosed `/renderer/`'s. Without this,
568+renderers that use `/$` to read the extra arguments will crash.
569+
570+Example:
571+```
572+/= dat /% /tree-json/
573+::
574+dat
575+```
576+produces the results of running `ren/tree-json` on the current path. This renderer needs the query string,
577+which is one of the extra arguments passed in from `%eyre`.
578+
579+Wide-form `/%` has no delimiter: `/%/tree-json/`
learn/arvo/arvo-internals/ford/runes.udondeleted−473
@@ -1,473 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− sort/'2'
4− title/'Ford User Manual'
5− ==
6−;>
7−
8−# Ford User Manual
9−
10−## ford runes
11−
12−One of the most common ways to use ford is through ford's runes, all of which begin with `/` ("net"). A ford rune runs a step of a ford build and places the result in the subject. There are various kinds of build steps, some of which take other build steps as parameters. The most common pattern is to have a sequence of ford runes at the top of a hoon source file that import the results of evaluating other hoon files. This is how we "import a library" in urbit: we add the result of compiling another hoon file into the current subject, possibly renaming it by wrapping a face around it.
13−
14−Another common use case is assembling and rendering markdown templates into a single HTML file, to be sent as an HTTP response in urbit's web server `%eyre`. It's important to keep in mind that %ford is quite flexible and generic, and is used in other parts of urbit -- such as the dojo -- that would not traditionally fall under the purview of a build system.
15−
16−### `/+` import from lib/
17−
18−The `/+` rune accepts a filename as an argument. It interprets that filename
19−as a hoon source file within the `lib` directory. This is how we import a shared
20−library in urbit.
21−
22−To run this example, put this code in your desk at `gen/faslus.hoon` and run
23−`+faslus` in your dojo. This example is a generator. For more information on
24−generators, see the [generator docs](https://urbit.org/docs/arvo/generators).
25−
26−```
27−/+ time-to-id
28−::
29−:- %say
30−|= {{now/@da * *} $~ $~}
31−:- %noun
32−(time-to-id now)
33−```
34−
35−produces: `"c.314d"` (or something similar depending on when you run it)
36−
37−You can import multiple libraries with a single `/+` rune by separating them
38−with commas.
39−
40−Replace the code in `gen/faslus.hoon` with the following:
41−
42−```
43−/+ time-to-id, hep-to-cab
44−::
45−:- %say
46−|= {{now/@da * *} $~ $~}
47−:- %noun
48−=/ id (time-to-id now)
49−=/ str "my-id-is-{id}"
50−(hep-to-cab (crip str))
51−```
52−
53−This should print something like `my_id_is_c.3588`.
54−
55−Another feature of the
56−`/+ and`/-`runes is the ability to specify the`ship`and`case\` from which to
57−load the library.
58−
59−Example:
60−
61−```
62−/+ time-to-id, hep-to-cab/4/~zod
63−```
64−
65−will load the `hep-to-cab` library from `~zod` at `%clay` revision `4`.
66−
67−### `/-` import from sur/
68−
69−The `/-` rune accepts a filename as an argument. It interprets that filename as
70−a hoon source file within the `sur` directory. The `sur` directory contains
71−shared structures that can be used by other parts of urbit. This is somewhat
72−similar to including a header file in C.
73−
74−Example:
75−
76−```
77−/- talk
78−::
79−*serial:talk
80−```
81−
82−produces: `0v0`
83−
84−`/-` can also take multiple files as arguments, and the ship and case of those
85−arguments can be specified. See the `/+` docs for more details about the syntax
86−for those features.
87−
88−### `/~` twig by hand
89−
90−`/~ <twig>` produces a "horn" that evaluates a twig and places the product in
91−the subject. Arbitrary hoon can be in the twig. A
92−[horn](https://urbit.org/docs/arvo/internals/ford/commentary/#-horn) is a data
93−structure representing a `%ford` static resource.
94−
95−Example:
96−
97−```
98−/~ [a=0 b=1]
99−[a b]
100−```
101−
102−produces: `[0 1]`
103−
104−In wide-form, `/~` always takes a tuple (which may be a degenerate tuple of one element), and produces it.
105−
106−Example:
107−```
108−/~[%something]
109−```
110−produces: `%something`
111−
112−```
113−/~[%a %b]
114−```
115−produces: `[%a %b]`
116−
117−### `//` include a file by relative path
118−
119−`// <rel-path>` parses `rel-path` as a hoon twig, and then adds the resulting
120−twig to the subject. Note that the result type of this rune is not a horn, but
121−just a hoon twig, so its result can't be used as an argument to other runes
122−that expect a horn. There is no wide-form for this rune.
123−
124−Example:
125−```
126−// %/file-to-include
127−::
128−(frobnicate:file-to-include %.n)
129−
130−:: contents of file-to-include.hoon
131−|%
132−++ frobnicate
133− |= a/? ^+ a
134− !a
135−--
136−```
137−produces: `%.y`
138−
139−_Note: `%` means current directory, which in a hoon file will resolve to the
140−"directory" containing that file. Also, %clay doesn't have first-class
141−directories the way unix filesystems do. Whereas in unix, a directory is a
142−special kind of file, in %clay it's just a path prefix, and there is no file
143−stored at that path._
144−
145−### `/=` wrap a face around an included horn
146−
147−`/=` runs a horn (usually produced by another ford rune), takes the result of
148−that horn, and wraps a face around it.
149−
150−Example:
151−```
152−/= foo /~ [a=0 b=1]
153−::
154−[a.foo b.foo]
155−```
156−produces: `[0 1]`
157−
158−In wide-form, `/=` uses `=` as a delimiter: `/=foo=/~[a=0 b=1]`
159−
160−### `/:` evaluate at path, and `/<mark>/` render mark at current path
161−
162−`/:` takes a path and a horn, and evaluates the horn with the current path set to the supplied path.
163−`/mar/` renders the mark 'mar' at the current path.
164−
165−Example:
166−```
167−/= hoo-source /: /path/to/hoon-file /hoon/
168−::
169−`@t`hoo-source
170−```
171−
172−produces the text of the hoon file at "/path/to/hoon-file/hoon".
173−
174−`/hoon/` renders the current path using the `%hoon` mark, which in this case
175−passes the contents through unchanged. In general, rendering a file with a
176−mark will potentially run the contents through a series of conversion
177−operations. For details on marks, see the
178−[marks docs](https://urbit.org/docs/arvo/marks).
179−
180−Here's an example that includes a mark conversion:
181−```
182−/= page /: /path/to/html/file /mime/
183−::
184−page
185−
186−:: contents of /path/to/html/file:
187−<html><head><title>My Fascinating Blog</title></head></html>
188−```
189−produces:
190−`[[%text %html ~] 60 '<html><head><title>My Fascinating Blog</title></head></html>']`
191−
192−This result includes the MIME type ('text/html'), the content length in bytes,
193−and the HTML itself.
194−
195−In wide-form, `/:` uses `:` as a delimiter: `/=page=/:/path/to/html/file:/mime/`
196−
197−### `/!mark/` evaluate as hoon, then pass through mark
198−
199−Example:
200−```
201−/= mime /: /%/some-hoon-file /!mime/
202−::
203−mime
204−
205−:: contents of /%/some-hoon-file:
206−%produces-a-cord
207−```
208−produces: `[[%text %plain ~] 15 'produces-a-cord']`
209−
210−### `/&` pass through a series of marks
211−
212−`/&` passes a horn through multiple marks, right-to-left. It has both a
213−wide-form and a tall-form syntax. In wide-form, it takes a series of mark
214−arguments followed by a horn. In tall-form, it takes a single mark followed by
215−a horn.
216−
217−```
218−/= some-text /: /%/text-file /&mime&/txt/
219−::
220−some-text
221−```
222−produces: `[[%text %plain ~] p=17 q='Hi I\'m some text\0a']`
223−
224−This example shows two of the ways marks are used. The first way is what
225−happens with the `/txt/` mark: we use it to find a file in clay with that
226−extension, without performing any conversions. Since this file is stored with
227−the `%txt` mark in `%clay`, its type is a `wain`: a list of cords, where each
228−cord is a single line. Once we've read the file, the `%mime` mark converts the
229−`wain` to a triple that includes the MIME type ("text/plain"), the content
230−length in bytes, and the content itself as a cord.
231−
232−```
233−/= page /&html&elem&/~[;div.foo;]
234−::
235−page
236−```
237−produces: `'<html><head></head><body><div class="foo"></div></body></html>'`
238−
239−This runs the sail expression `;div.foo;` through the `%elem` mark, then
240−through the `%html` mark. The `/~` rune produces an item of mark `noun`. The
241−`%elem` mark converts the mark of the expression from `noun` to `elem` by
242−checking that the type fits in `manx` (a hoon/sail type indicating an XML
243−element). The `%html` mark recognizes the `%elem` and converts it to an HTML
244−string with enclosing `<html>`, `<head>`, and `<body>` tags.
245−
246−It's possible to use wide-form `/&` with more than two marks, by using `&` as a
247−delimiter between marks and adding a `/` before the last mark, like:
248−`/&d&c&b&/a/`. The last argument here can actually be any arbitrary horn, not
249−just a mark: `/&c&b&/:path:/mark/`
250−
251−Tall-form `/&` takes only two arguments: a mark and a horn. The mark does not
252−need to be enclosed in `/`'s: `/& html /elem/`
253−
254−### `/|` short-circuiting 'or'
255−
256−`/|` takes a series of horns and produces the first one (left-to-right) that
257−succeeds. If none succeed, it produces stack traces from all of its arguments.
258−
259−Example:
260−```
261−/= res /: /%/path/to/file
262−/|
263− /!elem/
264− /elem/
265−==
266−::
267−res
268−```
269−tries to parse the file at `/%/path/to/file` as a hoon expression and evaluate
270−it (`/!elem/`), and then if that fails, tries to convert the file to an HTML
271−element directly (`/elem/`). This is used in urbit's `tree` publishing system
272−to enable a user to place either a hoon file or a static file in a directory,
273−and have them both result in webpages, with preference given to treating the
274−file as hoon to be evaluated.
275−
276−Wide-form `/|` encloses its arguments in parentheses, with a single space as a delimiter:
277−`/|(/!elem/ /elem/)`
278−
279−### `/_` unfiltered: run a horn on each file in the current directory
280−
281−`/_` can be used in two ways: filtered and unfiltered.
282−
283−Unfiltered `/_` takes a horn as an argument. It produces a new horn representing the
284−result of mapping the supplied horn over the list of files in the current
285−directory. The keys in the resulting map are the basenames of the files in the
286−directory, and each value is the result of running that horn on the contents of
287−the file.
288−
289−Example:
290−```
291−/= kids /_ /hoon/
292−::
293−`(map term cord)`kids
294−```
295−
296−produces a value of type `(map term cord)`, where each key is the basename (the
297−filename without the prefix), and each value is the result of running the
298−contents of the file through the `%hoon` mark, which validates that it's valid
299−hoon code and returns it unmodified. So, the resulting map associates basenames
300−with file contents.
301−
302−Wide-form unfiltered `/_` doesn't need a delimiter: `/= kids /_/hoon/`
303−
304−### `/_` filtered: run a horn on each file in the directory matching an aura
305−
306−Filtered `/_` takes an aura and a horn, and filters the list of files in the
307−current directory by whether their filenames can be parsed to an atom of that
308−aura. It then produces a map where each key is the filename after parsing into
309−that atom type, and each value is the result of running the horn on the
310−contents of that file.
311−
312−Example:
313−```
314−/= timed-posts /_ @da /md/
315−`(map @da @t)`timed-posts
316−```
317−produces a map from dates to cords. This product will only contain files whose
318−names are parsable into `@da` dates. The values are the file contents converted
319−to a cord of markdown-formatted text.
320−
321−Wide-form filtered `/_` uses `_` as a delimiter: `/= timed-posts /_@da_/md/`
322−
323−### `/;` operate on
324−
325−`/;` takes a twig and a horn. The twig should evaluate to a gate, which is then slammed
326−with the result of the horn as its sample.
327−
328−Example:
329−```
330−/= goo
331− /; |=({a/@ b/@} +(b))
332− /~ [a=0 b=1]
333−::
334−goo
335−```
336−
337−produces: `2`
338−
339−Here's a slightly more complex example with runes that use the filesystem:
340−```
341−/= file-length
342− /; |=(a/@t (lent (crip a)))
343− /: /%/path/to/hoon/file /hoon/
344−::
345−file-length
346−```
347−produces the number of bytes in the file "/%/path/to/hoon/file."
348−
349−### `/,` switch by path
350−
351−`/,` is a switch statement, which picks a branch to evaluate based on
352−whether the current path matches the path in the switch statement.
353−Takes a sequence of pairs of (path, horn) terminated by a `==`. No wide-form.
354−
355−Example:
356−```
357−/= just-right
358− /: /===/right-path :: set path to /%/right-path
359− /,
360− /wrong-path /~ ~
361− /another-wrong-path /~ ~
362− /right-path /~ %evaluate-me :: only evaluate this horn
363− ==
364−::
365−`@t`just-right
366−```
367−
368−produces: `'evaluate-me'`
369−
370−### `/.` list
371−
372−Produce a null-terminated list from a sequence of horns, terminated by a `==`. No wide-form.
373−
374−Example:
375−```
376−/= vanes
377− /.
378− /~ %ames
379− /~ %behn
380− /~ %clay
381− /~ %dill
382− /~ %eyre
383− /~ %ford
384− /~ %gall
385− ==
386−::
387−vanes
388−```
389−produces: `[%ames %behn %clay %dill %eyre %ford %gall ~]`.
390−
391−### `/*` heterogeneous map
392−
393−_DEPRECATED_
394−TODO: remove
395−
396−### `/^` cast
397−
398−`/^` takes a mold and a horn, and casts the result of the horn to the mold.
399−
400−Example:
401−```
402−/= liz /^ (list @) :: cast to real list
403− /~ ~[1 2 3] :: no 'i' or 't' faces
404−::
405−?< ?=($~ liz) :: prevent find-fork
406−i.liz
407−```
408−
409−produces: `1`
410−
411−Without the cast, we wouldn't be able to access the 'i' face of the list.
412−
413−Wide-form `/^` uses `^` as a delimiter: `/^(list @)^/~[1 2 3 ~]`
414−
415−### `/#` insert dephash
416−
417−`/#` takes a horn and produces a cell of the dependency
418−hash of the result of the horn, and the result itself.
419−
420−Example:
421−```
422−/= inline /^ {dep/@uvH txt/@t} /# /: /%/my-script /js/
423−::
424−;= ;script: (trip txt.inline) :: set script contents
425− ;script@"/~/on/{<dep.inline>}.js"; :: set script src
426−==
427−```
428−produces two `<script>` tags. The first has its contents set to the contents
429−of the JavaScript file we loaded from clay. The second is an auto-update
430−script that polls the server to check whether the dependency hash has changed.
431−This pattern is used in urbit's `tree` web publishing system.
432−
433−Wide-form `/#` does not need a delimiter:
434−`/= inline /^ {dep/@uvH txt/@t} /#/:/%/my-script:/js/`
435−
436−### `/$` process extra arguments
437−
438−`/$` will slam a gate on whatever extra arguments have been supplied to this build.
439−At the moment, only HTTP requests forwarded by `%eyre` contain any extra arguments,
440−and using this rune outside of that context will cause an error. Requests from `%eyre`
441−contain an argument representing the query string, which can be parsed using the
442−standard library gate `++fuel`.
443−
444−Example:
445−```
446−/= gas /$ fuel
447−::
448−:*
449− %who {<(~(get ju aut.ced.gas) 0)>}
450− %where {(spud s.bem.gas)}
451− %case {(scow %ud p.r.bem.gas)}
452−==
453−```
454−produces: [%who '~zod' %where /ford/pages/web %case 60]
455−
456−Wide-form `/$` takes its arguments inside brackets, like `/~`:
457−`/=gas=/$[fuel]`
458−
459−### `/%` propagate extra arguments into renderers
460−
461−`/%` will forward extra arguments (usually from `%eyre`) on to any enclosed `/renderer/`'s. Without this,
462−renderers that use `/$` to read the extra arguments will crash.
463−
464−Example:
465−```
466−/= dat /% /tree-json/
467−::
468−dat
469−```
470−produces the results of running `ren/tree-json` on the current path. This renderer needs the query string,
471−which is one of the extra arguments passed in from `%eyre`.
472−
473−Wide-form `/%` has no delimiter: `/%/tree-json/`
learn/arvo/arvo-internals/gall.udon+2344−1
@@ -14,4 +14,2347 @@ This is documentation about how to write Gall apps. Some knowledge of Hoon is a
1414 always accessible enough to beginners. We are planning to rewrite these in the
1515 near future. There is still useful information to be found in the meantime.
1616
17−;list;
17+;=
18+ ;h2
19+ ;div(id "api"): API Connectors
20+ ==
21+==
22+
23+> Note: This lesson depends on some code that needs to be updated before the examples will work correctly. This will be addressed in the near future. We apologize!
24+
25+Most people have lots of data stored in online services, many of
26+which have APIs. API connectors allow the user to access this
27+data from within their Urbit.
28+
29+A security driver allows the user to make authenticated requests
30+to the service's API, but the user still needs to know the API
31+and send and receive JSON. An API connector puts a layer of
32+porcelain over this to allow the user easier control over their
33+data.
34+
35+Each connector should perform two basic functions. First, it
36+should expose a tree of the data in the service that's accessible
37+through `.^` and FUSE. Second, it should expose event streams as
38+actions occur in the service. Let's take a look at how the `%gh`
39+app accomplishes both for Github.
40+
41+After starting `%gh` (`|start %gh`), let's look at the root of
42+the tree that `%gh` exposes:
43+
44+```
45+~your-urbit:dojo> .^(arch %gy /=gh=)
46+[fil=~ dir={[p=~.issues q=~]}]
47+```
48+
49+`%gh` is currently a skeleton -- it contains examples of all the
50+functionality necessary for a connector, but many endpoints
51+aren't implemented. As we can see here, only issues are
52+implemented. We can explore this tree:
53+
54+```
55+~your-urbit:dojo> .^(arch %gy /=gh=/issues)
56+[fil=~ dir={[p=~.by-repo q=~] [p=~.mine q=~]}]
57+```
58+
59+And eventually:
60+
61+```
62+/- gh
63+.^(issue:gh %gx /=gh=/issues/by-repo/philipcmonktest/testing/7)
64+<issue...>
65+login.user:.^(issue:gh %gx /=gh=/issues/by-repo/philipcmonktest/testing/7)
66+'philipcmonktest'
67+```
68+
69+The other thing an API connector needs to do is expose event
70+streams. One straightforward way to use this capacity is with
71+the `:pipe` app:
72+
73+```
74+:pipe|connect %gh /listen/philipcmonktest/testing/issues/'issue_comment' %public
75+```
76+
77+Now creating an issue results in the following message in your
78+`%public` `:talk` channel:
79+
80+```
81+~your-urbit[philipcmonktest@github]: opened issue ##11: i found a bug!
82+```
83+
84+You'll also get notifications of issue status changes and
85+comments.
86+
87+As is often the case, the best way to write an API connector is
88+to copy an existing one and modify it. We'll dissect the Github
89+connector here. This code is in `/=home=/app/gh/hoon`, and it's
90+also reproduced at the bottom of this page (in case the code
91+drifts out of sync with this doc).
92+
93+We'll go over the two parts to an API connector (one-time reading vs listening
94+for events) separately.
95+
96+#### Reading
97+
98+A connector exposes a tree of data. Every read request has a
99+`care`, which is generally either `%x` or `%y. `%x` is a request
100+for a particular piece of data, while `%y` is a request for a
101+directory listing. Roughly, `%x` means Unix `cat` and `%y` means
102+Unix `ls`.
103+
104+> Sometimes you wish to expose a tree where a part of the path can't be enumerated. For example, a `%y` of `/issues/by-repo` "should" produce a list of all Github users, but we don't do that because it's too long. Instead, we just produce our own username (from the `web.plan` file). You can still access repos from other users, you just don't see them in the directory listing.
105+
106+The usual flow for implementing this tree of data makes heavy use
107+of the `connector` library. This library is well documented in
108+the source, so check out `/=home=/lib/connector/hoon`.
109+
110+The `connector` library needs to be initialized with definitions
111+of `move` and `sub-result` (all the types of data that can be
112+returned by a place). This can just be a line at the top of the
113+main core:
114+
115+```
116+=+ connector=(connector move sub-result) :: Set up connector library
117+```
118+
119+Most of the Github-specific logic is in `++places`, which is a
120+list of all the places we can request. A place consists of:
121+
122+```
123+++ place
124+ $: guard/mold
125+ read-x/$-(path move)
126+ read-y/$-(path move)
127+ sigh-x/$-(jon/json (unit sub-result))
128+ sigh-y/$-(jon/json (unit arch))
129+ ==
130+```
131+
132+- `guard`, the type of the paths we should match. For example, to match `/issues/<user>/<repo>` use `{$issues @t @t $~}`.
133+
134+- `read-x`, called when someone tries to read the place with `care` `%x`. Should produce a single move, usually either a `%diff` response if we can immediately answer or a `%hiss` http request if we need to make a request to the api. See the `++read-*` functions in `++helpers` for some common handlers.
135+
136+- `read-y`, same as `read-x` except with care `%y`.
137+
138+- `sigh-x`, called when an http response comes back on this place. You're given the json of the result, and you should produce either a result or null. Null represents an error. If you didn't create an http request in `read-x`, then this should never be called. Use `++sigh-strange` from `++helpers` to unconditionally signal an error.
139+
140+- `sigh-y`, same as `sigh-x` except with care `%y`. Note that a `%y` request must produce an arch, unlike a `%x` request, which may produce data of any mark.
141+
142+Filling out the list of places is a lot of grunt work, but most
143+places are fairly straightforward, and the `++read-*` helper
144+functions are useful. Check out the library source for more
145+information on those.
146+
147+Besides the list of places, we just need to handle the flow of
148+control. `++peek` and `++peer-scry` are the interface we expose
149+to the rest of the system while `++sigh-httr` and `++sigh-tang`
150+are used to handle responses when we make HTTP requests.
151+
152+- `++peek` should usually just produce `~`. If there are cases where we can respond directly to a `.^` request without blocking on anything, we could do it here, but it's generally not worth the hassle since the same logic should be duplicated in `++peer-scry`.
153+
154+- `++peer-scry` is where the actual handling for a read request goes. In general, we just need to call `++read` from the `connector` library with the bone, list of places, care, and path. This will match the path to the appropriate place and run either `++read-x` or `++read-y`, depending on the care.
155+
156+- If `++read-x` or `++read-y` made a successful API request, then the response will come back on `++sigh-httr`. Here, we just need to parse out the wire and call `++sigh` from the `connector` library with the list of places, care, path, and HTTP result. This will match the path to the appropriate place and run either `++sigh-x` or `++sigh-y`, depending on the care.
157+
158+- If `++read-x` or `++read-y` made an API request that failed, then we'll get a stack trace in `++sigh-tang`. Here, we just print it out and move on.
159+
160+That's really all there is to the reading portion of API
161+connectors.
162+
163+One of the most accessible ways to jump into Arvo programming is
164+to just add more places to an existing API connector. It's
165+useful, small in scope, and comes in bite-sized chunks since most
166+places are less than ten lines of code.
167+
168+#### Listening
169+
170+Listening for events is fairly service-specific. In some
171+services, we poll for changes. The Twitter connector has an
172+example of this, but note that it predates the `connector`
173+library and is thus more complicated than it needs to be, and the
174+interface it exposes isn't standard. In Github, we power our
175+event streams with webhooks.
176+
177+For Github, when someone subscribes to
178+`/listen/<user>/<repo>/<events...>`, we want to produce
179+well-typed results when they occur.
180+
181+We only want to create one webhook per event, so in our state we
182+have `hook`, which is a map of event names to the set of bones
183+which are subscribed to that event. We must always keep this
184+up-to-date.
185+
186+Flow of control starts in `++peer-listen`, where we just call
187+`++listen`. In `++listen`, for each event in the list of events,
188+we check to see if we have that hook set up (by checking whether
189+it exists in `hook`). If so, we call `++update-hook` to add the
190+current bone to the set of listeners. Otherwise, we call
191+`++create-hook`, which sends a request to Github to set up the
192+new webhook. We also create an entry in `hook` with the current
193+bone.
194+
195+When we created the webhook, we told Github to send the event to
196+`/~/to/gh/gh-<event>.json?anon&wire=/`. This turns into a poke.
197+Let's parse out this url. The first `gh` is the app name to
198+poke. The next portion, `gh-<event>` is the mark to convert the
199+JSON to. For example, when the "issues" event fires, it'll get
200+converted to mark `gh-issues`. This mark has a conversion
201+routine from `json` to the `issues` type, which is defined in the
202+`gh` structure (`/=home=/sur/gh/hoon`). Once this conversion
203+happens, the `gh` app will get poked with the correctly marked
204+data in `++poke`.
205+
206+In `++poke`, we check `hook` to find the subscribers to the event
207+that was fired, and we update them.
208+
209+That's really all there is to it. Webhook flow isn't well
210+standardized, so even if your chosen service is powered by
211+webhooks, your listening code might look rather different. The
212+point is to expose the correct interface.
213+
214+
215+#### Github API Connector Code
216+
217+In case the code in `/=home=/app/gh/hoon` drifts out of sync with
218+this doc:
219+
220+```
221+:: This is a connector for the Github API v3.
222+::
223+:: You can interact with this in a few different ways:
224+::
225+:: - .^({type} %gx /=gh={/endpoint}) to read data or
226+:: .^(arch %gy /=gh={/endpoint}) to explore the possible
227+:: endpoints.
228+::
229+:: - subscribe to /listen/{owner}/{repo}/{events...} for
230+:: webhook-powered event notifications. For event list, see
231+:: https://developer.github.com/webhooks/.
232+::
233+:: This is written with the standard structure for api
234+:: connectors, as described in lib/connector.hoon.
235+::
236+/? 314
237+/- gh, plan-acct
238+/+ gh-parse, connector
239+::
240+!:
241+=> |%
242+ +$ move (pair bone card)
243+ +$ card
244+ $% [%diff sub-result]
245+ [%them wire (unit hiss:eyre)]
246+ [%hiss wire [%~ %~] %httr [%hiss hiss:eyre]]
247+ ==
248+ ::
249+ :: Types of results we produce to subscribers.
250+ ::
251+ +$ sub-result
252+ $% [%arch arch]
253+ [%gh-issue issue:gh]
254+ [%gh-list-issues (list issue:gh)]
255+ [%gh-issues issues:gh]
256+ [%gh-issue-comment issue-comment:gh]
257+ [%json json]
258+ [%null %~]
259+ ==
260+ ::
261+ :: Types of webhooks we expect.
262+ ::
263+ +$ hook-response
264+ $% [%gh-issues issues:gh]
265+ [%gh-issue-comment issue-comment:gh]
266+ ==
267+ --
268+=+ connector=(connector move sub-result) :: Set up connector library
269+::
270+|_ $: hid=bowl:gall
271+ hook=(map @t [id=@t listeners=(set bone)]) :: map events to listeners
272+ ==
273+:: ++ prep _`. :: Clear state when code changes
274+::
275+:: List of endpoints
276+::
277+++ places
278+ |= wir=wire
279+ ^- (list place:connector)
280+ =+ (helpers:connector ost.hid wir "https://api.github.com")
281+ => |% :: gh-specific helpers
282+ ++ sigh-list-issues-x
283+ |= jon=json
284+ %+ bind ((ar:jo issue:gh-parse) jon)
285+ |= issues=(list issue:gh)
286+ gh-list-issues+issues
287+ ::
288+ ++ sigh-list-issues-y
289+ |= jon=json
290+ %+ bind ((ar:jo issue:gh-parse) jon)
291+ |= issues=(list issue:gh)
292+ :- `(shax (jam issues))
293+ (malt (turn issues |=(issue:gh [(rsh 3 2 (scot %ui number)) ~])))
294+ --
295+ :~ ^- place :: /
296+ :* guard=,%~
297+ read-x=read-null
298+ read-y=(read-static %issues ~)
299+ sigh-x=sigh-strange
300+ sigh-y=sigh-strange
301+ ==
302+ ^- place :: /issues
303+ :* guard=,[%issues %~]
304+ read-x=read-null
305+ read-y=(read-static %mine %by-repo ~)
306+ sigh-x=sigh-strange
307+ sigh-y=sigh-strange
308+ ==
309+ ^- place :: /issues/mine
310+ :* guard=,[%issues %mine %~]
311+ read-x=(read-get /issues)
312+ read-y=(read-get /issues)
313+ sigh-x=sigh-list-issues-x
314+ sigh-y=sigh-list-issues-y
315+ ==
316+ ^- place :: /issues/by-repo
317+ :* guard=,[%issues %by-repo %~]
318+ read-x=read-null
319+ ^= read-y
320+ |= pax=path
321+ =+ /(scot %p our.hid)/home/(scot %da now.hid)/web/plan
322+ =+ .^([* acc=(map knot plan-acct)] %cx -)
323+ ::
324+ ((read-static usr:(~(got by acc) %github) ~) pax)
325+ sigh-x=sigh-strange
326+ sigh-y=sigh-strange
327+ ==
328+ ^- place :: /issues/by-repo/<user>
329+ :* guard=,[%issues %by-repo @t %~]
330+ read-x=read-null
331+ read-y=|=(pax=path (get /users/[-.+>.pax]/repos))
332+ sigh-x=sigh-strange
333+ ^= sigh-y
334+ |= jon=json
335+ %+ bind ((ar:jo repository:gh-parse) jon)
336+ |= repos=(list repository:gh)
337+ [~ (malt (turn repos |=(repository:gh [name ~])))]
338+ ==
339+ ^- place :: /issues/by-repo/<user>/<repo>
340+ :* guard=,[%issues %by-repo @t @t %~]
341+ read-x=|=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues))
342+ read-y=|=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues))
343+ sigh-x=sigh-list-issues-x
344+ sigh-y=sigh-list-issues-y
345+ ==
346+ ^- place :: /issues/by-repo/<user>/<repo>
347+ :* guard=,[%issues %by-repo @t @t @t %~]
348+ ^= read-x
349+ |=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues/[-.+>+>.pax]))
350+ ::
351+ read-y=(read-static ~)
352+ ^= sigh-x
353+ |= jon=json
354+ %+ bind (issue:gh-parse jon)
355+ |= issue=issue:gh
356+ gh-issue+issue
357+ ::
358+ sigh-y=sigh-strange
359+ ==
360+ ==
361+::
362+:: When a peek on a path blocks, ford turns it into a peer on
363+:: /scry/{care}/{path}. You can also just peer to this
364+:: directly.
365+::
366+:: We hand control to ++scry.
367+::
368+++ peer-scry
369+ |= pax=path
370+ ^- [(list move) _+>.$]
371+ ?> ?=([care:clay *] pax)
372+ :_ +>.$ :_ ~
373+ (read:connector ost.hid (places %read pax) i.pax t.pax)
374+::
375+:: HTTP response. We make sure the response is good, then
376+:: produce the result (as JSON) to whoever sent the request.
377+::
378+++ sigh-httr
379+ |= [way=wire res=httr:eyre]
380+ ^- [(list move) _+>.$]
381+ ?. ?=([%read care:clay @ *] way)
382+ ~& res=res
383+ [~ +>.$]
384+ =* style i.way
385+ =* ren i.t.way
386+ =* pax t.t.way
387+ :_ +>.$ :_ ~
388+ :+ ost.hid %diff
389+ (sigh:connector (places ren style pax) ren pax res)
390+::
391+:: HTTP error. We just print it out, though maybe we should
392+:: also produce a result so that the request doesn't hang?
393+::
394+++ sigh-tang
395+ |= [way=wire tan=tang]
396+ ^- [(list move) _+>.$]
397+ %- (slog >%gh-sigh-tang< tan)
398+ [[ost.hid %diff null+~]~ +>.$]
399+::
400+:: We can't actually give the response to pretty much anything
401+:: without blocking, so we just block unconditionally.
402+::
403+++ peek
404+ |= [ren=@tas tyl=path]
405+ ^- (unit (unit (pair mark *)))
406+ ~ ::``noun=[ren tyl]
407+::
408+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
409+:: Webhook-powered event streams (/listen) ::
410+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
411+::
412+:: To listen to a webhook-powered stream of events, subscribe
413+:: to /listen/<user>/<repo>/<events...>
414+::
415+:: We hand control to ++listen.
416+::
417+++ peer-listen
418+ |= pax=path
419+ ^- [(list move) _+>.$]
420+ ?. ?=([@ @ *] pax)
421+ ~& [%bad-listen-path pax]
422+ [~ +>.$]
423+ (listen pax)
424+::
425+:: This core handles event subscription requests by starting or
426+:: updating the webhook flow for each event.
427+::
428+++ listen
429+ |= pax=path
430+ =| mow=(list move)
431+ =< abet:listen
432+ |%
433+ ++ abet :: Resolve core.
434+ ^- [(list move) _+>.$]
435+ [(flop mow) +>.$]
436+ ::
437+ ++ send-hiss :: Send a hiss
438+ |= hiz=hiss:eyre
439+ ^+ +>
440+ =+ wir=`wire`[%x %listen pax]
441+ +>.$(mow [[ost.hid %hiss wir `~ %httr [%hiss hiz]] mow])
442+ ::
443+ :: Create or update a webhook to listen for a set of events.
444+ ::
445+ ++ listen
446+ ^+ .
447+ =+ pax=pax :: TMI-proofing
448+ ?> ?=([@ @ *] pax)
449+ =+ events=t.t.pax
450+ |- ^+ +>+.$
451+ ?~ events
452+ +>+.$
453+ ?: (~(has by hook) i.events)
454+ $(+>+ (update-hook i.events), events t.events)
455+ $(+>+ (create-hook i.events), events t.events)
456+ ::
457+ :: Set up a webhook.
458+ ::
459+ ++ create-hook
460+ |= event=@t
461+ ^+ +>
462+ ?> ?=([@ @ *] pax)
463+ =+ clean-event=`tape`(turn (trip event) |=(a=@tD ?:(=('_' a) '-' a)))
464+ =. hook
465+ %+ ~(put by hook) (crip clean-event)
466+ =+ %+ fall
467+ (~(get by hook) (crip clean-event))
468+ *[id=@t listeners=(set bone)]
469+ [id (~(put in listeners) ost.hid)]
470+ %- send-hiss
471+ :* %+ scan
472+ =+ [(trip i.pax) (trip i.t.pax)]
473+ "https://api.github.com/repos/{-<}/{->}/hooks"
474+ auri:de-purl:html
475+ %post ~ ~
476+ %- as-octs:mimes:html %- crip %- en-json:html %- pairs:enjs:format :~
477+ name+s+%web
478+ active+b+&
479+ events+a+~[s+event] ::(turn `(list ,@t)`t.t.pax |=(a=@t s=a))
480+ :- %config
481+ %- pairs:enjs:format :~
482+ =+ =+ clean-event
483+ "http://107.170.195.5:8443/~/to/gh/gh-{-}.json?anon&wire=/"
484+ [%url s+(crip -)]
485+ [%'content_type' s+%json]
486+ ==
487+ ==
488+ ==
489+ ::
490+ :: Add current bone to the list of subscribers for this event.
491+ ::
492+ ++ update-hook
493+ |= event=@t
494+ ^+ +>
495+ =+ hok=(~(got by hook) event)
496+ %_ +>.$
497+ hook
498+ %+ ~(put by hook) event
499+ hok(listeners (~(put in listeners.hok) ost.hid))
500+ ==
501+ --
502+::
503+:: Pokes that aren't caught in more specific arms are handled
504+:: here. These should be only from webhooks firing, so if we
505+:: get any mark that we shouldn't get from a webhook, we reject
506+:: it. Otherwise, we spam out the event to everyone who's
507+:: listening for that event.
508+::
509+++ poke
510+ |= response=hook-response
511+ ^- [(list move) _+>.$]
512+ =+ hook-data=(~(get by hook) (rsh 3 3 -.response))
513+ ?~ hook-data
514+ ~& [%strange-hook hook response]
515+ [~ +>.$]
516+ :: ~& response=response
517+ :_ +>.$
518+ %+ turn ~(tap in listeners.u.hook-data)
519+ |= ost=bone
520+ [ost %diff response]
521+--
522+```
523+
524+;=
525+ ;h2
526+ ;div(id "generators"): Generators
527+ ==
528+==
529+
530+Up until now we've poked apps directly. This requires the user to
531+specify the mark, and it requires the app to accept the arguments in a
532+way that's convenient for users to input. This is the "plumbing" way to
533+interact with apps. Generators are the "porcelain" layer. This is why
534+when you run a command like `+ls` or `|merge`, there are no marks in
535+sight.
536+
537+We've used generators before, back in [Basic
538+Operation](/docs/using/admin). At that point, we just used the
539+generators to produce values -- we didn't pipe their results into apps.
540+In the dojo cast, the role of a generator is to take a list of arguments
541+and produce a value, which is often, though not always, piped into an
542+app. Generators are pure, stateless functions, and they cannot send
543+moves.
544+
545+`+ls` and `+cat` are commonly-used generators that produce a directory
546+listing and print out a file, respectively. These are useful in
547+themselves, so we generally don't pipe the results into an app.
548+
549+Another generator is `+hood/merge`. Try running `+hood/merge` with the
550+normal arguments for `|merge`:
551+
552+```
553+> +hood/merge %home our %they
554+[syd=%home her=~zod sud=%they cas=[%da p=~2018.10.4..21.11.49..901c] gem=%auto]
555+
556+> +hood/merge %home our %they, =gem %this
557+[syd=%home her=~zod sud=%they cas=[%da p=~2018.10.4..21.12.11..ee32] gem=%this]
558+```
559+
560+This didn't run any merge, it just constructed the command that, if sent
561+to `:hood`, would run it. Note first that, even though it's not printed,
562+this value has mark `kiln-merge`. Also, the merge strategy `gem=%auto`
563+was added automatically. Optional arguments are straightforward with
564+generators.
565+
566+In general, generators are prepended by either `+` or `|`. The general
567+form is `+generator`, but often generators are created specifically to
568+work with a single app, they're usually placed in a subdirectory of gen
569+and run with `|`. Thus, if `my-generator` generator is made for use with
570+`:my-app`, then `my-generator` is put in
571+`/gen/my-app/my-generator.hoon`, and can be run directly with
572+`+my-app/my-generator <args>`. If you want to pipe the result into
573+`:my-app`, then run `:my-app +my-app/my-generator <args>`. Because this
574+pattern is so common, this can be abbreviated to
575+`:my-app|my-generator <args>`. Because most built-in commands are
576+generators for the `:hood` app, `:hood|generator <args>` can be
577+shortened to `|generator <args>`.
578+
579+Let's write a generator for a modified version of `:pong` from
580+the chapter on [Network Messages](/docs/arvo/system/network). Recall
581+that `:pong` takes an urbit address, which is of mark `urbit`,
582+and sends that urbit the message `'howdy'`. First--without a
583+generator--let's make `:ping` that does the same, except that
584+it lets the user optionally specify the message as well.
585+
586+We'll need a new mark for our arguments. Let's call it
587+`ping-message`.
588+
589+> For app-specific marks, it's good style to prefix the name of the mark with the name of the app. Since many apps have several such marks, subdirectories in `/mar` are rendered as `-`, so that `ping-message` is written in (/mar/ping/message.hoon).
590+
591+```
592+::
593+:::: /mar/ping/message/hoon
594+ ::
595+/? 314
596+|_ [to=@p message=@t]
597+++ grab
598+ |%
599+ +$ noun [@p @t]
600+ --
601+--
602+```
603+
604+The app can easily be modified to use this (`/app/ping.hoon`):
605+
606+```
607+:: Allows one ship to ping another with a string of text
608+::
609+:::: /app/ping/hoon
610+ ::
611+/? 314
612+|%
613+ +$ move [bone term wire *]
614+--
615+!:
616+|_ [bowl:gall state=%~]
617+::
618+++ poke-ping-message
619+ |= [to=@p message=@t]
620+ ~& 'sent'
621+ ^- [(list move) _+>.$]
622+ :- ^- (list move)
623+ :~ `move`[ost %poke /sending [to dap] %atom message]
624+ ==
625+ +>.$
626+::
627+++ poke-atom
628+ |= arg=@
629+ ~& 'received'
630+ ^- [(list move) _+>.$]
631+ ::
632+ ~& [%receiving (@t arg)]
633+ [~ +>.$]
634+::
635+++ coup |=(* `+>)
636+--
637+```
638+
639+Now we can run this with:
640+
641+```
642+~fintud-macrep:dojo> |start %ping
643+>=
644+
645+~fintud-macrep:dojo> :ping &ping-message [~sampel-sipnym 'heyya']
646+>=
647+```
648+
649+And on `~sampel-sipnym`, assuming it's running `:ping` as well,
650+we see `[%receiving 'heyya']`.
651+
652+This is an annoying way to invoke the app, though. The `[]` are
653+mandatory, and optional arguments are hard. Let's make a generator,
654+`+send` to make everything nicer. Since it's specific to
655+`:ping`, let's put it in `/gen/ping/send.hoon`:
656+
657+```
658+:- %say
659+|= [^ [to=@p message=?(%~ [text=@t %~])] %~]
660+[%ping-message to ?~(message 'howdy' text.message)]
661+```
662+
663+A couple of new things here. Firstly, `message=?(%~ [text=@t %~])] %~]`
664+should be read as "the message is either null or a pair of text and
665+null". Generator argument lists are always null-terminated, which makes
666+it convenient to accept lists in tail position (which are particularly
667+annoying without generators). `?(a b)` is the irregular form of
668+`$?(a b)`, which is a union type. Thus, `?(a b)` means the type of
669+anything that's in either `a` or `b`. Thus, in our case,
670+`?(~ [text=@t ~])` is either null or a pair of text and null.
671+
672+This is run as follows:
673+
674+```
675+~fintud-macrep:dojo> :ping|send ~sampel-sipnym
676+>=
677+
678+~fintud-macrep:dojo> :ping|send ~sampel-sipnym 'how do you do'
679+>=
680+```
681+
682+Which causes `~sampel-sipnym` to print `[%receiving 'howdy']` and
683+`[%receiving 'how do you do']`.
684+
685+(Note: `:ping|send ~sampel-sipnym` is short for `:ping +ping/send ~sampel-sipnym`.)
686+
687+*Exercises*:
688+
689+- Create a generator for `:sum` from [State](#state) so that you can run `:sum|add 5` to add numbers to it.
690+
691+- Create a generator for `:click` from [Web Apps](#backend) so that you can run `:click|poke` to poke it.
692+
693+
694+;=
695+ ;h2
696+ ;div(id "http"): Writing an HTTP Request
697+ ==
698+==
699+
700+There's a variety of arvo services we haven't touched on yet.
701+Let's figure out how to make HTTP requests and set timers.
702+
703+Let's build an uptime-monitoring system. It'll ping a web
704+service periodically and print out an error when the response
705+code isn't 2xx. Save the following as `app/up.hoon`:
706+
707+```
708+:: Up-ness monitor. Accepts atom url, 'on', or 'off'
709+::
710+:::: /hoon/up/app
711+ ::
712+/? 314
713+|%
714++$ move [bone card]
715++$ card
716+ $% [%hiss wire unit-iden=$~ mark=%httr cage=[mark=%purl vase=purl:eyre]]
717+ [%wait wire @da]
718+ ==
719++$ action
720+ $% [%on $~] :: enable polling('on')
721+ [%off $~] :: disable polling('off)
722+ [%target p=cord] :: set poll target('http://...')
723+ ==
724+--
725+|_ [hid=bowl:gall on=_| in-progress=_| target=@t]
726+++ poke-atom
727+ |= url-or-command=@t ^- (quip move _+>)
728+ =+ ^- act/action
729+ ?: ?=($on url-or-command) [%on ~]
730+ ?: ?=($off url-or-command) [%off ~]
731+ [%target url-or-command]
732+ ?- -.act
733+ $target [~ +>.$(target p.act)]
734+ $off [~ +>.$(on |)]
735+ $on
736+ :- ?: |(on in-progress) ~
737+ [ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]~
738+ +>.$(on &, in-progress &)
739+ ==
740+++ sigh-httr
741+ |= [wir=wire code=@ud headers=mess:eyre body=(unit octs)]
742+ ~& 'arrive here'
743+ ^- [(list move) _+>.$]
744+ ?: &((gte code 200) (lth code 300))
745+ ~& [%all-is-well code]
746+ :_ +>.$
747+ [ost.hid %wait /timer (add ~s10 now.hid)]~
748+ ~& [%we-have-a-problem code]
749+ ~& [%headers headers]
750+ ~& [%body body]
751+ :_ +>.$
752+ [ost.hid %wait /timer (add ~s10 now.hid)]~
753+++ wake-timer
754+ |= [wir=wire $~] ^- (quip move _+>)
755+ ?: on
756+ :_ +>.$
757+ [ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]~
758+ [~ +>.$(in-progress |)]
759+::
760+++ prep ~& target _`. :: computed when the source file changes;
761+-- :: here it prints target then resets our state
762+```
763+
764+There's some fancy stuff going on here. We'll go through it line by
765+line, though.
766+
767+There's two kinds of cards we're sending to arvo. A `%hiss` move tells
768+`%eyre` to make an HTTP request. It expects a `(unit iden)`, which will
769+be null here because we aren't doing any authentication; a mark, in this
770+case the http request mark `&httr`; and some data in the form of a
771+`cage`, which is a `[mark vase]`. This is confusing, so the mold in the
772+code quoted above includes a bunch of otherwise unnecessary faces for
773+the purpose of illustration. Compare: `[%hiss p=(unit iden) q=mark
774+r=cage]` from `zuse`.
775+
776+> You can grep zuse.hoon and arvo.hoon for most of these definitions. However, beware the ambiguity surrounding "hiss": there's ++hiss in section 3bI of `zuse` ("Arvo structures"), and there's `%hiss` the move that is sent to %eyre to make our HTTP request happen. Here we're talking about the latter. See `++kiss-eyre` in `zuse`.
777+
778+> Recall that `++unit` means "maybe". Formally, "`(unit a)` is either null or a pair of null and a value in `a`". Also recall that to pull a value out of a unit (`u.unit`), you must first verify that the unit is not null (for example with `?~`). See `++need`.
779+
780+A `purl:eyre` is a parsed url structure, which can be created with `de-purl:html`,
781+which is a function that takes a url as text and parses it into a `(unit
782+purl:eyre)`. Thus, the result is null if and only if the url is malformed.
783+'Purl' is also the mark which will be applied to this result.
784+
785+When you send this request, you can expect a `%sigh` with the
786+response, which we handle later on in `++sigh-httr`.
787+
788+For `%wait`, you just pass a [`@da`]() (absolute date), and arvo will
789+produce a `%wake` when the time comes.
790+
791+> A timer is guaranteed to not be triggered before the given time, but it's currently impossible to guarantee the timer will be triggered at exactly the requested time.
792+
793+Let's take a look at our state:
794+
795+```
796+|_ [hid=bowl:gall on=_| in-progress=_| target=@t]
797+```
798+
799+We have three pieces of app-specific state. `target` is the url
800+we're monitoring. `on` and `in-progress` are booleans
801+representing, respectively, whether or not we're supposed to keep
802+monitoring and whether or not we're in the middle of a request.
803+
804+The type of booleans is usually written as `?`, which is a union
805+of `&` (true) and `|` false. This type defaults to `&` (true). In our
806+case, we want both of these to default to `|` (false). Because
807+of that, we use `_|` as the type. `_value` means "take the type
808+of `value`, but make the default value be `value`". Thus, our
809+type is still a boolean, just like `?`, but the default value is
810+`|` (false).
811+
812+> This is the same `_` used in `_+>.$`, which means "the same type as the value "+>.$". In other words, the same type as our current context and state.
813+
814+Let's take a look at `++poke-atom`. When we're poked with an atom, we
815+first check whether the atom is `'off'`. If so, we set our state
816+variable `on` to false.
817+
818+If not, we check whether the atom is `'on'`. If so, we set `on` and
819+`in-progress` to true. If it was already either on or in progress, then
820+we don't take any other immediate action. If it was both off and not in
821+progress, then we send an HTTP request.
822+
823+If the argument is neither 'off' nor 'on', then we assume it's an
824+actual url, so we save it in `target`.
825+
826+Here's the move that sends the HTTP request:
827+
828+```
829+[ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]
830+```
831+
832+> Remember, we are expected to produce a *list* of moves. Note the `~` after the move in the full example. This is a convenient shortcut for creating a list of a single element. It's part of a small family of such shortcuts. `~[a b c]` is `[a b c ~]`, `[a b c]~` is `[[a b c] ~]` and `\`[a b c]` is `[~ a b c]`. These may be mixed and matched to create various convoluted structures and emojis.
833+
834+The correspondence between this move and `[bone card]` can be hard to
835+visualize on one line. Here it is more pedantically:
836+
837+```
838+:* bone=ost.hid :: the move
839+ term=%hiss
840+ wire=/request
841+ unit-iden=~
842+ mark=%httr
843+ cage=[%purl (need (de-purl:html target))]
844+==
845+```
846+
847+When the HTTP response comes back, we handle it with
848+`++sigh-httr`, which, along with the wire the request was sent
849+on, takes the status code, the response headers, and the response
850+body.
851+
852+We check whether the status code is between 200 and 300. If so,
853+all is well, and we print a message saying so. We start the
854+timer for ten seconds after the present time.
855+
856+If we got a bad status code, then we print out the entire
857+response and start the timer again.
858+
859+After ten seconds, arvo will give us a `%wake` event, which will
860+be handled in `++wake-timer`. If we're still supposed to keep
861+monitoring, we send the same HTTP request as before. Otherwise,
862+we set `in-progress` to false.
863+
864+Let's try it out:
865+
866+```
867+~fintud-macrep:dojo> |start %up
868+>=
869+~fintud-macrep:dojo> :up &atom 'http://www.google.com'
870+>=
871+[%all-is-well 200]
872+[%all-is-well 200]
873+~fintud-macrep:dojo> :up &atom 'http://example.com'
874+>=
875+[%all-is-well 200]
876+~fintud-macrep:dojo> :up &atom 'http://google.com'
877+>=
878+[%we-have-a-problem 301]
879+[ %headers
880+ ~[
881+ [p='X-Frame-Options' q='SAMEORIGIN']
882+ [p='X-XSS-Protection' q='1; mode=block']
883+ [p='Content-Length' q='219']
884+ [p='Server' q='gws']
885+ [p='Cache-Control' q='public, max-age=2592000']
886+ [p='Expires' q='Sun, 10 Jan 2016 23:45:05 GMT']
887+ [p='Date' q='Fri, 11 Dec 2015 23:45:05 GMT']
888+ [p='Content-Type' q='text/html; charset=UTF-8']
889+ [p='Location' q='http://www.google.com/']
890+ ]
891+]
892+[ %body
893+ [ ~
894+ [ p=219
895+ q
896+ \/'<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">\0a<TITLE>301 Moved</TI\/
897+ TLE></HEAD><BODY>\0a<H1>301 Moved</H1>\0aThe document has moved\0a<A HREF="http://www.google.com/">her
898+ e</A>.\0d\0a</BODY></HTML>\0d\0a'
899+ \/ \/
900+ ]
901+ ]
902+]
903+~fintud-macrep:dojo> :up &atom 'off'
904+```
905+
906+;=
907+ ;h2
908+ ;div(id "marks"): Marks
909+ ==
910+==
911+
912+We've used predefined marks already, but we haven't yet created
913+our own marks. Let's write a sample mark of our own, then chain
914+it together with some preexisting ones to have fun with type
915+conversions.
916+
917+Let's make a small "cord" mark. "Cord" is a name we use for `@t`
918+text, but there's no predefined mark for it. Let's put the following code in:
919+`/mar/cord.hoon`:
920+
921+```
922+/? 314
923+|_ cod=@t
924+++ grab
925+ |%
926+ ++ atom |=(arg=@ `@t`(scot %ud arg))
927+ --
928+++ grow
929+ |%
930+ ++ md cod
931+ --
932+--
933+```
934+
935+`/? 314` is the required
936+version number, just like in apps. After that everything's in a
937+`|_`, which is a `|%` core, but with input arguments. In our
938+case, the argument is the marked data.
939+
940+There are three possible top-level arms in the `|_` core,
941+`++grab`, `++grow`, and `++grad` (which is used for revision
942+control, covered elsewhere). `++grab` specifies
943+functions to convert from another mark to the current mark.
944+`++grow` specifies how to convert from the current mark to
945+another one.
946+
947+In our case, we only define one arm in `++grab`, namely `++atom`.
948+This allows us to convert any atom to a cord. `++scot` is a
949+standard library function in `hoon.hoon` which pretty-prints
950+atoms of various types. We want to treat the atom as an
951+unsigned decimal number, so we give `%ud` and the given argument
952+to `++scot`. Thus, the form of an arm in `++grab` is
953+`|=(other-mark-type this-mark-value)`.
954+
955+In `++grow`, we just convert to the `md` mark, which is just a
956+`@t` internally, but it has fancy conversion functions to things
957+like html. `++md` isn't a function because the "argument" is
958+already a `@t`, so we can just produce the new value directly.
959+
960+Let's play around a bit with this mark. First, let's take a
961+marked atom and convert it to our new mark.
962+
963+```
964+~fintud-macrep:dojo> &atom 9
965+9
966+
967+~fintud-macrep:dojo> &cord &atom 9
968+'9'
969+
970+~fintud-macrep:dojo> &cord &atom &cord &atom 9
971+ '57'
972+```
973+
974+ASCII 9 is 57. There's no requirement, implicit or otherwise,
975+that conversions back and forth between marks be inverses of each
976+other. These are semantic conversions, in that they refer to the
977+same concept. They're not isomorphisms.
978+
979+Let's play around a little more:
980+
981+```
982+~fintud-macrep:dojo> &md &cord &atom 17
983+'17'
984+
985+~fintud-macrep:dojo> &hymn &md &cord &atom 17
986+[ [%html ~]
987+ [[%head ~] ~]
988+ [[%body ~] [g=[n=%pre a=~] c=~[[g=[n=%$ a=~[[n=%$ v="17"]]] c=~]]] ~]
989+ ~
990+]
991+```
992+
993+That was exciting. If you squint at that, it looks an
994+awful lot like html. Our value `17` is still in there, in the
995+body. `urb` is the mark we render most web pages to. It makes
996+sure you have a complete skeleton of a web page. Of course, by
997+the time this gets to the web page, it's plain html. Let's do
998+the final step in the conversion.
999+
1000+```
1001+~fintud-macrep:dojo> &mime &hymn &md &cord &atom 17
1002+[[%text %html ~] p=52 q='<html><head></head><body><pre>17</pre></body></html>']
1003+```
1004+
1005+This is a mime-typed octet stream with type `/text/html`, length
1006+121 bytes, and our lowly number `17` rendered to a web page.
1007+`cord` was just one step in the chain.
1008+
1009+Of course, arvo can infer some parts of this chain:
1010+
1011+```
1012+~fintud-macrep:dojo> &cord 17
1013+'17'
1014+```
1015+
1016+Likewise, `md` is the only way to get from `cord` to `hymn`, so
1017+that can be omitted. If we omit the `hymn`, though, we get:
1018+
1019+```
1020+~fintud-macrep:dojo> &mime &cord 17
1021+[[%text %x-markdown ~] p=2 q='17']
1022+```
1023+
1024+Here, we converted straight from `cord` to `md` to `mime`. Arvo
1025+decided that was the most straightforward conversion, but it
1026+gives a different result than passing it through the `hymn`
1027+mark.
1028+
1029+The minimal correct input, then, is `&mime &hymn &cord &atom 17`.
1030+
1031+;=
1032+ ;h2
1033+ ;div(id "network"): Network Messages
1034+ ==
1035+==
1036+
1037+In the following we assume that you have some knowledge of Hoon. If you don't, check out chapters 1 and 2 of the Hoon tutorial and check back when you're ready.
1038+
1039+Let's get our planets to talk to each other. To listen for and receive messages from other planets, we'll need an app. Let's look at a very simple one, `echo.hoon`:
1040+
1041+```
1042+:: Accepts any noun from dojo and prints it out
1043+::
1044+:::: /===/app/echo/hoon
1045+ ::
1046+!: :: enables debug printfs
1047+|% :: forms a core with subject as payload
1048++$ move [bone card] :: defines echo app's arvo move mold
1049++$ card $% $~ :: defines card (data) mold as null tagged union
1050+ == :: end of mold definition; see $%
1051+-- :: end of card arm definition
1052+:: ::
1053+|_ [bow=bowl:gall $~] :: forms a core with bowl (app state) as sample
1054+++ poke-noun :: begin definition of poke-noun arm
1055+ |= non=* :: forms a gate which accepts any noun
1056+ ^- [(list move) _+>.$] :: casts product to mold of moves and context
1057+ ~& echo+noun+non :: debug printf, i.e. '[%echo %noun *]'
1058+ [~ +>.$] :: produce a cell of empty list and our state
1059+-- :: end of poke-noun arm definition
1060+```
1061+
1062+Save this as `echo.hoon` in the `/app` directory of your urbit's pier.
1063+
1064+This is a very simple app that does only one thing. If you poke it with
1065+a value, it prints that value out. To try this out, you have to start
1066+the app, then you can poke it from the command line with the following
1067+commands:
1068+
1069+```
1070+~fintud-macrep:dojo> |start %echo
1071+>=
1072+
1073+~fintud-macrep:dojo> :echo 5
1074+[%echo %noun 5]
1075+>=
1076+
1077+~fintud-macrep:dojo> :echo [1 2]
1078+[%echo %noun [1 2]]
1079+>=
1080+```
1081+
1082+> There is currently a bug where the `[%echo %noun *]` lines are printed *above* the line you entered, so your output may not look exactly like this. `>=` means that a command was successfully received and executed.
1083+
1084+Most of the app code should be simple enough to guess its function. The
1085+important part of this code is the definition of `++poke-noun`.
1086+
1087+Once an app starts, it's always running in the background and you interact with
1088+it by sending it messages. The most straightforward way to do that is to poke it
1089+from the command line, which we we did with `:echo 5`
1090+(`:[app-name] [argument(s)]`).
1091+
1092+In this case, `++poke-noun` takes an argument (*sample*) `arg` and
1093+prints it to dojo with `~&` ([sigpad](/docs/reference/hoon-expressions/rune/sig#sigpad/)).
1094+This is an unusual rune that formally "does nothing", but the interpreter
1095+detects it and printfs the first child, before executing the second as if the
1096+first didn't exist. This is a slightly hacky way of printing to the console,
1097+but we'll get to the correct way later on.
1098+
1099+But what does `++poke-noun` produce? Recall that `^-` casts to a type. In this
1100+case, it's declaring that the end result (*product*) of the function
1101+(`++poke-noun`'s *gate*) will be of type `[(list) _+>.$]`. But what does this
1102+mean?
1103+
1104+The phrase to remember is "a list of moves and our state". Urbit is a message
1105+passing system, so whenever we want to do something that interacts with the rest
1106+of the system, we send a message. Thus, a move is Arvo's equivalent of a
1107+syscall. The first thing that `++poke-noun` produces is a list of messages,
1108+called "moves". In this case, we don't actually want the system to do anything,
1109+so we produce the empty list, `~` (in the `[~ +>.$]` line).
1110+
1111+The second thing `++poke-noun` produces is our state. `+>.$` refers to a
1112+particular address in our subject where our formal app state is stored.
1113+It'll become clear why this is later on, but for now pretend that `+>.$`
1114+is a magic invocation that means "app state".
1115+
1116+Let's look at another example. Say we want to
1117+only accept a number, and then print out the square of that number.
1118+
1119+```
1120+:: Accepts an atom from the dojo and squares it.
1121+::
1122+:::: /===/app/square/hoon
1123+ ::
1124+!:
1125+|% :: no moves in :square
1126++$ move [bone card] :: no cards in :square
1127++$ card $% $~
1128+ ==
1129+--
1130+:: :: stateless
1131+|_ [bow=bowl:gall $~]
1132+++ poke-atom
1133+ |= tom=@
1134+ ^- [(list move) _+>.$]
1135+ ~& square+(mul tom tom)
1136+ [~ +>.$]
1137+--
1138+```
1139+
1140+Save this as `square.hoon` in the `/app` directory of your urbit's pier.
1141+
1142+A few things have changed. Firstly, we no longer accept arbitrary nouns because
1143+we can only square atoms (integers, in this case an unsigned one). Thus, our
1144+argument is now `tom=@`. Secondly, it's `++poke-atom` rather than `++poke-noun`.
1145+
1146+### Intro to marks
1147+
1148+Are there other `++poke`s? Yes. In fact, `noun` and `atom` are just two
1149+of arbitrarily many "marks". A mark is fundamentally a type definition,
1150+but accessible at the Arvo level. Each mark is defined in the `/mar`
1151+directory. Some marks have conversion routines to other marks, and some
1152+have diff, patch, and merge algorithms. None of these are required for a
1153+mark to exist, however.
1154+
1155+`noun` and `atom` are two predefined marks. In your `/mar` directory,
1156+there are already many more, and you may add more at will. The type
1157+associated with `noun` is `*`, and the type associated with `atom` is
1158+`@`.
1159+
1160+When we poke an app from anywhere, we do so with a mark that searches
1161+for the corresponding (`++poke-[mark]`) arm. Data constructed on the
1162+command line is by default marked with `noun`. In this case, the app is
1163+expecting an atom, so we have to explicitly mark the data with `atom`
1164+using `&[mark]`. Try the following commands:
1165+
1166+```
1167+~fintud-macrep:dojo> |start %square
1168+>=
1169+
1170+~fintud-macrep:dojo> :square 6
1171+gall: %square: no poke arm for noun
1172+
1173+~fintud-macrep:dojo> :square &atom 6
1174+[%square 36]
1175+>=
1176+```
1177+
1178+> Recall the bug where `%square` may get printed above the input line.
1179+
1180+Marks are powerful, and they're the backbone of Urbit's data pipeline,
1181+so we'll be getting quite used to them.
1182+
1183+*Exercise*:
1184+
1185+- Write an app that computes fizzbuzz on its input.
1186+
1187+#### Sending a message to another urbit
1188+
1189+Let's write our first network message! Here's `examples/app/pong.hoon`:
1190+
1191+```
1192+:: Allows one urbit to send the string 'Pong' to
1193+:: another urbit.
1194+::
1195+:::: /===/app/pong/hoon
1196+ ::
1197+!:
1198+|%
1199++$ move [bone card]
1200++$ card $% [$poke wire dock poke-contents]
1201+ ==
1202++$ poke-contents $% [$atom @]
1203+ ==
1204+--
1205+|_ [bow=bowl:gall $~] :: stateless
1206+::
1207+++ poke-urbit
1208+ |= to=ship
1209+ ^- [(list move) _+>.$]
1210+ ~& pong+'Outgoing pong!'
1211+ :_ +>.$
1212+ ~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong']]
1213+::
1214+++ poke-atom
1215+ |= tom=@
1216+ ^- [(list move) _+>.$]
1217+ ~& pong+'Incoming pong!'
1218+ ~& pong+received+`@t`tom
1219+ [~ +>.$]
1220+::
1221+++ coup |=(* [~ +>.$])
1222+::
1223+--
1224+```
1225+
1226+
1227+Run it with these commands:
1228+
1229+```
1230+~fintud-macrep:dojo> |start %pong
1231+>=
1232+
1233+~fintud-macrep:dojo> :pong &urbit ~sampel-sipnym
1234+>=
1235+```
1236+
1237+Replace `~sampel-sipnym` with another urbit. The easiest thing to do is to start
1238+a comet, a free and disposable Urbit identity. If you don't know how to start a
1239+comet, see [the user setup section](/docs/getting-started/). Don't forget to start
1240+the `%pong` app on that urbit, too. You should see, on the foreign
1241+urbit, this output:
1242+
1243+```
1244+[%pong 'Incoming pong!']
1245+[%pong %received 'Pong']
1246+```
1247+
1248+Most of the code should be straightforward. In `++poke-atom`, the only new thing
1249+is the expression `` `@t`tom ``, which is *casting* the argument `tom` to type
1250+`@t`. As we already know, `@t` is the type of "cord" (text string).
1251+
1252+The more interesting part is in `++poke-urbit`. The `urbit` mark is an urbit
1253+identity, and the Hoon type associated with it is `ship` or `@p` (the "p"
1254+stands for "phonetic base").
1255+
1256+Recall that in a `++poke` arm we produce "a list of moves and our state". Until
1257+now, we've left the list of moves empty, since we haven't wanted to tell Arvo to
1258+do anything in particular. Now we want to send a message to another urbit. Thus,
1259+we produce a list with one element:
1260+
1261+```
1262+~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong]]
1263+```
1264+
1265+#### Moves
1266+
1267+The general form of a move is `[bone term wire *]`.
1268+
1269+Or, in pseudo-code:
1270+
1271+`["cause" sys-call/action tack-new-layer-on-cause action-specific information]`
1272+
1273+Let's walk through each of these elements step by step.
1274+
1275+###### Bones ("cause")
1276+
1277+If you look up `++bone` in `hoon.hoon`, you'll see that it's a number (`@ud`),
1278+and that it's an opaque reference to a duct. `++duct` in `hoon.hoon` is a list
1279+of `wire`s, where `++wire` is an alias for `++path`. `++path` is a list of
1280+`++knot`s, which are ASCII text. Thus, a duct is a list of paths, and a bone is
1281+an opaque reference to it (in the same way that a Unix file descriptor is an
1282+opaque reference to a file structure). Thus, to truly understand bones, we must
1283+understand ducts.
1284+
1285+A duct is a stack of causes, again, represented as paths, which are called wires.
1286+At the bottom of every duct is a unix event, such as a keystroke, network
1287+packet, file change, or timer event. When Arvo is given this event, it routes
1288+the event to appropriate kernel module for handling.
1289+
1290+Sometimes, the module can immediately handle the event and produce any necessary
1291+results. For example, when we poked the `++poke-atom` arm above, we poked %gall,
1292+our application server, which was able to respond to our poke directly. When the
1293+module cannot service the request itself, it sends instructions to another
1294+kernel module or application (through the %gall module) to do a specified
1295+action, and produces the result from that.
1296+
1297+Furthermore, when one module sends a message to another kernel module or
1298+application, it also sends along the duct it was given with its new wire tacked
1299+onto the top. Now the duct has two entries, with the unix event on the bottom
1300+and the kernel module that handled it on top. This process can continue
1301+indefinitely, pushing more and more wires onto the top of the duct. When an
1302+entity finally produces a result, a wire is popped off the duct, and the result
1303+is passed all the way back down, repeating the process of wire popping
1304+sequentially until the bottom of the duct is reached.
1305+
1306+In effect, a duct is an Arvo-level call stack. It's worth noting that while in
1307+traditional call stacks a function call happens synchronously and returns
1308+exactly once. In Arvo, multiple moves can be sent at once, are evaluated
1309+asynchronously, and each one may be responded to zero or more times.
1310+
1311+The point to take home is that whatever caused `++poke-urbit` to be called is
1312+also the root cause for the network message we're trying to send. Thus, we say
1313+to send the network message along the given bone `ost`.
1314+
1315+##### Wire (path)
1316+
1317+Of course, we have to push a new wire onto our duct before passing it along (or
1318+responding to it directly) anywhere. This wire can have any data we want in it,
1319+but we don't need anything specific here, so we just use the wire `/sending`
1320+(`/elem1/elem2/elemN` is one syntax used to create `++path`s and `++wire`s of N
1321+elements). If we were expecting a response (which we're not), it would come back
1322+along the `/sending` wire, meaning that the path `/sending` will be passed back
1323+to the response handler as an argument. Although it's not required, it's
1324+generally a good idea to make the wire human-readable for bug-handling purposes.
1325+
1326+##### Term (sys-call)
1327+
1328+Each move also has a `term`, composed of lowercase ASCII and/or `-`. This `term`
1329+has the sign `@tas`. In this case, our `term` is `%poke`, which is the name of
1330+the particular kind of move we're sending. You can always use `%poke` to message
1331+an app. Other common names include `%warp`, to read from the filesystem;
1332+`%wait`, to set a timer; and `%them`, to send an http request.
1333+
1334+The move ends with `*` (that is, any noun) since each type of move takes
1335+different data. In our case, a `%poke` move takes a target (urbit and app) and
1336+marked data, then pokes the arm of the corresponding mark on that app on that
1337+urbit with that data. `[to-urbit-address %pong]` is the target urbit and app,
1338+`%atom` is the `mark`, and`'Pong'` is the data.
1339+
1340+When Arvo receives a `%poke` move, it calls the appropriate `++poke`.
1341+The same mechanism is used for sending messages between apps on the same
1342+urbit as for sending messages between apps on different urbits.
1343+
1344+> We said earlier that we're not expecting a response. This is not entirely true: the `++coup` is called when we receive acknowledgment that the `++poke` was called. We don't do anything with this information right now, but we could.
1345+
1346+*Exercises*:
1347+
1348+- Extend either of the apps in the first two exercises to accept input over the network in the same way as `pong`.
1349+
1350+- Modify `pong.hoon` to print out a message when it receives acknowledgement.
1351+
1352+- Write two apps, `even` and `odd`. When you pass an atom to `even`, check whether it's even. If so, divide it by two and recurse; otherwise, poke `odd` with it. When `odd` receives an atom, check whether it's equal to one. If so, terminate, printing "%success". Otherwise, check whether it's odd. If so, multiply it by three, add one, and recurse; otherwise, poke `even` with it. When either app receives a number, print it out along with the name of the app. In the end, you should be able to watch Collatz's conjecture play out between the two apps. Sample output:
1353+
1354+```
1355+~fintud-macrep:dojo> :even &atom 18
1356+[%even 18]
1357+[%odd 9]
1358+[%even 28]
1359+[%even 14]
1360+[%odd 7]
1361+[%even 22]
1362+[%odd 11]
1363+[%even 34]
1364+[%odd 17]
1365+[%even 52]
1366+[%even 26]
1367+[%odd 13]
1368+[%even 40]
1369+[%even 20]
1370+[%even 10]
1371+[%odd 5]
1372+[%even 16]
1373+[%even 8]
1374+[%even 4]
1375+[%even 2]
1376+%success
1377+```
1378+
1379+- Put `even` and `odd` on two separate urbits and pass the messages over the network. Post a link to a working solution in :talk to receive a cookie.
1380+
1381+
1382+;=
1383+ ;h2
1384+ ;div(id "security"): Security Drivers
1385+ ==
1386+==
1387+
1388+A security driver is a file in `/=home=/sec/<tld>/<domain>/hoon`
1389+that handles the authentication for all HTTP requests to
1390+`https://<domain>.<tld>`. When anything in Urbit makes an HTTP
1391+request through `%eyre` (our web server), it checks to see if we
1392+have a security driver for the requested domain, and if so
1393+filters the request through the driver. The security driver will
1394+usually either decorate the request with the needed credentials
1395+if it has them, or else it will guide the user through the
1396+process of authenticating Urbit with the service.
1397+
1398+Each web service needs its own security driver, but most of them
1399+are pretty standard. We recommend starting with an existing
1400+security driver based on your needed authentication method (e.g.
1401+basic auth, OAuth1, OAuth2), and changing whatever is specific to
1402+your service.
1403+
1404+The best strategy for building security drivers is to copy a
1405+similar one and tweak it until it works for you. The best
1406+representatives are Github for Basic Authentication, Twitter for
1407+OAuth1, Slack for OAuth2 when access tokens don't expire, and
1408+Google APIs for OAuth2 when access tokens do expire. In most
1409+cases you'll need to make very few changes to one of these
1410+models.
1411+
1412+Still, it's worth seeing one or two built from the ground up.
1413+Here, we'll build a connector for the Github API v3. (It's already in `/sec/com/github.hoon` if you want to see it.)
1414+
1415+The
1416+simplest way to interact with the Github API is to just fetch
1417+https://api.github.com from the dojo. First, run this:
1418+
1419+```
1420+> |init-auth-basic /com/github
1421+```
1422+
1423+Input your Github username and password as directed. Next:
1424+
1425+```
1426+~your-urbit:dojo> +https://api.github.com
1427+```
1428+
1429+> Note: the current version of this API is outdated, so you'll get a 403 message at this point. We need to update this so you can follow along with the examples. We're sorry!
1430+
1431+Github exposes a few endpoints to the general web, and the root
1432+endpoint is one of them. This gives you a textual representation
1433+of a JSON object that contains a bunch of urls to other parts of
1434+Github's API. This is exactly the same response you would get
1435+from just running `curl https://api.github.com` on UNIX.
1436+
1437+If we don't have a security driver for Github yet, many of the
1438+endpoints won't be accessible, or they will only have publicly
1439+accessible information. Most of what we care about requires us
1440+to be authenticated.
1441+
1442+#### Basic auth
1443+
1444+Here's a simple security driver:
1445+
1446+```
1447+:: Test url +https://api.github.com/user
1448+::
1449+:::: /hoon/github/com/sec
1450+ ::
1451+/+ basic-auth
1452+!:
1453+|_ [bal=(bale keys:basic-auth) $~]
1454+++ aut ~(standard basic-auth bal ~)
1455+++ filter-request out-adding-header:aut
1456+--
1457+```
1458+
1459+Github supports authentication through either Basic
1460+Authentication or OAuth2. We'll show the basic auth example
1461+first, but in general we'd prefer OAuth2.
1462+
1463+Since this driver is for Github, put it in
1464+`/=home=/sec/com/github/hoon`.
1465+
1466+To try this out, we first have to initialize our credentials with
1467+`|init-auth-basic`, which prompts for the url of the service
1468+(api.github.com), username, and password. It stores this
1469+information in a manner that `%eyre` knows how to decode and send
1470+put into your `bale`. Note that `|init-auth-basic` is standard for
1471+basic auth, but other auth schemes (like OAuth) are initialized
1472+in other ways.
1473+
1474+After you've run `|init-auth-basic`, you should be able to run
1475+`+https://api.github.com/user` and get a response indicating who
1476+you're logged in as.
1477+
1478+You can similarly POST:
1479+
1480+```
1481+~your-urbit:dojo> +https://api.github.com/gists &json _(cork de-json:html need) '{"files":{"file1.txt":{"content":"can\'t stop the signal"}}}'
1482+```
1483+
1484+This creates a gist, go to `https://gist.github.com/<username>` to
1485+see it.
1486+
1487+The `+url` syntax used in "source" position makes a GET request,
1488+but if you pass it data it will make a POST request with that
1489+data as the body. This request is authenticated seamlessly. You
1490+can send data of any mark as long as it has a conversion path to
1491+`%mime`.
1492+
1493+Let's take a look at the code and see if we can figure out what's
1494+happening here:
1495+
1496+```
1497+/+ basic-auth
1498+```
1499+
1500+First, we load a library called `basic-auth`. This library
1501+exposes two items. `keys` is the type of the basic auth key,
1502+which is essentially a base64'd username and password.
1503+`standard` accepts a `bale` and produces a core with everything
1504+we'll need to implement basic auth.
1505+
1506+Every security driver needs some amount of state, which is stored
1507+in `bale`. `bale` contains:
1508+
1509+- `our`, our urbit name
1510+- `now`, the current time
1511+- `eny`, 256 bits of entropy
1512+- `byk`, the urbit, desk and case which the security driver is running from
1513+- `usr`, the particular identity we're logging in with
1514+- `dom`, the site we're accessing
1515+- `key`, the secrets required to authenticate requests. The type for this entry is supplied by the programmer as the argument to `++bale`. Thus, in our case, `key` in our bale is of type `keys:basic-auth`.
1516+
1517+Additionally, a security driver contains at least one out of the
1518+five "special" arms:
1519+
1520+- `++filter-request` is a function which takes a hiss (http request) and produces a `sec-move` (defined in zuse), which is one of:
1521+ - `[%send hiss]`, which sends the new hiss. This is the case in, for example, basic auth, where all we need to do is add an extra header to the request.
1522+ - `[%give httr]`, where httr is an http response. This immediately returns an http response to the sender.
1523+ - `[%show purl]`, where a purl is a parsed url. This displays a message asking the user to visit the given url to continue the authentication process.
1524+ - `[%redo ~]`, which redoes the request.
1525+ - `%eyre` calls `++filter-request` just before sending an HTTP request to the specified domain. This allows the security driver to filter the requests, decorating them with authentication data.
1526+- `++filter-response` is a function which takes an httr and produces a `sec-move`. `%eyre` calls it after receiving an HTTP response from the specified domain. This allows the security driver to handle authentication errors, commonly caused by expired tokens, and retry the request.
1527+- `++receive-auth-query-string` is a function that takes a `quay` (list of query parameters) and produces a `sec-move`. `%eyre` calls it when it receives a request on the callback url. Generally, this happens in OAuth after the user has granted access to the urbit app, and the service makes a request to the callback url with the code. The security driver should then make a request to convert the code into an access token.
1528+- `++receive-auth-response` is a function that takes an httr and produces a `sec-move`. `%eyre` calls it when it gets a response to the request made in `++receive-auth-query-string`.
1529+- `++update` is a function which converts old state to a new format when the security driver gets updated. If you want to just get rid of the old state, define `++discard-state` as `~`.
1530+
1531+For basic auth, we only have to worry about `++filter-request`,
1532+since all we need to do is add the correct header to each
1533+request. Our `++aut` core contains a function
1534+`++out-addding-header`, which does exactly what we want.
1535+
1536+Where do the keys come from, though? Remember we ran
1537+`|init-auth-basic` to input them. This just prompts you for the
1538+service url, username, and password, and it stores them next to
1539+the driver. In our case, that's
1540+`/=home=/sec/com/gitub/api/atom`. These keys are stored
1541+encrypted, and you don't want to edit them directly. `%eyre`
1542+loads them directly into your `bale`.
1543+
1544+#### OAuth2
1545+
1546+Most services are better accessed through some form of OAuth.
1547+Github can be accessed with OAuth2, which is a little more
1548+complicated than basic auth, but not hugely so.
1549+
1550+The basic steps for OAuth2 are these:
1551+
1552+- create an app and get its client id and client secret (on Github)
1553+- store these in Urbit (with `|init-oauth2`)
1554+- try to make a request that requires authentication. The security driver should prompt you to visit a particular url.
1555+- visit the url and click "authorize", which gives the app access to your account
1556+- the security driver will turn the code it receives into an access token
1557+- on every request, include that access token
1558+
1559+Creating an app is easy and
1560+[well-documented](https://github.com/settings/applications/new).
1561+If necessary, set the callback url to
1562+`/~/ac/github.com/_state/in`, and note its client id and client
1563+secret.
1564+
1565+Run `|init-oauth2`, which will prompt for the hostname
1566+(api.github.com), client id, and client secret. This will store
1567+the information, encrypted, in `/=home=/sec/com/github.atom`,
1568+just as with Basic Authentication.
1569+
1570+Now we need a security driver. Use this:
1571+
1572+```
1573+:: Test url +https://api.github.com/user
1574+::
1575+:::: /hoon/github/com/sec
1576+ ::
1577+/+ oauth2
1578+!:
1579+::::
1580+ ::
1581+|_ [bal=(bale keys:oauth2) tok=token:oauth2]
1582+++ scopes :: comment out scopes to taste
1583+ :~ 'user' 'user:email' 'user:follow' 'public_repo' 'repo'
1584+ 'repo_deployment' 'repo:status' 'delete_repo' 'notifications'
1585+ 'gist' 'read:repo_hook' 'write:repo_hook' 'admin:repo_hook'
1586+ 'admin:org_hook' 'read:org' 'write:org' 'admin:org'
1587+ 'read:public_key' 'write:public_key' 'admin:public_key'
1588+ ==
1589+:: ++aut is a "standard oauth2" core, which implements the
1590+:: most common handling of oauth2 semantics. see lib/oauth2 for more details,
1591+:: and examples at the bottom of the file.
1592+++ aut (~(standard oauth2 bal tok) . |=(tok/token:oauth2 +>(tok tok)))
1593+++ filter-request
1594+ %^ out-add-query-param:aut 'access_token'
1595+ scope=~[%client %admin]
1596+ oauth-dialog='https://github.com/login/oauth/authorize'
1597+::
1598+++ receive-auth-query-string
1599+ %- in-code-to-token:aut
1600+ url='https://github.com/login/oauth/api/access_token'
1601+++ receive-auth-response bak-save-token:aut
1602+--
1603+```
1604+
1605+The oauth2 library provides the main "engine" in `standard`, just
1606+like in basic auth, except that we also have to specify a
1607+function to save the access token when we get it. It's worth
1608+noting that this library is well documented in the source,
1609+including examples: `/=home=/lib/oauth2/hoon`.
1610+
1611+Running `+http://api.github.com/user` tries to make a request to
1612+Github with authentication. This loads into the bale the keys,
1613+which are of type `keys:oauth2`, defined in the oauth2 library.
1614+We don't have to worry about the specifics of these keys -- the
1615+library handles them -- but they include the client id and the
1616+client secret.
1617+
1618+Before the request is sent, `%eyre` calls `++filter-request` to
1619+decorate it with authentication headers. Since we don't yet have
1620+an access token, we need to prompt the user to visit the "dialog"
1621+url. `++out-add-query-param` checks whether we have a token, and
1622+if we don't it produces `%show` and a message telling the user to
1623+visit the `oauth-dialog` url we provide, with the extra query
1624+parameters added (client id, scopes, and state).
1625+
1626+When the user visits that url, Github will ask them to log in and
1627+authorize the application. When they do so, Github will post a
1628+request to `/~/ac/github.com/_state/in` with a code in the query
1629+string. `%eyre` sends the query string to
1630+`++receive-auth-query-string`, which is a function that takes a
1631+quay and produces a `sec-move`. `++in-code-to-token` from our
1632+`aut` takes the `code` parameter from the quay and uses it to
1633+create a request to the given url. This request includes the
1634+client id, the client secret, and the code we just got.
1635+
1636+Github's response to that request includes an access token in its
1637+body. This is handled in `++receive-auth-response`.
1638+`++bak-save-token` extracts that token and gives it to the
1639+function that we passed in the definition of `++aut`. In our
1640+case, we just save that token into our state for later usage.
1641+
1642+Now we have the credentials we need, so `++filter-request` is
1643+called with the original request, and `++out-add-query-param`
1644+passes the request through with the addition of the query
1645+parameter `access_token`.
1646+
1647+Just like with Basic Authentication, you should be able to run
1648+`+https://api.github.com/user` and get a response indicating who
1649+you're logged in as.
1650+
1651+Some drivers a slightly more complicated. For example, Github's
1652+access token's don't expire, but that's not the case for all
1653+service. The googleapis driver shows the flow when the access
1654+token can expire. Twitter uses OAuth1, for which we have another
1655+library.
1656+
1657+Remember, of course, that the best strategy for building security
1658+drivers is to copy a similar one and tweak it to taste.
1659+
1660+;=
1661+ ;h2
1662+ ;div(id "state"): State
1663+ ==
1664+==
1665+
1666+In the last section we built a few small apps that sent moves. These apps were
1667+entirely stateless, however. Most useful apps require some amount of state.
1668+Let's build a trivial stateful app. It'll keep a running the sum of all the
1669+atoms we poke it with. Here's `examples/app/sum.hoon`:
1670+
1671+```
1672+:: Keeps track of the sum of all the atoms it has been
1673+:: poked with and prints the sum out
1674+::
1675+:::: /===/app/sum/hoon
1676+ ::
1677+!:
1678+|%
1679++$ move [bone card]
1680++$ card $% $~
1681+ ==
1682+--
1683+|_ [bow=bowl:gall sum=@]
1684+::
1685+++ poke-atom
1686+ |= tom=@
1687+ ^- [(list move) _+>.$]
1688+ ~& sum+(add sum tom)
1689+ [~ +>.$(sum (add sum tom))]
1690+::
1691+++ coup
1692+ |= [wir=wire err=(unit tang)]
1693+ ^- [(list move) _+>.$]
1694+ ?~ err
1695+ ~& sum+success+'Poke succeeded!'
1696+ [~ +>.$]
1697+ ~& sum+error+'Poke failed. Error:'
1698+ ~& sum+error+err
1699+ [~ +>.$]
1700+::
1701+--
1702+```
1703+
1704+We can start it with `|start %sum`, and then run it:
1705+
1706+```
1707+~fintud-macrep:dojo> :sum &atom 5
1708+[%sum 5]
1709+>=
1710+
1711+~fintud-macrep:dojo> :sum &atom 2
1712+[%sum 7]
1713+>=
1714+
1715+~fintud-macrep:dojo> :sum &atom 15
1716+[%sum 22]
1717+>=
1718+```
1719+
1720+We can see that app state is being saved, but when, where, and how?
1721+
1722+The state is stored as the second thing in the `|_` line. In our case, it's
1723+simply an atom named `sum`. We change it by producing our state not with
1724+`+>.$` (as before), but with `+>.$(sum (add sum tom))`. We've seen all these
1725+parts before, but you might not recognize them.
1726+
1727+Recall in the first chapter that we recursed with the expression
1728+`$(b (add 3 b))`. This meant "produce `$` with `b` changed to `(add 3 b)`.
1729+Similarly, `+>.$(sum (add sum tom))` means "produce `+>.$` (i.e. our
1730+context, which contains our state) with `sum` changed to `(add sum tom)`.
1731+
1732+At a high level, then, when we handle state, we do it explicitly. It's passed in
1733+and produced explicitly. In Unix systems, application state is just a block of
1734+memory, which you need to serialize to disk if you want to keep it around for
1735+very long.
1736+
1737+In Urbit, app state is a single (usually complex) value. In our example, we have
1738+very simple state, so we defined `sum=@`, meaning that our state is an atom.
1739+Of course, `sum` is just a name, and you're free to name your state whatever
1740+you like. But let's clarify a couple other things before we continue.
1741+
1742+First, `bowl` is a set of general global states. This set is managed by the
1743+system. It includes things like `now` (the current time), `our` (our urbit
1744+identity), and `eny` (512 bits of guaranteed-fresh entropy). For the full list
1745+of things in `++bowl`, search for `++ bowl` (note: two spaces) in
1746+`/arvo/zuse.hoon`.
1747+
1748+> This is, perhaps, the most common way to learn Hoon. The easiest way to learn about an identifier you see in code is to search in `/arvo/zuse.hoon` and `/arvo/hoon.hoon` for it.\\ Urbit's codebase is less than 30000 lines of code combined, including the hoon parser, the compiler, and the `/arvo` microkernel, so you can usually use the code and its comments as a reference doc. You can also read [zuse.hoon](https://github.com/urbit/arvo/blob/master/arvo/zuse.hoon) and [hoon.hoon](https://github.com/urbit/arvo/blob/master/arvo/hoon.hoon) in your browser.
1749+
1750+The second thing we should clear up is this: Urbit needs no "serialize to disk"
1751+step. Everything you produce in the app state is persistent across calls to the
1752+app, restarts of the urbit, and even power failure. If you want to write to the
1753+Unix filesystem, you can, but it's not needed for persistence. Urbit has
1754+transactional events, which makes it an [ACID operating
1755+system](https://en.wikipedia.org/wiki/ACID). Thus, you don't have to worry about
1756+persistence when programming in Urbit, or ever go through the hassle of having
1757+to set up and write to a database.
1758+
1759+*Exercises*:
1760+
1761+- Modify `:sum` to reset the counter when you poke it with 0.
1762+
1763+- Write an app called `last` that prints out the previous value you poked it with.
1764+
1765+Sample output:
1766+
1767+```
1768+~fintud-macrep:dojo> :last 7
1769+[%last 0]
1770+>=
1771+
1772+~fintud-macrep:dojo> :last [1 2 3]
1773+[%last 7]
1774+>=
1775+
1776+~fintud-macrep:dojo> :last 'howdy'
1777+[%last [1 2 3]]
1778+```
1779+
1780+
1781+;=
1782+ ;h2
1783+ ;div(id "subscriptions"): Subscriptions
1784+ ==
1785+==
1786+
1787+We've dealt fairly extensively with "poke" messages to an app, but these
1788+are somewhat limited. A poke is a one-way message, but more often we
1789+want to subscribe to updates from another app. You could build a
1790+subscription model out of one-way pokes, but it's such a common pattern
1791+that it's built into Arvo.
1792+
1793+Let's take a look at two apps, `:source` and `:sink`. First,
1794+`:source`:
1795+
1796+```
1797+:: Sends subscription updates to sink.hoon
1798+::
1799+:::: /===/app/source/hoon
1800+ ::
1801+!:
1802+::
1803+|%
1804+ +$ move [bone card]
1805+ +$ card $% [%diff diff-contents]
1806+ ==
1807++$ diff-contents $% [%noun *]
1808+ ==
1809+--
1810+::
1811+|_ [bow=bowl:gall $~]
1812+::
1813+++ poke-noun
1814+ |= non=*
1815+ ^- [(list move) _+>.$]
1816+ :_ +>.$
1817+ %+ turn (prey:pubsub:userlib /example-path bow)
1818+ |=([o=bone *] [o %diff %noun non])
1819+::
1820+++ peer-example-path
1821+ |= pax=path
1822+ ^- [(list move) _+>.$]
1823+ ~& source+peer-notify+'Someone subscribed to you!'
1824+ ~& source+[ship+src.bow path+pax]
1825+ [~ +>.$]
1826+::
1827+++ coup
1828+ |= [wir=wire err=(unit tang)]
1829+ ^- [(list move) _+>.$]
1830+ ?~ err
1831+ ~& source+success+'Poke succeeded!'
1832+ [~ +>.$]
1833+ ~& source+error+'Poke failed. Error:'
1834+ ~& source+error+err
1835+ [~ +>.$]
1836+::
1837+++ reap
1838+ |= [wir=wire err=(unit tang)]
1839+ ^- [(list move) _+>.$]
1840+ ?~ err
1841+ ~& source+success+'Peer succeeded!'
1842+ [~ +>.$]
1843+ ~& source+error+'Peer failed. Error:'
1844+ ~& source+error+err
1845+ [~ +>.$]
1846+::
1847+--
1848+```
1849+
1850+Save this as `source.hoon` in the `/app` directory of your urbit's pier.
1851+
1852+And secondly, `:sink`:
1853+
1854+```
1855+:: Sets up a simple subscription to source.hoon
1856+::
1857+:::: /===/app/sink/hoon
1858+ ::
1859+!:
1860+|%
1861++$ move [bone card]
1862++$ card $% [%peer wire dock path]
1863+ [%pull wire dock $~]
1864+ ==
1865+--
1866+::
1867+|_ [bow=bowl:gall val=?]
1868+::
1869+++ poke-noun
1870+ |= non=*
1871+ ^- [(list move) _+>.$]
1872+ ?: &(=(%on non) val)
1873+ :_ +>.$(val |)
1874+ :~ :* ost.bow
1875+ %peer
1876+ /subscribe
1877+ [our.bow %source]
1878+ /example-path
1879+ ==
1880+ ==
1881+ ?: &(=(%off non) !val)
1882+ :_ +>.$(val &)
1883+ ~[[ost.bow %pull /subscribe [our.bow %source] ~]]
1884+ ~& ?: val
1885+ sink+unsubscribed+'You are now unsubscribed!'
1886+ sink+subscribed+'You are now subscribed!'
1887+ [~ +>.$]
1888+::
1889+++ diff-noun
1890+ |= [wir=wire non=*]
1891+ ^- [(list move) _+>.$]
1892+ ~& sink+received-data+'You got something!'
1893+ ~& sink+data+non
1894+ [~ +>.$]
1895+::
1896+++ coup
1897+ |= [wir=wire err=(unit tang)]
1898+ ^- [(list move) _+>.$]
1899+ ?~ err
1900+ ~& sink+success+'Poke succeeded!'
1901+ [~ +>.$]
1902+ ~& sink+error+'Poke failed. Error:'
1903+ ~& sink+error+err
1904+ [~ +>.$]
1905+::
1906+++ reap
1907+ |= [wir=wire err=(unit tang)]
1908+ ^- [(list move) _+>.$]
1909+ ?~ err
1910+ ~& sink+success+'Peer succeeded!'
1911+ [~ +>.$]
1912+ ~& sink+error+'Peer failed. Error:'
1913+ ~& sink+error+err
1914+ [~ +>.$]
1915+::
1916+--
1917+```
1918+
1919+Save this as `sink.hoon` in the `/app` directory of your urbit's pier (make sure both `source` and `sink` are on the same ship).
1920+
1921+Two notes:
1922+
1923+- `bowl` is the type of the system state within our app. For example, it includes things like `our`, the name of the host urbit, and `now`, the current time.
1924+
1925+- You may have noticed the separate `|%` above the application core `|_`. We usually put our types in another core on top of the application core. We can access these type from our `|_` because in `hoon.hoon` files, all cores are called against each other. (The shorthand for 'called' is `=>`.) Thus, the `|%` with the types is in the context of the `|_`, as it lies above it: `hoon.hoon` `=> |% w types => |_`
1926+
1927+Here's some sample output of the two working together:
1928+
1929+```
1930+~fintud-macrep:dojo> |start %source
1931+>=
1932+
1933+~fintud-macrep:dojo> |start %sink
1934+>=
1935+
1936+~fintud-macrep:dojo> :sink %on
1937+[%source %peer-notify 'Someone subscribed to you!']
1938+[%source [%ship ~fintud-macrep] %path /]
1939+[%sink %success 'Peer succeeded!']
1940+>=
1941+
1942+~fintud-macrep:dojo> :source 5
1943+[%sink %received-data 'You got something!']
1944+[%sink %data 5]
1945+>=
1946+
1947+~fintud-macrep:dojo> :sink %off
1948+>=
1949+
1950+~fintud-macrep:dojo> :source 6
1951+>=
1952+
1953+~fintud-macrep:dojo> :sink %on
1954+[%source %peer-notify 'Someone subscribed to you!']
1955+[%source [%ship ~fintud-macrep] %path /]
1956+[%sink %success 'Peer succeeded!']
1957+>=
1958+
1959+~fintud-macrep:dojo> :source 7
1960+[%sink %received-data 'You got something!']
1961+[%sink %data 7]
1962+>=
1963+```
1964+
1965+###### :source
1966+
1967+Hopefully you can get a sense for what's happening here. When we poke
1968+`:sink` with `%on`, `:sink` subscribes to `:source`,
1969+and so whenever we poke `:source`, `:sink` gets the update and
1970+prints it out. Then we unsubscribe by poking `:sink` with `%off`, and
1971+`:sink` stops getting updates. We then resubscribe.
1972+
1973+There's a fair bit going on in this code. Let's look at `:source`
1974+first.
1975+
1976+Our definition of `move` is fairly specific, since we're only going to
1977+sending one kind of move. The `%diff` move is a subscription update, and
1978+its content is marked data which gall routes to our subscribers.
1979+
1980+This is a slightly different kind of move than we've dealt with so
1981+far. It's producing a result rather than calling other
1982+code (i.e. it's a return rather than a function call), so if you recall
1983+the discussion of ducts, a layer gets popped off the duct rather than
1984+added to it. This is why no wire is needed for the move -- we won't
1985+receive anything in response to it.
1986+
1987+Anyways, there are four functions (arms) inside the `|_`. We already know when
1988+`++poke-noun` is called. `++peer-example-path` is called when someone tries to
1989+subscribe to our app. Of course, you don't just subscribe to an app; you
1990+subscribe to a path on that app. This path comes in as the argument to `++peer`.
1991+
1992+In our case, we don't care what path you subscribed on, and all we do is print
1993+out that you subscribed. Arvo keeps track of your subscriptions, so you don't
1994+have to. You can access your subscribers by looking at `sup` in the bowl that's
1995+passed in. `sup` is of type `(map bone {@p path})`, which associates bones with
1996+the urbit who subscribed, and which path they subscribed on. If you want to
1997+communicate with your subscribers, send them messages along their bone.
1998+
1999+`++poke-noun` "spams" the given argument to all our subscribers.
2000+There's a few things we haven't seen before. Firstly, `:_(a b)` is the
2001+same as `[b a]`. It's just a convenient way of formatting things when
2002+the first thing in a cell is much more complicated than the second.
2003+Thus, we're producing our state unchanged.
2004+
2005+Our list of moves is the result of a call to `++turn`. `++turn` is what many
2006+languages call "map" -- it runs a function on every item in a list and collects
2007+the results in a list. The list is `(prey /example-path bow)` and the function
2008+is the `|=` line right after it.
2009+
2010+`prey:pubsub:userlib` is a standard library function defined in `zuse.hoon`. It takes a path
2011+and a bowl and gives you a list of the subscribers who are subscribed on a path
2012+that begins with the given path. "Prey" is short for "prefix".
2013+
2014+Now we have the list of relevant subscribers. This a list of triples,
2015+`[bone @p path]`, where the only thing we really need is the bone, because we
2016+don't need to know their urbit or what exact path they subscribed on. Thus, our
2017+transformer function takes `[o=bone *]` and produces `[o %diff %noun non]`,
2018+which is a move that provides bone `o` with this subscription update:
2019+`[%noun non]`". This is fairly dense code, but what it's doing is
2020+straightforward!
2021+
2022+###### :sink
2023+
2024+`:source` should now make sense. `:sink` is a little longer, but not much more
2025+complicated.
2026+
2027+In `:sink`, our definition of of `++move` is different. All moves start
2028+with a `bone`, and we conventionally refer to the second half as the "card", so
2029+that we can say a move is an action that sends a card along a bone.
2030+
2031+We have two kinds of cards here: we `%peer` to start a subscription, and we
2032+`%pull` to stop it. Both of these are "forward" moves that may receive a
2033+response, so they need a wire to tack onto the duct before they pass it on. They
2034+also need a target, which is a pair of an urbit and an app name. Additionally,
2035+`%peer` needs a path on that app to subscribe too. `%pull` doesn't need this,
2036+because its semantics are to cancel any subscriptions coming over this duct. If
2037+your bone and wire are the same as when you subscribed, then the cancellation
2038+will happen correctly.
2039+
2040+The only state we need for `:sink` is a boolean to indicate whether
2041+we're already subscribed to `:source`. We use `val=?`, where `?`
2042+is the sign of type boolean (similar to `*`, `@`), which defaults to true (that
2043+is, `0`).
2044+
2045+In `++poke-noun` we check our input to see both if it's `%on` and we're
2046+available (`val` is true). If so, we produce the move to subscribe to
2047+`:source`:
2048+
2049+```
2050+:~ :* ost.bow
2051+ %peer
2052+ /subscribe
2053+ [our.bow %source]
2054+ /example-path
2055+ ==
2056+==
2057+```
2058+
2059+Also, in the preceding lines, we set `val` to false (`|`) with `+>.$(val |)`.
2060+Remember that the `:_` constructs an inverted cell, with the first child
2061+(`+>.$(val |` in our case) as the tail and the second child as the head. Here,
2062+the cell we produce when our subscription is `%on` and `val` is true has a
2063+head with our new state where `val` is set to false and a tail of our list of
2064+moves, which is shown in the code block above.
2065+
2066+Otherwise, if our input is `%off` and we're already subscribed (i.e. `val`
2067+is false), then we unsubscribe from `:source` and set `val` back to true (`&`),
2068+again using our handy inverted cell constructor mold `:_`:
2069+
2070+```
2071+:_ +>.$(val &)
2072+~[[ost.bow %pull /subscribe [our.bow %source] ~]]
2073+```
2074+
2075+It's important to send over the same bone and wire (`/subscribe`) as the
2076+one we originally subscribed on.
2077+
2078+If neither of these cases are true, then we print our current subscription
2079+state, based on whether `val` is true or false, and return a cell containing
2080+a null list of moves and our unchanged app state:
2081+
2082+```
2083+~& ?: val
2084+ sink+unsubscribed+'You are now unsubscribed!'
2085+ sink+subscribed+'You are now subscribed!'
2086+[~ +>.$]
2087+```
2088+
2089+`++diff-noun` is called when we get a `%diff` update along a subscription with a
2090+mark of `noun`. `++diff-noun` is given the wire that we originally passed with
2091+the `%peer` subscription request along and the data we got back. In our case we
2092+just print out the data:
2093+
2094+```
2095+~& sink+received-data+'You got something!'
2096+~& sink+data+non
2097+```
2098+
2099+`++reap` is called when we receive an acknowledgment as to whether the
2100+subscription was handled successfully. You can remember that `++reap` is the
2101+counterpart to `++peer` as it's pronounced like 'peer' backwards. Similarly,
2102+`coup` is similar to 'poke' backwards.
2103+
2104+Moving forward, `++reap` is given the wire we attempted to subscribe over,
2105+possibly along with an error message in cases of failure. `(unit type)` means
2106+"either `~` or `[~ type]`, which means it's used like Haskell's "maybe" or C's
2107+nullability. If `err` is `~`, then the subscription was successful and we tell
2108+that to the user. Otherwise, we print out the error message.
2109+
2110+
2111+;=
2112+ ;h2
2113+ ;div(id "backend"): Backend
2114+ ==
2115+==
2116+
2117+We've done purely functional web pages as hook files, and we've
2118+done command line apps, so now let's interact with an app over
2119+the web. The fundamental concepts are no different than from the
2120+command line -- you send "poke" messages to apps and subscribe to
2121+data streams. The only difference is that you do it with
2122+javascript.
2123+
2124+Let's create a small web app that counts the number of times you
2125+poke it. There'll be a button to poke the app, and line of text
2126+below it saying how many times the app has been poked. We can
2127+update this by subscribing our page to the relevant path on its app.
2128+
2129+Save the following as `click.hoon` in the `/app` directory of your urbit's pier.
2130+
2131+```
2132+/? 314
2133+!:
2134+|%
2135+++ move [bone %diff %mark *]
2136+--
2137+!:
2138+|_ [hid=bowl:gall clicks=@]
2139+++ poke-click
2140+ |= click=%click
2141+ ~& [%poked +(clicks)]
2142+ :_ +>.$(clicks +(clicks))
2143+ %+ turn (prey:pubsub:userlib /the-path hid)
2144+ |=([o=bone *] [o %diff %clicks +(clicks)])
2145+++ peer-the-path
2146+ |= pax=path
2147+ [[[ost.hid %diff %clicks clicks] ~] +>.$]
2148+--
2149+```
2150+
2151+There's nothing really new here, except that we use a couple of
2152+new marks, `click` and `clicks`. When we get poked with a
2153+`click`, we increment the variable `clicks` in our state and tell
2154+all our subscribers the new value. When someone subscribes to us
2155+on the path `/the-path`, we immediately give them the current
2156+number of clicks.
2157+
2158+Let's take a look at the new marks. Save this as `/mar/click.hoon`:
2159+
2160+```
2161+|_ click=%click
2162+++ grab
2163+ |%
2164+ ++ noun |=(* %click)
2165+ ++ json
2166+ |= jon=^json
2167+ ?> =('click' (need (so:dejs-soft:format jon)))
2168+ %click
2169+ --
2170+--
2171+```
2172+
2173+The mark `click` has type `%click`, which means the only
2174+valid value is `%click`. We can convert from `noun` by just
2175+producing `%click`.
2176+
2177+We also convert from json by parsing a json string with `so:dejs-soft:format`,
2178+asserting the parsing succeeded with `need`, and asserting the
2179+result was 'click' with `?>`, which asserts that its first child
2180+is true.
2181+
2182+> Note the argument to `++json`is `jon=^json`. Why `^json`? `++json` shadows the type definition, so if we want to refer to the type, we have to prepend a `^`. This extends to multiple levels: `^^^foo` means the fourth most innermost instance of `foo`.
2183+
2184+> `dejs-soft:format` in `zuse` is a useful library for parsing complex json into hoon structures. In this case, the `:` between `dejs-soft` and `format` means 'inside of', because `dejs-soft` is an arm contained within the core `format`. Our case is actually simple enough that the `?>` line could have been `?> =([%s 'click'] jon)`.
2185+
2186+We can test this mark from the command line (don't forget to start your app with `|start %click`)
2187+
2188+```
2189+~fintud-macrep:dojo> &click %click
2190+%click
2191+
2192+~fintud-macrep:dojo> &click &json [%s 'click']
2193+%click
2194+
2195+~fintud-macrep:dojo> &click &json &mime [/text/json (as-octs:mimes:html '"click"')]
2196+%click
2197+
2198+~fintud-macrep:dojo> &click &json &mime [/text/json (as-octs:mimes:html '"clickety"')]
2199+/~fintud-macrep/home/0/mar/click:<[7 5].[8 11]>
2200+ford: casting %json to %click
2201+ford: cast %click
2202+```
2203+
2204+And save the following as `/mar/clicks.hoon`:
2205+
2206+```
2207+|_ clicks=@
2208+++ grab
2209+ |%
2210+ ++ noun @
2211+ --
2212+++ grow
2213+ |%
2214+ ++ json
2215+ (frond:enjs:format %clicks (numb:enjs:format clicks))
2216+ --
2217+--
2218+```
2219+
2220+`clicks` is just an atom. We convert to json by creating an
2221+object with a single field "clicks" with our value.
2222+
2223+> Be sure to check out section 3bD, JSON and XML, in zuse.hoon `frond:enjs:format` is just a function that takes a key-value pair and produces a JSON object with one element.
2224+
2225+```
2226+~fintud-macrep:dojo> &json &clicks 6
2227+[%o p={[p='clicks' q=[%n p=~.6]]}]
2228+```
2229+
2230+Now that we know the marks involved, take another look at the app
2231+above. Everything should be pretty straightforward. Let's poke
2232+the app from the command line.
2233+
2234+```
2235+~fintud-macrep:dojo> |start %click
2236+>=
2237+~fintud-macrep:dojo> :click &click %click
2238+[%poked 1]
2239+>=
2240+~fintud-macrep:dojo> :click &click %click
2241+[%poked 2]
2242+>=
2243+```
2244+
2245+*Exercise*:
2246+
2247+- Modify `:sink` from the subscriptions chapter to listen to `:click` and print out the subscription updates on the command line.
2248+
2249+## Frontend
2250+
2251+> Note: the instructions below are outdated and do not work in the current version of Urbit. Feel free to experiment though.
2252+
2253+That's all that's needed for the back end. The front end is just
2254+some "sail" html (Hoon markup for XML) and javascript. Here's `/web/pages/click.hoon`:
2255+
2256+```
2257+;html
2258+ ;head
2259+ ;script(type "text/javascript", src "//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js");
2260+ ;script(type "text/javascript", src "/~/at/lib/js/urb.js");
2261+ ;title: Clickety!
2262+ ==
2263+ ;body
2264+ ;div##cont
2265+ ;input##go(type "button", value "Poke!");
2266+ ;div##err(class "disabled");
2267+ ;div##clicks;
2268+ ==
2269+ ;script(type "text/javascript", src "/pages/click/click.js");
2270+ ==
2271+==
2272+```
2273+
2274+You should recognize the sail syntax from an earlier chapter.
2275+Aside from jquery, we also include `urb.js`, which is a framework
2276+for interacting with urbit.
2277+
2278+To view the frontend, point your browser at `ship-name.urbit.org/~~/pages/click` if you're on the live network. If you're running a fake galaxy, navigate to whatever port it's running on, which is usually: `https://localhost:80/~~/pages/click`.
2279+
2280+We have a button labeled "Poke!" and a div with id `clicks` where
2281+we'll put the number of clicks. We also include a small
2282+javascript file where the client-side application logic can be
2283+found. It's in `/web/pages/click.js`:
2284+
2285+```
2286+$(function() {
2287+ var clicks, $go, $clicks, $err
2288+
2289+ $go = $('##go')
2290+ $clicks = $('##clicks')
2291+ $err = $('##err')
2292+
2293+ $go.on("click",
2294+ function() {
2295+ window.urb.send(
2296+ "click", {mark: "click-click"}
2297+ ,function(err,res) {
2298+ if(err)
2299+ return $err.text("There was an error. Sorry!")
2300+ if(res.data !== undefined &&
2301+ res.data.ok !== undefined &&
2302+ res.data.ok !== true)
2303+ $err.text(res.data.res)
2304+ else
2305+ console.log("poke succeeded");
2306+ })
2307+ })
2308+
2309+ window.urb.appl = "click"
2310+ window.urb.bind('/the-path',
2311+ function(err,dat) {
2312+ clicks = dat.data.clicks
2313+ $clicks.text(clicks)
2314+ }
2315+ )
2316+})
2317+```
2318+
2319+We set up two event handlers. When we click the button, we run
2320+`window.urb.send`, which sends a poke to the app specified as the first argument, in this case our :click app. The arguments
2321+are data, parameters, and the callback. The data is the specific
2322+data we want to send. The parameters are all optional, but here's a list
2323+of the available ones:
2324+
2325+- `ship`: target urbit. Defaults to `window.urb.ship`, which
2326+ defaults to the urbit which served the page.
2327+- `appl`: target app. Defaults to `window.urb.appl`, which
2328+ defaults to null.
2329+- `mark`: mark of the data. Defaults to `window.urb.send.mark`,
2330+ which defaults to "json".
2331+- `wire`: wire of the poke. Defaults to `/`.
2332+
2333+In our case, we specify only that the mark is "click".
2334+
2335+The callback function is called when we receive an
2336+acknowledgment. If there was an error, we put it in the `err`
2337+div that we defined above. Otherwise, we printf to the console a
2338+message saying the poke succeeded. As is common, we gray
2339+out the button when it is clicked. It is only reenabled when positive acknowledgement is received.
2340+
2341+Our second event handler is `window.urb.bind`, which is called immediately when the page is loaded, subscribing the page to the specified data stream on the app set with `urb.appl` (which is, in this case, :click). It also takes three arguments: path, parameters, and callback. The path is the path on the app to subscribe to. The parameters are all optional (indeed, we omit them entirely here), but are similar to those for `send`:
2342+
2343+- `ship`: target urbit. Defaults to `window.urb.ship`, which defaults to the urbit which served the page.
2344+- `appl`: target app. Defaults to `window.urb.appl`, which defaults to null.
2345+- `mark`: mark of expected data. Data of other marks is converted to this mark on the server before coming to the web front end. Defaults to `window.urb.bind.mark`, which defaults to "json".
2346+- `wire`: wire of the subscription. Defaults to the given path.
2347+
2348+The callback function here just updates the data in the `clicks`
2349+div. A truly robust app would intelligently handle errors, of
2350+course.
2351+
2352+Note that the app doesn't have anything web-specific in itself.
2353+As far as it knows, it's just receiving pokes and subscriptions.
2354+The javascript is fairly pure as well, sending and receiving json
2355+everywhere. The marks are the translation layer, and they're the
2356+only things that need to know how the hoon types map to json.
2357+
2358+*Exercise*:
2359+
2360+- Open the app in multiple tabs, click the button, and verify that all the tabs stay in sink. Poke it manually from the command line and verify the tabs are updated as well.
learn/arvo/arvo-internals/gall/api.udondeleted−509
@@ -1,509 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− sort/'9'
4− title/'API Connectors'
5− ==
6−;>
7−
8−# API Connectors
9−
10−> Note: This lesson depends on some code that needs to be updated before the examples will work correctly. This will be addressed in the near future. We apologize!
11−
12−Most people have lots of data stored in online services, many of
13−which have APIs. API connectors allow the user to access this
14−data from within their Urbit.
15−
16−A security driver allows the user to make authenticated requests
17−to the service's API, but the user still needs to know the API
18−and send and receive JSON. An API connector puts a layer of
19−porcelain over this to allow the user easier control over their
20−data.
21−
22−Each connector should perform two basic functions. First, it
23−should expose a tree of the data in the service that's accessible
24−through `.^` and FUSE. Second, it should expose event streams as
25−actions occur in the service. Let's take a look at how the `%gh`
26−app accomplishes both for Github.
27−
28−After starting `%gh` (`|start %gh`), let's look at the root of
29−the tree that `%gh` exposes:
30−
31−```
32−~your-urbit:dojo> .^(arch %gy /=gh=)
33−[fil=~ dir={[p=~.issues q=~]}]
34−```
35−
36−`%gh` is currently a skeleton -- it contains examples of all the
37−functionality necessary for a connector, but many endpoints
38−aren't implemented. As we can see here, only issues are
39−implemented. We can explore this tree:
40−
41−```
42−~your-urbit:dojo> .^(arch %gy /=gh=/issues)
43−[fil=~ dir={[p=~.by-repo q=~] [p=~.mine q=~]}]
44−```
45−
46−And eventually:
47−
48−```
49−/- gh
50−.^(issue:gh %gx /=gh=/issues/by-repo/philipcmonktest/testing/7)
51−<issue...>
52−login.user:.^(issue:gh %gx /=gh=/issues/by-repo/philipcmonktest/testing/7)
53−'philipcmonktest'
54−```
55−
56−The other thing an API connector needs to do is expose event
57−streams. One straightforward way to use this capacity is with
58−the `:pipe` app:
59−
60−```
61−:pipe|connect %gh /listen/philipcmonktest/testing/issues/'issue_comment' %public
62−```
63−
64−Now creating an issue results in the following message in your
65−`%public` `:talk` channel:
66−
67−```
68−~your-urbit[philipcmonktest@github]: opened issue #11: i found a bug!
69−```
70−
71−You'll also get notifications of issue status changes and
72−comments.
73−
74−As is often the case, the best way to write an API connector is
75−to copy an existing one and modify it. We'll dissect the Github
76−connector here. This code is in `/=home=/app/gh/hoon`, and it's
77−also reproduced at the bottom of this page (in case the code
78−drifts out of sync with this doc).
79−
80−We'll go over the two parts to an API connector (one-time reading vs listening
81−for events) separately.
82−
83−## Reading
84−
85−A connector exposes a tree of data. Every read request has a
86−`care`, which is generally either `%x` or `%y. `%x` is a request
87−for a particular piece of data, while `%y` is a request for a
88−directory listing. Roughly, `%x` means Unix `cat` and `%y` means
89−Unix `ls`.
90−
91−> Sometimes you wish to expose a tree where a part of the path can't be enumerated. For example, a `%y` of `/issues/by-repo` "should" produce a list of all Github users, but we don't do that because it's too long. Instead, we just produce our own username (from the `web.plan` file). You can still access repos from other users, you just don't see them in the directory listing.
92−
93−The usual flow for implementing this tree of data makes heavy use
94−of the `connector` library. This library is well documented in
95−the source, so check out `/=home=/lib/connector/hoon`.
96−
97−The `connector` library needs to be initialized with definitions
98−of `move` and `sub-result` (all the types of data that can be
99−returned by a place). This can just be a line at the top of the
100−main core:
101−
102−```
103−=+ connector=(connector move sub-result) :: Set up connector library
104−```
105−
106−Most of the Github-specific logic is in `++places`, which is a
107−list of all the places we can request. A place consists of:
108−
109−```
110−++ place
111− $: guard/mold
112− read-x/$-(path move)
113− read-y/$-(path move)
114− sigh-x/$-(jon/json (unit sub-result))
115− sigh-y/$-(jon/json (unit arch))
116− ==
117−```
118−
119−- `guard`, the type of the paths we should match. For example, to match `/issues/<user>/<repo>` use `{$issues @t @t $~}`.
120−
121−- `read-x`, called when someone tries to read the place with `care` `%x`. Should produce a single move, usually either a `%diff` response if we can immediately answer or a `%hiss` http request if we need to make a request to the api. See the `++read-*` functions in `++helpers` for some common handlers.
122−
123−- `read-y`, same as `read-x` except with care `%y`.
124−
125−- `sigh-x`, called when an http response comes back on this place. You're given the json of the result, and you should produce either a result or null. Null represents an error. If you didn't create an http request in `read-x`, then this should never be called. Use `++sigh-strange` from `++helpers` to unconditionally signal an error.
126−
127−- `sigh-y`, same as `sigh-x` except with care `%y`. Note that a `%y` request must produce an arch, unlike a `%x` request, which may produce data of any mark.
128−
129−Filling out the list of places is a lot of grunt work, but most
130−places are fairly straightforward, and the `++read-*` helper
131−functions are useful. Check out the library source for more
132−information on those.
133−
134−Besides the list of places, we just need to handle the flow of
135−control. `++peek` and `++peer-scry` are the interface we expose
136−to the rest of the system while `++sigh-httr` and `++sigh-tang`
137−are used to handle responses when we make HTTP requests.
138−
139−- `++peek` should usually just produce `~`. If there are cases where we can respond directly to a `.^` request without blocking on anything, we could do it here, but it's generally not worth the hassle since the same logic should be duplicated in `++peer-scry`.
140−
141−- `++peer-scry` is where the actual handling for a read request goes. In general, we just need to call `++read` from the `connector` library with the bone, list of places, care, and path. This will match the path to the appropriate place and run either `++read-x` or `++read-y`, depending on the care.
142−
143−- If `++read-x` or `++read-y` made a successful API request, then the response will come back on `++sigh-httr`. Here, we just need to parse out the wire and call `++sigh` from the `connector` library with the list of places, care, path, and HTTP result. This will match the path to the appropriate place and run either `++sigh-x` or `++sigh-y`, depending on the care.
144−
145−- If `++read-x` or `++read-y` made an API request that failed, then we'll get a stack trace in `++sigh-tang`. Here, we just print it out and move on.
146−
147−That's really all there is to the reading portion of API
148−connectors.
149−
150−One of the most accessible ways to jump into Arvo programming is
151−to just add more places to an existing API connector. It's
152−useful, small in scope, and comes in bite-sized chunks since most
153−places are less than ten lines of code.
154−
155−## Listening
156−
157−Listening for events is fairly service-specific. In some
158−services, we poll for changes. The Twitter connector has an
159−example of this, but note that it predates the `connector`
160−library and is thus more complicated than it needs to be, and the
161−interface it exposes isn't standard. In Github, we power our
162−event streams with webhooks.
163−
164−For Github, when someone subscribes to
165−`/listen/<user>/<repo>/<events...>`, we want to produce
166−well-typed results when they occur.
167−
168−We only want to create one webhook per event, so in our state we
169−have `hook`, which is a map of event names to the set of bones
170−which are subscribed to that event. We must always keep this
171−up-to-date.
172−
173−Flow of control starts in `++peer-listen`, where we just call
174−`++listen`. In `++listen`, for each event in the list of events,
175−we check to see if we have that hook set up (by checking whether
176−it exists in `hook`). If so, we call `++update-hook` to add the
177−current bone to the set of listeners. Otherwise, we call
178−`++create-hook`, which sends a request to Github to set up the
179−new webhook. We also create an entry in `hook` with the current
180−bone.
181−
182−When we created the webhook, we told Github to send the event to
183−`/~/to/gh/gh-<event>.json?anon&wire=/`. This turns into a poke.
184−Let's parse out this url. The first `gh` is the app name to
185−poke. The next portion, `gh-<event>` is the mark to convert the
186−JSON to. For example, when the "issues" event fires, it'll get
187−converted to mark `gh-issues`. This mark has a conversion
188−routine from `json` to the `issues` type, which is defined in the
189−`gh` structure (`/=home=/sur/gh/hoon`). Once this conversion
190−happens, the `gh` app will get poked with the correctly marked
191−data in `++poke`.
192−
193−In `++poke`, we check `hook` to find the subscribers to the event
194−that was fired, and we update them.
195−
196−That's really all there is to it. Webhook flow isn't well
197−standardized, so even if your chosen service is powered by
198−webhooks, your listening code might look rather different. The
199−point is to expose the correct interface.
200−
201−
202−## Github API Connector Code
203−
204−In case the code in `/=home=/app/gh/hoon` drifts out of sync with
205−this doc:
206−
207−```
208−:: This is a connector for the Github API v3.
209−::
210−:: You can interact with this in a few different ways:
211−::
212−:: - .^({type} %gx /=gh={/endpoint}) to read data or
213−:: .^(arch %gy /=gh={/endpoint}) to explore the possible
214−:: endpoints.
215−::
216−:: - subscribe to /listen/{owner}/{repo}/{events...} for
217−:: webhook-powered event notifications. For event list, see
218−:: https://developer.github.com/webhooks/.
219−::
220−:: This is written with the standard structure for api
221−:: connectors, as described in lib/connector.hoon.
222−::
223−/? 314
224−/- gh, plan-acct
225−/+ gh-parse, connector
226−::
227−!:
228−=> |%
229− +$ move (pair bone card)
230− +$ card
231− $% [%diff sub-result]
232− [%them wire (unit hiss:eyre)]
233− [%hiss wire [%~ %~] %httr [%hiss hiss:eyre]]
234− ==
235− ::
236− :: Types of results we produce to subscribers.
237− ::
238− +$ sub-result
239− $% [%arch arch]
240− [%gh-issue issue:gh]
241− [%gh-list-issues (list issue:gh)]
242− [%gh-issues issues:gh]
243− [%gh-issue-comment issue-comment:gh]
244− [%json json]
245− [%null %~]
246− ==
247− ::
248− :: Types of webhooks we expect.
249− ::
250− +$ hook-response
251− $% [%gh-issues issues:gh]
252− [%gh-issue-comment issue-comment:gh]
253− ==
254− --
255−=+ connector=(connector move sub-result) :: Set up connector library
256−::
257−|_ $: hid=bowl:gall
258− hook=(map @t [id=@t listeners=(set bone)]) :: map events to listeners
259− ==
260−:: ++ prep _`. :: Clear state when code changes
261−::
262−:: List of endpoints
263−::
264−++ places
265− |= wir=wire
266− ^- (list place:connector)
267− =+ (helpers:connector ost.hid wir "https://api.github.com")
268− => |% :: gh-specific helpers
269− ++ sigh-list-issues-x
270− |= jon=json
271− %+ bind ((ar:jo issue:gh-parse) jon)
272− |= issues=(list issue:gh)
273− gh-list-issues+issues
274− ::
275− ++ sigh-list-issues-y
276− |= jon=json
277− %+ bind ((ar:jo issue:gh-parse) jon)
278− |= issues=(list issue:gh)
279− :- `(shax (jam issues))
280− (malt (turn issues |=(issue:gh [(rsh 3 2 (scot %ui number)) ~])))
281− --
282− :~ ^- place :: /
283− :* guard=,%~
284− read-x=read-null
285− read-y=(read-static %issues ~)
286− sigh-x=sigh-strange
287− sigh-y=sigh-strange
288− ==
289− ^- place :: /issues
290− :* guard=,[%issues %~]
291− read-x=read-null
292− read-y=(read-static %mine %by-repo ~)
293− sigh-x=sigh-strange
294− sigh-y=sigh-strange
295− ==
296− ^- place :: /issues/mine
297− :* guard=,[%issues %mine %~]
298− read-x=(read-get /issues)
299− read-y=(read-get /issues)
300− sigh-x=sigh-list-issues-x
301− sigh-y=sigh-list-issues-y
302− ==
303− ^- place :: /issues/by-repo
304− :* guard=,[%issues %by-repo %~]
305− read-x=read-null
306− ^= read-y
307− |= pax=path
308− =+ /(scot %p our.hid)/home/(scot %da now.hid)/web/plan
309− =+ .^([* acc=(map knot plan-acct)] %cx -)
310− ::
311− ((read-static usr:(~(got by acc) %github) ~) pax)
312− sigh-x=sigh-strange
313− sigh-y=sigh-strange
314− ==
315− ^- place :: /issues/by-repo/<user>
316− :* guard=,[%issues %by-repo @t %~]
317− read-x=read-null
318− read-y=|=(pax=path (get /users/[-.+>.pax]/repos))
319− sigh-x=sigh-strange
320− ^= sigh-y
321− |= jon=json
322− %+ bind ((ar:jo repository:gh-parse) jon)
323− |= repos=(list repository:gh)
324− [~ (malt (turn repos |=(repository:gh [name ~])))]
325− ==
326− ^- place :: /issues/by-repo/<user>/<repo>
327− :* guard=,[%issues %by-repo @t @t %~]
328− read-x=|=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues))
329− read-y=|=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues))
330− sigh-x=sigh-list-issues-x
331− sigh-y=sigh-list-issues-y
332− ==
333− ^- place :: /issues/by-repo/<user>/<repo>
334− :* guard=,[%issues %by-repo @t @t @t %~]
335− ^= read-x
336− |=(pax=path (get /repos/[-.+>.pax]/[-.+>+.pax]/issues/[-.+>+>.pax]))
337− ::
338− read-y=(read-static ~)
339− ^= sigh-x
340− |= jon=json
341− %+ bind (issue:gh-parse jon)
342− |= issue=issue:gh
343− gh-issue+issue
344− ::
345− sigh-y=sigh-strange
346− ==
347− ==
348−::
349−:: When a peek on a path blocks, ford turns it into a peer on
350−:: /scry/{care}/{path}. You can also just peer to this
351−:: directly.
352−::
353−:: We hand control to ++scry.
354−::
355−++ peer-scry
356− |= pax=path
357− ^- [(list move) _+>.$]
358− ?> ?=([care:clay *] pax)
359− :_ +>.$ :_ ~
360− (read:connector ost.hid (places %read pax) i.pax t.pax)
361−::
362−:: HTTP response. We make sure the response is good, then
363−:: produce the result (as JSON) to whoever sent the request.
364−::
365−++ sigh-httr
366− |= [way=wire res=httr:eyre]
367− ^- [(list move) _+>.$]
368− ?. ?=([%read care:clay @ *] way)
369− ~& res=res
370− [~ +>.$]
371− =* style i.way
372− =* ren i.t.way
373− =* pax t.t.way
374− :_ +>.$ :_ ~
375− :+ ost.hid %diff
376− (sigh:connector (places ren style pax) ren pax res)
377−::
378−:: HTTP error. We just print it out, though maybe we should
379−:: also produce a result so that the request doesn't hang?
380−::
381−++ sigh-tang
382− |= [way=wire tan=tang]
383− ^- [(list move) _+>.$]
384− %- (slog >%gh-sigh-tang< tan)
385− [[ost.hid %diff null+~]~ +>.$]
386−::
387−:: We can't actually give the response to pretty much anything
388−:: without blocking, so we just block unconditionally.
389−::
390−++ peek
391− |= [ren=@tas tyl=path]
392− ^- (unit (unit (pair mark *)))
393− ~ ::``noun=[ren tyl]
394−::
395−::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
396−:: Webhook-powered event streams (/listen) ::
397−::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
398−::
399−:: To listen to a webhook-powered stream of events, subscribe
400−:: to /listen/<user>/<repo>/<events...>
401−::
402−:: We hand control to ++listen.
403−::
404−++ peer-listen
405− |= pax=path
406− ^- [(list move) _+>.$]
407− ?. ?=([@ @ *] pax)
408− ~& [%bad-listen-path pax]
409− [~ +>.$]
410− (listen pax)
411−::
412−:: This core handles event subscription requests by starting or
413−:: updating the webhook flow for each event.
414−::
415−++ listen
416− |= pax=path
417− =| mow=(list move)
418− =< abet:listen
419− |%
420− ++ abet :: Resolve core.
421− ^- [(list move) _+>.$]
422− [(flop mow) +>.$]
423− ::
424− ++ send-hiss :: Send a hiss
425− |= hiz=hiss:eyre
426− ^+ +>
427− =+ wir=`wire`[%x %listen pax]
428− +>.$(mow [[ost.hid %hiss wir `~ %httr [%hiss hiz]] mow])
429− ::
430− :: Create or update a webhook to listen for a set of events.
431− ::
432− ++ listen
433− ^+ .
434− =+ pax=pax :: TMI-proofing
435− ?> ?=([@ @ *] pax)
436− =+ events=t.t.pax
437− |- ^+ +>+.$
438− ?~ events
439− +>+.$
440− ?: (~(has by hook) i.events)
441− $(+>+ (update-hook i.events), events t.events)
442− $(+>+ (create-hook i.events), events t.events)
443− ::
444− :: Set up a webhook.
445− ::
446− ++ create-hook
447− |= event=@t
448− ^+ +>
449− ?> ?=([@ @ *] pax)
450− =+ clean-event=`tape`(turn (trip event) |=(a=@tD ?:(=('_' a) '-' a)))
451− =. hook
452− %+ ~(put by hook) (crip clean-event)
453− =+ %+ fall
454− (~(get by hook) (crip clean-event))
455− *[id=@t listeners=(set bone)]
456− [id (~(put in listeners) ost.hid)]
457− %- send-hiss
458− :* %+ scan
459− =+ [(trip i.pax) (trip i.t.pax)]
460− "https://api.github.com/repos/{-<}/{->}/hooks"
461− auri:de-purl:html
462− %post ~ ~
463− %- as-octs:mimes:html %- crip %- en-json:html %- pairs:enjs:format :~
464− name+s+%web
465− active+b+&
466− events+a+~[s+event] ::(turn `(list ,@t)`t.t.pax |=(a=@t s=a))
467− :- %config
468− %- pairs:enjs:format :~
469− =+ =+ clean-event
470− "http://107.170.195.5:8443/~/to/gh/gh-{-}.json?anon&wire=/"
471− [%url s+(crip -)]
472− [%'content_type' s+%json]
473− ==
474− ==
475− ==
476− ::
477− :: Add current bone to the list of subscribers for this event.
478− ::
479− ++ update-hook
480− |= event=@t
481− ^+ +>
482− =+ hok=(~(got by hook) event)
483− %_ +>.$
484− hook
485− %+ ~(put by hook) event
486− hok(listeners (~(put in listeners.hok) ost.hid))
487− ==
488− --
489−::
490−:: Pokes that aren't caught in more specific arms are handled
491−:: here. These should be only from webhooks firing, so if we
492−:: get any mark that we shouldn't get from a webhook, we reject
493−:: it. Otherwise, we spam out the event to everyone who's
494−:: listening for that event.
495−::
496−++ poke
497− |= response=hook-response
498− ^- [(list move) _+>.$]
499− =+ hook-data=(~(get by hook) (rsh 3 3 -.response))
500− ?~ hook-data
501− ~& [%strange-hook hook response]
502− [~ +>.$]
503− :: ~& response=response
504− :_ +>.$
505− %+ turn ~(tap in listeners.u.hook-data)
506− |= ost=bone
507− [ost %diff response]
508−--
509−```
learn/arvo/arvo-internals/gall/generators.udondeleted−172
@@ -1,172 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− next/'true'
4− sort/'6'
5− title/'Using generators with apps'
6− ==
7−;>
8−
9−# Generators
10−
11−Up until now we've poked apps directly. This requires the user to
12−specify the mark, and it requires the app to accept the arguments in a
13−way that's convenient for users to input. This is the "plumbing" way to
14−interact with apps. Generators are the "porcelain" layer. This is why
15−when you run a command like `+ls` or `|merge`, there are no marks in
16−sight.
17−
18−We've used generators before, back in [Basic
19−Operation](/docs/using/admin). At that point, we just used the
20−generators to produce values -- we didn't pipe their results into apps.
21−In the dojo cast, the role of a generator is to take a list of arguments
22−and produce a value, which is often, though not always, piped into an
23−app. Generators are pure, stateless functions, and they cannot send
24−moves.
25−
26−`+ls` and `+cat` are commonly-used generators that produce a directory
27−listing and print out a file, respectively. These are useful in
28−themselves, so we generally don't pipe the results into an app.
29−
30−Another generator is `+hood/merge`. Try running `+hood/merge` with the
31−normal arguments for `|merge`:
32−
33−```
34−> +hood/merge %home our %they
35−[syd=%home her=~zod sud=%they cas=[%da p=~2018.10.4..21.11.49..901c] gem=%auto]
36−
37−> +hood/merge %home our %they, =gem %this
38−[syd=%home her=~zod sud=%they cas=[%da p=~2018.10.4..21.12.11..ee32] gem=%this]
39−```
40−
41−This didn't run any merge, it just constructed the command that, if sent
42−to `:hood`, would run it. Note first that, even though it's not printed,
43−this value has mark `kiln-merge`. Also, the merge strategy `gem=%auto`
44−was added automatically. Optional arguments are straightforward with
45−generators.
46−
47−In general, generators are prepended by either `+` or `|`. The general
48−form is `+generator`, but often generators are created specifically to
49−work with a single app, they're usually placed in a subdirectory of gen
50−and run with `|`. Thus, if `my-generator` generator is made for use with
51−`:my-app`, then `my-generator` is put in
52−`/gen/my-app/my-generator.hoon`, and can be run directly with
53−`+my-app/my-generator <args>`. If you want to pipe the result into
54−`:my-app`, then run `:my-app +my-app/my-generator <args>`. Because this
55−pattern is so common, this can be abbreviated to
56−`:my-app|my-generator <args>`. Because most built-in commands are
57−generators for the `:hood` app, `:hood|generator <args>` can be
58−shortened to `|generator <args>`.
59−
60−Let's write a generator for a modified version of `:pong` from
61−the chapter on [Network Messages](/docs/arvo/system/network). Recall
62−that `:pong` takes an urbit address, which is of mark `urbit`,
63−and sends that urbit the message `'howdy'`. First--without a
64−generator--let's make `:ping` that does the same, except that
65−it lets the user optionally specify the message as well.
66−
67−We'll need a new mark for our arguments. Let's call it
68−`ping-message`.
69−
70−> For app-specific marks, it's good style to prefix the name of the mark with the name of the app. Since many apps have several such marks, subdirectories in `/mar` are rendered as `-`, so that `ping-message` is written in (/mar/ping/message.hoon).
71−
72−```
73−::
74−:::: /mar/ping/message/hoon
75− ::
76−/? 314
77−|_ [to=@p message=@t]
78−++ grab
79− |%
80− +$ noun [@p @t]
81− --
82−--
83−```
84−
85−The app can easily be modified to use this (`/app/ping.hoon`):
86−
87−```
88−:: Allows one ship to ping another with a string of text
89−::
90−:::: /app/ping/hoon
91− ::
92−/? 314
93−|%
94− +$ move [bone term wire *]
95−--
96−!:
97−|_ [bowl:gall state=%~]
98−::
99−++ poke-ping-message
100− |= [to=@p message=@t]
101− ~& 'sent'
102− ^- [(list move) _+>.$]
103− :- ^- (list move)
104− :~ `move`[ost %poke /sending [to dap] %atom message]
105− ==
106− +>.$
107−::
108−++ poke-atom
109− |= arg=@
110− ~& 'received'
111− ^- [(list move) _+>.$]
112− ::
113− ~& [%receiving (@t arg)]
114− [~ +>.$]
115−::
116−++ coup |=(* `+>)
117−--
118−```
119−
120−Now we can run this with:
121−
122−```
123−~fintud-macrep:dojo> |start %ping
124−>=
125−
126−~fintud-macrep:dojo> :ping &ping-message [~sampel-sipnym 'heyya']
127−>=
128−```
129−
130−And on `~sampel-sipnym`, assuming it's running `:ping` as well,
131−we see `[%receiving 'heyya']`.
132−
133−This is an annoying way to invoke the app, though. The `[]` are
134−mandatory, and optional arguments are hard. Let's make a generator,
135−`+send` to make everything nicer. Since it's specific to
136−`:ping`, let's put it in `/gen/ping/send.hoon`:
137−
138−```
139−:- %say
140−|= [^ [to=@p message=?(%~ [text=@t %~])] %~]
141−[%ping-message to ?~(message 'howdy' text.message)]
142−```
143−
144−A couple of new things here. Firstly, `message=?(%~ [text=@t %~])] %~]`
145−should be read as "the message is either null or a pair of text and
146−null". Generator argument lists are always null-terminated, which makes
147−it convenient to accept lists in tail position (which are particularly
148−annoying without generators). `?(a b)` is the irregular form of
149−`$?(a b)`, which is a union type. Thus, `?(a b)` means the type of
150−anything that's in either `a` or `b`. Thus, in our case,
151−`?(~ [text=@t ~])` is either null or a pair of text and null.
152−
153−This is run as follows:
154−
155−```
156−~fintud-macrep:dojo> :ping|send ~sampel-sipnym
157−>=
158−
159−~fintud-macrep:dojo> :ping|send ~sampel-sipnym 'how do you do'
160−>=
161−```
162−
163−Which causes `~sampel-sipnym` to print `[%receiving 'howdy']` and
164−`[%receiving 'how do you do']`.
165−
166−(Note: `:ping|send ~sampel-sipnym` is short for `:ping +ping/send ~sampel-sipnym`.)
167−
168−*Exercises*:
169−
170−- Create a generator for `:sum` from [State](../../state) so that you can run `:sum|add 5` to add numbers to it.
171−
172−- Create a generator for `:click` from [Web Apps](../../web-apps) so that you can run `:click|poke` to poke it.
learn/arvo/arvo-internals/gall/http.udondeleted−215
@@ -1,215 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− next/'true'
4− sort/'7'
5− title/'HTTP requests and timers'
6− ==
7−;>
8−
9−# Writing an HTTP request
10−
11−There's a variety of arvo services we haven't touched on yet.
12−Let's figure out how to make HTTP requests and set timers.
13−
14−Let's build an uptime-monitoring system. It'll ping a web
15−service periodically and print out an error when the response
16−code isn't 2xx. Save the following as `app/up.hoon`:
17−
18−```
19−:: Up-ness monitor. Accepts atom url, 'on', or 'off'
20−::
21−:::: /hoon/up/app
22− ::
23−/? 314
24−|%
25−+$ move [bone card]
26−+$ card
27− $% [%hiss wire unit-iden=$~ mark=%httr cage=[mark=%purl vase=purl:eyre]]
28− [%wait wire @da]
29− ==
30−+$ action
31− $% [%on $~] :: enable polling('on')
32− [%off $~] :: disable polling('off)
33− [%target p=cord] :: set poll target('http://...')
34− ==
35−--
36−|_ [hid=bowl:gall on=_| in-progress=_| target=@t]
37−++ poke-atom
38− |= url-or-command=@t ^- (quip move _+>)
39− =+ ^- act/action
40− ?: ?=($on url-or-command) [%on ~]
41− ?: ?=($off url-or-command) [%off ~]
42− [%target url-or-command]
43− ?- -.act
44− $target [~ +>.$(target p.act)]
45− $off [~ +>.$(on |)]
46− $on
47− :- ?: |(on in-progress) ~
48− [ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]~
49− +>.$(on &, in-progress &)
50− ==
51−++ sigh-httr
52− |= [wir=wire code=@ud headers=mess:eyre body=(unit octs)]
53− ~& 'arrive here'
54− ^- [(list move) _+>.$]
55− ?: &((gte code 200) (lth code 300))
56− ~& [%all-is-well code]
57− :_ +>.$
58− [ost.hid %wait /timer (add ~s10 now.hid)]~
59− ~& [%we-have-a-problem code]
60− ~& [%headers headers]
61− ~& [%body body]
62− :_ +>.$
63− [ost.hid %wait /timer (add ~s10 now.hid)]~
64−++ wake-timer
65− |= [wir=wire $~] ^- (quip move _+>)
66− ?: on
67− :_ +>.$
68− [ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]~
69− [~ +>.$(in-progress |)]
70−::
71−++ prep ~& target _`. :: computed when the source file changes;
72−-- :: here it prints target then resets our state
73−```
74−
75−There's some fancy stuff going on here. We'll go through it line by
76−line, though.
77−
78−There's two kinds of cards we're sending to arvo. A `%hiss` move tells
79−`%eyre` to make an HTTP request. It expects a `(unit iden)`, which will
80−be null here because we aren't doing any authentication; a mark, in this
81−case the http request mark `&httr`; and some data in the form of a
82−`cage`, which is a `[mark vase]`. This is confusing, so the mold in the
83−code quoted above includes a bunch of otherwise unnecessary faces for
84−the purpose of illustration. Compare: `[%hiss p=(unit iden) q=mark
85−r=cage]` from `zuse`.
86−
87−> You can grep zuse.hoon and arvo.hoon for most of these definitions. However, beware the ambiguity surrounding "hiss": there's ++hiss in section 3bI of `zuse` ("Arvo structures"), and there's `%hiss` the move that is sent to %eyre to make our HTTP request happen. Here we're talking about the latter. See `++kiss-eyre` in `zuse`.
88−
89−> Recall that `++unit` means "maybe". Formally, "`(unit a)` is either null or a pair of null and a value in `a`". Also recall that to pull a value out of a unit (`u.unit`), you must first verify that the unit is not null (for example with `?~`). See `++need`.
90−
91−A `purl:eyre` is a parsed url structure, which can be created with `de-purl:html`,
92−which is a function that takes a url as text and parses it into a `(unit
93−purl:eyre)`. Thus, the result is null if and only if the url is malformed.
94−'Purl' is also the mark which will be applied to this result.
95−
96−When you send this request, you can expect a `%sigh` with the
97−response, which we handle later on in `++sigh-httr`.
98−
99−For `%wait`, you just pass a [`@da`]() (absolute date), and arvo will
100−produce a `%wake` when the time comes.
101−
102−> A timer is guaranteed to not be triggered before the given time, but it's currently impossible to guarantee the timer will be triggered at exactly the requested time.
103−
104−Let's take a look at our state:
105−
106−```
107−|_ [hid=bowl:gall on=_| in-progress=_| target=@t]
108−```
109−
110−We have three pieces of app-specific state. `target` is the url
111−we're monitoring. `on` and `in-progress` are booleans
112−representing, respectively, whether or not we're supposed to keep
113−monitoring and whether or not we're in the middle of a request.
114−
115−The type of booleans is usually written as `?`, which is a union
116−of `&` (true) and `|` false. This type defaults to `&` (true). In our
117−case, we want both of these to default to `|` (false). Because
118−of that, we use `_|` as the type. `_value` means "take the type
119−of `value`, but make the default value be `value`". Thus, our
120−type is still a boolean, just like `?`, but the default value is
121−`|` (false).
122−
123−> This is the same `_` used in `_+>.$`, which means "the same type as the value "+>.$". In other words, the same type as our current context and state.
124−
125−Let's take a look at `++poke-atom`. When we're poked with an atom, we
126−first check whether the atom is `'off'`. If so, we set our state
127−variable `on` to false.
128−
129−If not, we check whether the atom is `'on'`. If so, we set `on` and
130−`in-progress` to true. If it was already either on or in progress, then
131−we don't take any other immediate action. If it was both off and not in
132−progress, then we send an HTTP request.
133−
134−If the argument is neither 'off' nor 'on', then we assume it's an
135−actual url, so we save it in `target`.
136−
137−Here's the move that sends the HTTP request:
138−
139−```
140−[ost.hid %hiss /request ~ %httr %purl (need (de-purl:html target))]
141−```
142−
143−> Remember, we are expected to produce a *list* of moves. Note the `~` after the move in the full example. This is a convenient shortcut for creating a list of a single element. It's part of a small family of such shortcuts. `~[a b c]` is `[a b c ~]`, `[a b c]~` is `[[a b c] ~]` and `\`[a b c]` is `[~ a b c]`. These may be mixed and matched to create various convoluted structures and emojis.
144−
145−The correspondence between this move and `[bone card]` can be hard to
146−visualize on one line. Here it is more pedantically:
147−
148−```
149−:* bone=ost.hid :: the move
150− term=%hiss
151− wire=/request
152− unit-iden=~
153− mark=%httr
154− cage=[%purl (need (de-purl:html target))]
155−==
156−```
157−
158−When the HTTP response comes back, we handle it with
159−`++sigh-httr`, which, along with the wire the request was sent
160−on, takes the status code, the response headers, and the response
161−body.
162−
163−We check whether the status code is between 200 and 300. If so,
164−all is well, and we print a message saying so. We start the
165−timer for ten seconds after the present time.
166−
167−If we got a bad status code, then we print out the entire
168−response and start the timer again.
169−
170−After ten seconds, arvo will give us a `%wake` event, which will
171−be handled in `++wake-timer`. If we're still supposed to keep
172−monitoring, we send the same HTTP request as before. Otherwise,
173−we set `in-progress` to false.
174−
175−Let's try it out:
176−
177−```
178−~fintud-macrep:dojo> |start %up
179−>=
180−~fintud-macrep:dojo> :up &atom 'http://www.google.com'
181−>=
182−[%all-is-well 200]
183−[%all-is-well 200]
184−~fintud-macrep:dojo> :up &atom 'http://example.com'
185−>=
186−[%all-is-well 200]
187−~fintud-macrep:dojo> :up &atom 'http://google.com'
188−>=
189−[%we-have-a-problem 301]
190−[ %headers
191− ~[
192− [p='X-Frame-Options' q='SAMEORIGIN']
193− [p='X-XSS-Protection' q='1; mode=block']
194− [p='Content-Length' q='219']
195− [p='Server' q='gws']
196− [p='Cache-Control' q='public, max-age=2592000']
197− [p='Expires' q='Sun, 10 Jan 2016 23:45:05 GMT']
198− [p='Date' q='Fri, 11 Dec 2015 23:45:05 GMT']
199− [p='Content-Type' q='text/html; charset=UTF-8']
200− [p='Location' q='http://www.google.com/']
201− ]
202−]
203−[ %body
204− [ ~
205− [ p=219
206− q
207− \/'<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">\0a<TITLE>301 Moved</TI\/
208− TLE></HEAD><BODY>\0a<H1>301 Moved</H1>\0aThe document has moved\0a<A HREF="http://www.google.com/">her
209− e</A>.\0d\0a</BODY></HTML>\0d\0a'
210− \/ \/
211− ]
212− ]
213−]
214−~fintud-macrep:dojo> :up &atom 'off'
215−```
learn/arvo/arvo-internals/gall/marks.udondeleted−128
@@ -1,128 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− next/'true'
4− sort/'4'
5− title/'Marks'
6− ==
7−;>
8−
9−# Marks
10−
11−We've used predefined marks already, but we haven't yet created
12−our own marks. Let's write a sample mark of our own, then chain
13−it together with some preexisting ones to have fun with type
14−conversions.
15−
16−Let's make a small "cord" mark. "Cord" is a name we use for `@t`
17−text, but there's no predefined mark for it. Let's put the following code in:
18−`/mar/cord.hoon`:
19−
20−```
21−/? 314
22−|_ cod=@t
23−++ grab
24− |%
25− ++ atom |=(arg=@ `@t`(scot %ud arg))
26− --
27−++ grow
28− |%
29− ++ md cod
30− --
31−--
32−```
33−
34−`/? 314` is the required
35−version number, just like in apps. After that everything's in a
36−`|_`, which is a `|%` core, but with input arguments. In our
37−case, the argument is the marked data.
38−
39−There are three possible top-level arms in the `|_` core,
40−`++grab`, `++grow`, and `++grad` (which is used for revision
41−control, covered elsewhere). `++grab` specifies
42−functions to convert from another mark to the current mark.
43−`++grow` specifies how to convert from the current mark to
44−another one.
45−
46−In our case, we only define one arm in `++grab`, namely `++atom`.
47−This allows us to convert any atom to a cord. `++scot` is a
48−standard library function in `hoon.hoon` which pretty-prints
49−atoms of various types. We want to treat the atom as an
50−unsigned decimal number, so we give `%ud` and the given argument
51−to `++scot`. Thus, the form of an arm in `++grab` is
52−`|=(other-mark-type this-mark-value)`.
53−
54−In `++grow`, we just convert to the `md` mark, which is just a
55−`@t` internally, but it has fancy conversion functions to things
56−like html. `++md` isn't a function because the "argument" is
57−already a `@t`, so we can just produce the new value directly.
58−
59−Let's play around a bit with this mark. First, let's take a
60−marked atom and convert it to our new mark.
61−
62−```
63−~fintud-macrep:dojo> &atom 9
64−9
65−
66−~fintud-macrep:dojo> &cord &atom 9
67−'9'
68−
69−~fintud-macrep:dojo> &cord &atom &cord &atom 9
70− '57'
71−```
72−
73−ASCII 9 is 57. There's no requirement, implicit or otherwise,
74−that conversions back and forth between marks be inverses of each
75−other. These are semantic conversions, in that they refer to the
76−same concept. They're not isomorphisms.
77−
78−Let's play around a little more:
79−
80−```
81−~fintud-macrep:dojo> &md &cord &atom 17
82−'17'
83−
84−~fintud-macrep:dojo> &hymn &md &cord &atom 17
85−[ [%html ~]
86− [[%head ~] ~]
87− [[%body ~] [g=[n=%pre a=~] c=~[[g=[n=%$ a=~[[n=%$ v="17"]]] c=~]]] ~]
88− ~
89−]
90−```
91−
92−That was exciting. If you squint at that, it looks an
93−awful lot like html. Our value `17` is still in there, in the
94−body. `urb` is the mark we render most web pages to. It makes
95−sure you have a complete skeleton of a web page. Of course, by
96−the time this gets to the web page, it's plain html. Let's do
97−the final step in the conversion.
98−
99−```
100−~fintud-macrep:dojo> &mime &hymn &md &cord &atom 17
101−[[%text %html ~] p=52 q='<html><head></head><body><pre>17</pre></body></html>']
102−```
103−
104−This is a mime-typed octet stream with type `/text/html`, length
105−121 bytes, and our lowly number `17` rendered to a web page.
106−`cord` was just one step in the chain.
107−
108−Of course, arvo can infer some parts of this chain:
109−
110−```
111−~fintud-macrep:dojo> &cord 17
112−'17'
113−```
114−
115−Likewise, `md` is the only way to get from `cord` to `hymn`, so
116−that can be omitted. If we omit the `hymn`, though, we get:
117−
118−```
119−~fintud-macrep:dojo> &mime &cord 17
120−[[%text %x-markdown ~] p=2 q='17']
121−```
122−
123−Here, we converted straight from `cord` to `md` to `mime`. Arvo
124−decided that was the most straightforward conversion, but it
125−gives a different result than passing it through the `hymn`
126−mark.
127−
128−The minimal correct input, then, is `&mime &hymn &cord &atom 17`.
learn/arvo/arvo-internals/gall/network.udondeleted−353
@@ -1,353 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− next/'true'
4− sort/'1'
5− title/'Network messages'
6− ==
7−;>
8−
9−# Network messages
10−
11−In the following we assume that you have some knowledge of Hoon. If you don't, check out chapters 1 and 2 of the Hoon tutorial and check back when you're ready.
12−
13−Let's get our planets to talk to each other. To listen for and receive messages from other planets, we'll need an app. Let's look at a very simple one, `echo.hoon`:
14−
15−```
16−:: Accepts any noun from dojo and prints it out
17−::
18−:::: /===/app/echo/hoon
19− ::
20−!: :: enables debug printfs
21−|% :: forms a core with subject as payload
22−+$ move [bone card] :: defines echo app's arvo move mold
23−+$ card $% $~ :: defines card (data) mold as null tagged union
24− == :: end of mold definition; see $%
25−-- :: end of card arm definition
26−:: ::
27−|_ [bow=bowl:gall $~] :: forms a core with bowl (app state) as sample
28−++ poke-noun :: begin definition of poke-noun arm
29− |= non=* :: forms a gate which accepts any noun
30− ^- [(list move) _+>.$] :: casts product to mold of moves and context
31− ~& echo+noun+non :: debug printf, i.e. '[%echo %noun *]'
32− [~ +>.$] :: produce a cell of empty list and our state
33−-- :: end of poke-noun arm definition
34−```
35−
36−Save this as `echo.hoon` in the `/app` directory of your urbit's pier.
37−
38−This is a very simple app that does only one thing. If you poke it with
39−a value, it prints that value out. To try this out, you have to start
40−the app, then you can poke it from the command line with the following
41−commands:
42−
43−```
44−~fintud-macrep:dojo> |start %echo
45−>=
46−
47−~fintud-macrep:dojo> :echo 5
48−[%echo %noun 5]
49−>=
50−
51−~fintud-macrep:dojo> :echo [1 2]
52−[%echo %noun [1 2]]
53−>=
54−```
55−
56−> There is currently a bug where the `[%echo %noun *]` lines are printed *above* the line you entered, so your output may not look exactly like this. `>=` means that a command was successfully received and executed.
57−
58−Most of the app code should be simple enough to guess its function. The
59−important part of this code is the definition of `++poke-noun`.
60−
61−Once an app starts, it's always running in the background and you interact with
62−it by sending it messages. The most straightforward way to do that is to poke it
63−from the command line, which we we did with `:echo 5`
64−(`:[app-name] [argument(s)]`).
65−
66−In this case, `++poke-noun` takes an argument (*sample*) `arg` and
67−prints it to dojo with `~&` ([sigpad](../../../reference/rune/sig/pad/)).
68−This is an unusual rune that formally "does nothing", but the interpreter
69−detects it and printfs the first child, before executing the second as if the
70−first didn't exist. This is a slightly hacky way of printing to the console,
71−but we'll get to the correct way later on.
72−
73−But what does `++poke-noun` produce? Recall that `^-` casts to a type. In this
74−case, it's declaring that the end result (*product*) of the function
75−(`++poke-noun`'s *gate*) will be of type `[(list) _+>.$]`. But what does this
76−mean?
77−
78−The phrase to remember is "a list of moves and our state". Urbit is a message
79−passing system, so whenever we want to do something that interacts with the rest
80−of the system, we send a message. Thus, a move is Arvo's equivalent of a
81−syscall. The first thing that `++poke-noun` produces is a list of messages,
82−called "moves". In this case, we don't actually want the system to do anything,
83−so we produce the empty list, `~` (in the `[~ +>.$]` line).
84−
85−The second thing `++poke-noun` produces is our state. `+>.$` refers to a
86−particular address in our subject where our formal app state is stored.
87−It'll become clear why this is later on, but for now pretend that `+>.$`
88−is a magic invocation that means "app state".
89−
90−Let's look at another example. Say we want to
91−only accept a number, and then print out the square of that number.
92−
93−```
94−:: Accepts an atom from the dojo and squares it.
95−::
96−:::: /===/app/square/hoon
97− ::
98−!:
99−|% :: no moves in :square
100−+$ move [bone card] :: no cards in :square
101−+$ card $% $~
102− ==
103−--
104−:: :: stateless
105−|_ [bow=bowl:gall $~]
106−++ poke-atom
107− |= tom=@
108− ^- [(list move) _+>.$]
109− ~& square+(mul tom tom)
110− [~ +>.$]
111−--
112−```
113−
114−Save this as `square.hoon` in the `/app` directory of your urbit's pier.
115−
116−A few things have changed. Firstly, we no longer accept arbitrary nouns because
117−we can only square atoms (integers, in this case an unsigned one). Thus, our
118−argument is now `tom=@`. Secondly, it's `++poke-atom` rather than `++poke-noun`.
119−
120−## Intro to marks
121−
122−Are there other `++poke`s? Yes. In fact, `noun` and `atom` are just two
123−of arbitrarily many "marks". A mark is fundamentally a type definition,
124−but accessible at the Arvo level. Each mark is defined in the `/mar`
125−directory. Some marks have conversion routines to other marks, and some
126−have diff, patch, and merge algorithms. None of these are required for a
127−mark to exist, however.
128−
129−`noun` and `atom` are two predefined marks. In your `/mar` directory,
130−there are already many more, and you may add more at will. The type
131−associated with `noun` is `*`, and the type associated with `atom` is
132−`@`.
133−
134−When we poke an app from anywhere, we do so with a mark that searches
135−for the corresponding (`++poke-[mark]`) arm. Data constructed on the
136−command line is by default marked with `noun`. In this case, the app is
137−expecting an atom, so we have to explicitly mark the data with `atom`
138−using `&[mark]`. Try the following commands:
139−
140−```
141−~fintud-macrep:dojo> |start %square
142−>=
143−
144−~fintud-macrep:dojo> :square 6
145−gall: %square: no poke arm for noun
146−
147−~fintud-macrep:dojo> :square &atom 6
148−[%square 36]
149−>=
150−```
151−
152−> Recall the bug where `%square` may get printed above the input line.
153−
154−Marks are powerful, and they're the backbone of Urbit's data pipeline,
155−so we'll be getting quite used to them.
156−
157−*Exercise*:
158−
159−- Write an app that computes fizzbuzz on its input.
160−
161−## Sending a message to another urbit
162−
163−Let's write our first network message! Here's `examples/app/pong.hoon`:
164−
165−```
166−:: Allows one urbit to send the string 'Pong' to
167−:: another urbit.
168−::
169−:::: /===/app/pong/hoon
170− ::
171−!:
172−|%
173−+$ move [bone card]
174−+$ card $% [$poke wire dock poke-contents]
175− ==
176−+$ poke-contents $% [$atom @]
177− ==
178−--
179−|_ [bow=bowl:gall $~] :: stateless
180−::
181−++ poke-urbit
182− |= to=ship
183− ^- [(list move) _+>.$]
184− ~& pong+'Outgoing pong!'
185− :_ +>.$
186− ~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong']]
187−::
188−++ poke-atom
189− |= tom=@
190− ^- [(list move) _+>.$]
191− ~& pong+'Incoming pong!'
192− ~& pong+received+`@t`tom
193− [~ +>.$]
194−::
195−++ coup |=(* [~ +>.$])
196−::
197−--
198−```
199−
200−
201−Run it with these commands:
202−
203−```
204−~fintud-macrep:dojo> |start %pong
205−>=
206−
207−~fintud-macrep:dojo> :pong &urbit ~sampel-sipnym
208−>=
209−```
210−
211−Replace `~sampel-sipnym` with another urbit. The easiest thing to do is to start
212−a comet, a free and disposable Urbit identity. If you don't know how to start a
213−comet, see [the user setup section](../../../using/setup/). Don't forget to start
214−the `%pong` app on that urbit, too. You should see, on the foreign
215−urbit, this output:
216−
217−```
218−[%pong 'Incoming pong!']
219−[%pong %received 'Pong']
220−```
221−
222−Most of the code should be straightforward. In `++poke-atom`, the only new thing
223−is the expression `` `@t`tom ``, which is *casting* the argument `tom` to type
224−`@t`. As we already know, `@t` is the type of "cord" (text string).
225−
226−The more interesting part is in `++poke-urbit`. The `urbit` mark is an urbit
227−identity, and the Hoon type associated with it is `ship` or `@p` (the "p"
228−stands for "phonetic base").
229−
230−Recall that in a `++poke` arm we produce "a list of moves and our state". Until
231−now, we've left the list of moves empty, since we haven't wanted to tell Arvo to
232−do anything in particular. Now we want to send a message to another urbit. Thus,
233−we produce a list with one element:
234−
235−```
236−~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong]]
237−```
238−
239−### Moves
240−
241−The general form of a move is `[bone term wire *]`.
242−
243−Or, in pseudo-code:
244−
245−`["cause" sys-call/action tack-new-layer-on-cause action-specific information]`
246−
247−Let's walk through each of these elements step by step.
248−
249−#### Bones ("cause")
250−
251−If you look up `++bone` in `hoon.hoon`, you'll see that it's a number (`@ud`),
252−and that it's an opaque reference to a duct. `++duct` in `hoon.hoon` is a list
253−of `wire`s, where `++wire` is an alias for `++path`. `++path` is a list of
254−`++knot`s, which are ASCII text. Thus, a duct is a list of paths, and a bone is
255−an opaque reference to it (in the same way that a Unix file descriptor is an
256−opaque reference to a file structure). Thus, to truly understand bones, we must
257−understand ducts.
258−
259−A duct is a stack of causes, again, represented as paths, which are called wires.
260−At the bottom of every duct is a unix event, such as a keystroke, network
261−packet, file change, or timer event. When Arvo is given this event, it routes
262−the event to appropriate kernel module for handling.
263−
264−Sometimes, the module can immediately handle the event and produce any necessary
265−results. For example, when we poked the `++poke-atom` arm above, we poked %gall,
266−our application server, which was able to respond to our poke directly. When the
267−module cannot service the request itself, it sends instructions to another
268−kernel module or application (through the %gall module) to do a specified
269−action, and produces the result from that.
270−
271−Furthermore, when one module sends a message to another kernel module or
272−application, it also sends along the duct it was given with its new wire tacked
273−onto the top. Now the duct has two entries, with the unix event on the bottom
274−and the kernel module that handled it on top. This process can continue
275−indefinitely, pushing more and more wires onto the top of the duct. When an
276−entity finally produces a result, a wire is popped off the duct, and the result
277−is passed all the way back down, repeating the process of wire popping
278−sequentially until the bottom of the duct is reached.
279−
280−In effect, a duct is an Arvo-level call stack. It's worth noting that while in
281−traditional call stacks a function call happens synchronously and returns
282−exactly once. In Arvo, multiple moves can be sent at once, are evaluated
283−asynchronously, and each one may be responded to zero or more times.
284−
285−The point to take home is that whatever caused `++poke-urbit` to be called is
286−also the root cause for the network message we're trying to send. Thus, we say
287−to send the network message along the given bone `ost`.
288−
289−##### Wire (path)
290−
291−Of course, we have to push a new wire onto our duct before passing it along (or
292−responding to it directly) anywhere. This wire can have any data we want in it,
293−but we don't need anything specific here, so we just use the wire `/sending`
294−(`/elem1/elem2/elemN` is one syntax used to create `++path`s and `++wire`s of N
295−elements). If we were expecting a response (which we're not), it would come back
296−along the `/sending` wire, meaning that the path `/sending` will be passed back
297−to the response handler as an argument. Although it's not required, it's
298−generally a good idea to make the wire human-readable for bug-handling purposes.
299−
300−##### Term (sys-call)
301−
302−Each move also has a `term`, composed of lowercase ASCII and/or `-`. This `term`
303−has the sign `@tas`. In this case, our `term` is `%poke`, which is the name of
304−the particular kind of move we're sending. You can always use `%poke` to message
305−an app. Other common names include `%warp`, to read from the filesystem;
306−`%wait`, to set a timer; and `%them`, to send an http request.
307−
308−The move ends with `*` (that is, any noun) since each type of move takes
309−different data. In our case, a `%poke` move takes a target (urbit and app) and
310−marked data, then pokes the arm of the corresponding mark on that app on that
311−urbit with that data. `[to-urbit-address %pong]` is the target urbit and app,
312−`%atom` is the `mark`, and`'Pong'` is the data.
313−
314−When Arvo receives a `%poke` move, it calls the appropriate `++poke`.
315−The same mechanism is used for sending messages between apps on the same
316−urbit as for sending messages between apps on different urbits.
317−
318−> We said earlier that we're not expecting a response. This is not entirely true: the `++coup` is called when we receive acknowledgment that the `++poke` was called. We don't do anything with this information right now, but we could.
319−
320−*Exercises*:
321−
322−- Extend either of the apps in the first two exercises to accept input over the network in the same way as `pong`.
323−
324−- Modify `pong.hoon` to print out a message when it receives acknowledgement.
325−
326−- Write two apps, `even` and `odd`. When you pass an atom to `even`, check whether it's even. If so, divide it by two and recurse; otherwise, poke `odd` with it. When `odd` receives an atom, check whether it's equal to one. If so, terminate, printing "%success". Otherwise, check whether it's odd. If so, multiply it by three, add one, and recurse; otherwise, poke `even` with it. When either app receives a number, print it out along with the name of the app. In the end, you should be able to watch Collatz's conjecture play out between the two apps. Sample output:
327−
328−```
329−~fintud-macrep:dojo> :even &atom 18
330−[%even 18]
331−[%odd 9]
332−[%even 28]
333−[%even 14]
334−[%odd 7]
335−[%even 22]
336−[%odd 11]
337−[%even 34]
338−[%odd 17]
339−[%even 52]
340−[%even 26]
341−[%odd 13]
342−[%even 40]
343−[%even 20]
344−[%even 10]
345−[%odd 5]
346−[%even 16]
347−[%even 8]
348−[%even 4]
349−[%even 2]
350−%success
351−```
352−
353−- Put `even` and `odd` on two separate urbits and pass the messages over the network. Post a link to a working solution in :talk to receive a cookie.
learn/arvo/arvo-internals/gall/security-driver.udondeleted−281
@@ -1,281 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− next/'true'
4− sort/'8'
5− title/'Security Drivers'
6− ==
7−;>
8−
9−# Security drivers
10−
11−A security driver is a file in `/=home=/sec/<tld>/<domain>/hoon`
12−that handles the authentication for all HTTP requests to
13−`https://<domain>.<tld>`. When anything in Urbit makes an HTTP
14−request through `%eyre` (our web server), it checks to see if we
15−have a security driver for the requested domain, and if so
16−filters the request through the driver. The security driver will
17−usually either decorate the request with the needed credentials
18−if it has them, or else it will guide the user through the
19−process of authenticating Urbit with the service.
20−
21−Each web service needs its own security driver, but most of them
22−are pretty standard. We recommend starting with an existing
23−security driver based on your needed authentication method (e.g.
24−basic auth, OAuth1, OAuth2), and changing whatever is specific to
25−your service.
26−
27−The best strategy for building security drivers is to copy a
28−similar one and tweak it until it works for you. The best
29−representatives are Github for Basic Authentication, Twitter for
30−OAuth1, Slack for OAuth2 when access tokens don't expire, and
31−Google APIs for OAuth2 when access tokens do expire. In most
32−cases you'll need to make very few changes to one of these
33−models.
34−
35−Still, it's worth seeing one or two built from the ground up.
36−Here, we'll build a connector for the Github API v3. (It's already in `/sec/com/github.hoon` if you want to see it.)
37−
38−The
39−simplest way to interact with the Github API is to just fetch
40−https://api.github.com from the dojo. First, run this:
41−
42−```
43−> |init-auth-basic /com/github
44−```
45−
46−Input your Github username and password as directed. Next:
47−
48−```
49−~your-urbit:dojo> +https://api.github.com
50−```
51−
52−> Note: the current version of this API is outdated, so you'll get a 403 message at this point. We need to update this so you can follow along with the examples. We're sorry!
53−
54−Github exposes a few endpoints to the general web, and the root
55−endpoint is one of them. This gives you a textual representation
56−of a JSON object that contains a bunch of urls to other parts of
57−Github's API. This is exactly the same response you would get
58−from just running `curl https://api.github.com` on UNIX.
59−
60−If we don't have a security driver for Github yet, many of the
61−endpoints won't be accessible, or they will only have publicly
62−accessible information. Most of what we care about requires us
63−to be authenticated.
64−
65−## Basic auth
66−
67−Here's a simple security driver:
68−
69−```
70−:: Test url +https://api.github.com/user
71−::
72−:::: /hoon/github/com/sec
73− ::
74−/+ basic-auth
75−!:
76−|_ [bal=(bale keys:basic-auth) $~]
77−++ aut ~(standard basic-auth bal ~)
78−++ filter-request out-adding-header:aut
79−--
80−```
81−
82−Github supports authentication through either Basic
83−Authentication or OAuth2. We'll show the basic auth example
84−first, but in general we'd prefer OAuth2.
85−
86−Since this driver is for Github, put it in
87−`/=home=/sec/com/github/hoon`.
88−
89−To try this out, we first have to initialize our credentials with
90−`|init-auth-basic`, which prompts for the url of the service
91−(api.github.com), username, and password. It stores this
92−information in a manner that `%eyre` knows how to decode and send
93−put into your `bale`. Note that `|init-auth-basic` is standard for
94−basic auth, but other auth schemes (like OAuth) are initialized
95−in other ways.
96−
97−After you've run `|init-auth-basic`, you should be able to run
98−`+https://api.github.com/user` and get a response indicating who
99−you're logged in as.
100−
101−You can similarly POST:
102−
103−```
104−~your-urbit:dojo> +https://api.github.com/gists &json _(cork de-json:html need) '{"files":{"file1.txt":{"content":"can\'t stop the signal"}}}'
105−```
106−
107−This creates a gist, go to `https://gist.github.com/<username>` to
108−see it.
109−
110−The `+url` syntax used in "source" position makes a GET request,
111−but if you pass it data it will make a POST request with that
112−data as the body. This request is authenticated seamlessly. You
113−can send data of any mark as long as it has a conversion path to
114−`%mime`.
115−
116−Let's take a look at the code and see if we can figure out what's
117−happening here:
118−
119−```
120−/+ basic-auth
121−```
122−
123−First, we load a library called `basic-auth`. This library
124−exposes two items. `keys` is the type of the basic auth key,
125−which is essentially a base64'd username and password.
126−`standard` accepts a `bale` and produces a core with everything
127−we'll need to implement basic auth.
128−
129−Every security driver needs some amount of state, which is stored
130−in `bale`. `bale` contains:
131−
132−- `our`, our urbit name
133−- `now`, the current time
134−- `eny`, 256 bits of entropy
135−- `byk`, the urbit, desk and case which the security driver is running from
136−- `usr`, the particular identity we're logging in with
137−- `dom`, the site we're accessing
138−- `key`, the secrets required to authenticate requests. The type for this entry is supplied by the programmer as the argument to `++bale`. Thus, in our case, `key` in our bale is of type `keys:basic-auth`.
139−
140−Additionally, a security driver contains at least one out of the
141−five "special" arms:
142−
143−- `++filter-request` is a function which takes a hiss (http request) and produces a `sec-move` (defined in zuse), which is one of:
144− - `[%send hiss]`, which sends the new hiss. This is the case in, for example, basic auth, where all we need to do is add an extra header to the request.
145− - `[%give httr]`, where httr is an http response. This immediately returns an http response to the sender.
146− - `[%show purl]`, where a purl is a parsed url. This displays a message asking the user to visit the given url to continue the authentication process.
147− - `[%redo ~]`, which redoes the request.
148− - `%eyre` calls `++filter-request` just before sending an HTTP request to the specified domain. This allows the security driver to filter the requests, decorating them with authentication data.
149−- `++filter-response` is a function which takes an httr and produces a `sec-move`. `%eyre` calls it after receiving an HTTP response from the specified domain. This allows the security driver to handle authentication errors, commonly caused by expired tokens, and retry the request.
150−- `++receive-auth-query-string` is a function that takes a `quay` (list of query parameters) and produces a `sec-move`. `%eyre` calls it when it receives a request on the callback url. Generally, this happens in OAuth after the user has granted access to the urbit app, and the service makes a request to the callback url with the code. The security driver should then make a request to convert the code into an access token.
151−- `++receive-auth-response` is a function that takes an httr and produces a `sec-move`. `%eyre` calls it when it gets a response to the request made in `++receive-auth-query-string`.
152−- `++update` is a function which converts old state to a new format when the security driver gets updated. If you want to just get rid of the old state, define `++discard-state` as `~`.
153−
154−For basic auth, we only have to worry about `++filter-request`,
155−since all we need to do is add the correct header to each
156−request. Our `++aut` core contains a function
157−`++out-addding-header`, which does exactly what we want.
158−
159−Where do the keys come from, though? Remember we ran
160−`|init-auth-basic` to input them. This just prompts you for the
161−service url, username, and password, and it stores them next to
162−the driver. In our case, that's
163−`/=home=/sec/com/gitub/api/atom`. These keys are stored
164−encrypted, and you don't want to edit them directly. `%eyre`
165−loads them directly into your `bale`.
166−
167−## OAuth2
168−
169−Most services are better accessed through some form of OAuth.
170−Github can be accessed with OAuth2, which is a little more
171−complicated than basic auth, but not hugely so.
172−
173−The basic steps for OAuth2 are these:
174−
175−- create an app and get its client id and client secret (on Github)
176−- store these in Urbit (with `|init-oauth2`)
177−- try to make a request that requires authentication. The security driver should prompt you to visit a particular url.
178−- visit the url and click "authorize", which gives the app access to your account
179−- the security driver will turn the code it receives into an access token
180−- on every request, include that access token
181−
182−Creating an app is easy and
183−[well-documented](https://github.com/settings/applications/new).
184−If necessary, set the callback url to
185−`/~/ac/github.com/_state/in`, and note its client id and client
186−secret.
187−
188−Run `|init-oauth2`, which will prompt for the hostname
189−(api.github.com), client id, and client secret. This will store
190−the information, encrypted, in `/=home=/sec/com/github.atom`,
191−just as with Basic Authentication.
192−
193−Now we need a security driver. Use this:
194−
195−```
196−:: Test url +https://api.github.com/user
197−::
198−:::: /hoon/github/com/sec
199− ::
200−/+ oauth2
201−!:
202−::::
203− ::
204−|_ [bal=(bale keys:oauth2) tok=token:oauth2]
205−++ scopes :: comment out scopes to taste
206− :~ 'user' 'user:email' 'user:follow' 'public_repo' 'repo'
207− 'repo_deployment' 'repo:status' 'delete_repo' 'notifications'
208− 'gist' 'read:repo_hook' 'write:repo_hook' 'admin:repo_hook'
209− 'admin:org_hook' 'read:org' 'write:org' 'admin:org'
210− 'read:public_key' 'write:public_key' 'admin:public_key'
211− ==
212−:: ++aut is a "standard oauth2" core, which implements the
213−:: most common handling of oauth2 semantics. see lib/oauth2 for more details,
214−:: and examples at the bottom of the file.
215−++ aut (~(standard oauth2 bal tok) . |=(tok/token:oauth2 +>(tok tok)))
216−++ filter-request
217− %^ out-add-query-param:aut 'access_token'
218− scope=~[%client %admin]
219− oauth-dialog='https://github.com/login/oauth/authorize'
220−::
221−++ receive-auth-query-string
222− %- in-code-to-token:aut
223− url='https://github.com/login/oauth/api/access_token'
224−++ receive-auth-response bak-save-token:aut
225−--
226−```
227−
228−The oauth2 library provides the main "engine" in `standard`, just
229−like in basic auth, except that we also have to specify a
230−function to save the access token when we get it. It's worth
231−noting that this library is well documented in the source,
232−including examples: `/=home=/lib/oauth2/hoon`.
233−
234−Running `+http://api.github.com/user` tries to make a request to
235−Github with authentication. This loads into the bale the keys,
236−which are of type `keys:oauth2`, defined in the oauth2 library.
237−We don't have to worry about the specifics of these keys -- the
238−library handles them -- but they include the client id and the
239−client secret.
240−
241−Before the request is sent, `%eyre` calls `++filter-request` to
242−decorate it with authentication headers. Since we don't yet have
243−an access token, we need to prompt the user to visit the "dialog"
244−url. `++out-add-query-param` checks whether we have a token, and
245−if we don't it produces `%show` and a message telling the user to
246−visit the `oauth-dialog` url we provide, with the extra query
247−parameters added (client id, scopes, and state).
248−
249−When the user visits that url, Github will ask them to log in and
250−authorize the application. When they do so, Github will post a
251−request to `/~/ac/github.com/_state/in` with a code in the query
252−string. `%eyre` sends the query string to
253−`++receive-auth-query-string`, which is a function that takes a
254−quay and produces a `sec-move`. `++in-code-to-token` from our
255−`aut` takes the `code` parameter from the quay and uses it to
256−create a request to the given url. This request includes the
257−client id, the client secret, and the code we just got.
258−
259−Github's response to that request includes an access token in its
260−body. This is handled in `++receive-auth-response`.
261−`++bak-save-token` extracts that token and gives it to the
262−function that we passed in the definition of `++aut`. In our
263−case, we just save that token into our state for later usage.
264−
265−Now we have the credentials we need, so `++filter-request` is
266−called with the original request, and `++out-add-query-param`
267−passes the request through with the addition of the query
268−parameter `access_token`.
269−
270−Just like with Basic Authentication, you should be able to run
271−`+https://api.github.com/user` and get a response indicating who
272−you're logged in as.
273−
274−Some drivers a slightly more complicated. For example, Github's
275−access token's don't expire, but that's not the case for all
276−service. The googleapis driver shows the flow when the access
277−token can expire. Twitter uses OAuth1, for which we have another
278−library.
279−
280−Remember, of course, that the best strategy for building security
281−drivers is to copy a similar one and tweak it to taste.
learn/arvo/arvo-internals/gall/state.udondeleted−123
@@ -1,123 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− next/'true'
4− sort/'2'
5− title/'State'
6− ==
7−;>
8−
9−# State
10−
11−In the last section we built a few small apps that sent moves. These apps were
12−entirely stateless, however. Most useful apps require some amount of state.
13−Let's build a trivial stateful app. It'll keep a running the sum of all the
14−atoms we poke it with. Here's `examples/app/sum.hoon`:
15−
16−```
17−:: Keeps track of the sum of all the atoms it has been
18−:: poked with and prints the sum out
19−::
20−:::: /===/app/sum/hoon
21− ::
22−!:
23−|%
24−+$ move [bone card]
25−+$ card $% $~
26− ==
27−--
28−|_ [bow=bowl:gall sum=@]
29−::
30−++ poke-atom
31− |= tom=@
32− ^- [(list move) _+>.$]
33− ~& sum+(add sum tom)
34− [~ +>.$(sum (add sum tom))]
35−::
36−++ coup
37− |= [wir=wire err=(unit tang)]
38− ^- [(list move) _+>.$]
39− ?~ err
40− ~& sum+success+'Poke succeeded!'
41− [~ +>.$]
42− ~& sum+error+'Poke failed. Error:'
43− ~& sum+error+err
44− [~ +>.$]
45−::
46−--
47−```
48−
49−We can start it with `|start %sum`, and then run it:
50−
51−```
52−~fintud-macrep:dojo> :sum &atom 5
53−[%sum 5]
54−>=
55−
56−~fintud-macrep:dojo> :sum &atom 2
57−[%sum 7]
58−>=
59−
60−~fintud-macrep:dojo> :sum &atom 15
61−[%sum 22]
62−>=
63−```
64−
65−We can see that app state is being saved, but when, where, and how?
66−
67−The state is stored as the second thing in the `|_` line. In our case, it's
68−simply an atom named `sum`. We change it by producing our state not with
69−`+>.$` (as before), but with `+>.$(sum (add sum tom))`. We've seen all these
70−parts before, but you might not recognize them.
71−
72−Recall in the first chapter that we recursed with the expression
73−`$(b (add 3 b))`. This meant "produce `$` with `b` changed to `(add 3 b)`.
74−Similarly, `+>.$(sum (add sum tom))` means "produce `+>.$` (i.e. our
75−context, which contains our state) with `sum` changed to `(add sum tom)`.
76−
77−At a high level, then, when we handle state, we do it explicitly. It's passed in
78−and produced explicitly. In Unix systems, application state is just a block of
79−memory, which you need to serialize to disk if you want to keep it around for
80−very long.
81−
82−In Urbit, app state is a single (usually complex) value. In our example, we have
83−very simple state, so we defined `sum=@`, meaning that our state is an atom.
84−Of course, `sum` is just a name, and you're free to name your state whatever
85−you like. But let's clarify a couple other things before we continue.
86−
87−First, `bowl` is a set of general global states. This set is managed by the
88−system. It includes things like `now` (the current time), `our` (our urbit
89−identity), and `eny` (512 bits of guaranteed-fresh entropy). For the full list
90−of things in `++bowl`, search for `++ bowl` (note: two spaces) in
91−`/arvo/zuse.hoon`.
92−
93−> This is, perhaps, the most common way to learn Hoon. The easiest way to learn about an identifier you see in code is to search in `/arvo/zuse.hoon` and `/arvo/hoon.hoon` for it.\\ Urbit's codebase is less than 30000 lines of code combined, including the hoon parser, the compiler, and the `/arvo` microkernel, so you can usually use the code and its comments as a reference doc. You can also read [zuse.hoon](https://github.com/urbit/arvo/blob/master/arvo/zuse.hoon) and [hoon.hoon](https://github.com/urbit/arvo/blob/master/arvo/hoon.hoon) in your browser.
94−
95−The second thing we should clear up is this: Urbit needs no "serialize to disk"
96−step. Everything you produce in the app state is persistent across calls to the
97−app, restarts of the urbit, and even power failure. If you want to write to the
98−Unix filesystem, you can, but it's not needed for persistence. Urbit has
99−transactional events, which makes it an [ACID operating
100−system](https://en.wikipedia.org/wiki/ACID). Thus, you don't have to worry about
101−persistence when programming in Urbit, or ever go through the hassle of having
102−to set up and write to a database.
103−
104−*Exercises*:
105−
106−- Modify `:sum` to reset the counter when you poke it with 0.
107−
108−- Write an app called `last` that prints out the previous value you poked it with.
109−
110−Sample output:
111−
112−```
113−~fintud-macrep:dojo> :last 7
114−[%last 0]
115−>=
116−
117−~fintud-macrep:dojo> :last [1 2 3]
118−[%last 7]
119−>=
120−
121−~fintud-macrep:dojo> :last 'howdy'
122−[%last [1 2 3]]
123−```
learn/arvo/arvo-internals/gall/subscriptions.udondeleted−332
@@ -1,332 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− next/'true'
4− sort/'3'
5− title/'Subscriptions'
6− ==
7−;>
8−
9−# Subscriptions
10−
11−We've dealt fairly extensively with "poke" messages to an app, but these
12−are somewhat limited. A poke is a one-way message, but more often we
13−want to subscribe to updates from another app. You could build a
14−subscription model out of one-way pokes, but it's such a common pattern
15−that it's built into Arvo.
16−
17−Let's take a look at two apps, `:source` and `:sink`. First,
18−`:source`:
19−
20−```
21−:: Sends subscription updates to sink.hoon
22−::
23−:::: /===/app/source/hoon
24− ::
25−!:
26−::
27−|%
28− +$ move [bone card]
29− +$ card $% [%diff diff-contents]
30− ==
31−+$ diff-contents $% [%noun *]
32− ==
33−--
34−::
35−|_ [bow=bowl:gall $~]
36−::
37−++ poke-noun
38− |= non=*
39− ^- [(list move) _+>.$]
40− :_ +>.$
41− %+ turn (prey:pubsub:userlib /example-path bow)
42− |=([o=bone *] [o %diff %noun non])
43−::
44−++ peer-example-path
45− |= pax=path
46− ^- [(list move) _+>.$]
47− ~& source+peer-notify+'Someone subscribed to you!'
48− ~& source+[ship+src.bow path+pax]
49− [~ +>.$]
50−::
51−++ coup
52− |= [wir=wire err=(unit tang)]
53− ^- [(list move) _+>.$]
54− ?~ err
55− ~& source+success+'Poke succeeded!'
56− [~ +>.$]
57− ~& source+error+'Poke failed. Error:'
58− ~& source+error+err
59− [~ +>.$]
60−::
61−++ reap
62− |= [wir=wire err=(unit tang)]
63− ^- [(list move) _+>.$]
64− ?~ err
65− ~& source+success+'Peer succeeded!'
66− [~ +>.$]
67− ~& source+error+'Peer failed. Error:'
68− ~& source+error+err
69− [~ +>.$]
70−::
71−--
72−```
73−
74−Save this as `source.hoon` in the `/app` directory of your urbit's pier.
75−
76−And secondly, `:sink`:
77−
78−```
79−:: Sets up a simple subscription to source.hoon
80−::
81−:::: /===/app/sink/hoon
82− ::
83−!:
84−|%
85−+$ move [bone card]
86−+$ card $% [%peer wire dock path]
87− [%pull wire dock $~]
88− ==
89−--
90−::
91−|_ [bow=bowl:gall val=?]
92−::
93−++ poke-noun
94− |= non=*
95− ^- [(list move) _+>.$]
96− ?: &(=(%on non) val)
97− :_ +>.$(val |)
98− :~ :* ost.bow
99− %peer
100− /subscribe
101− [our.bow %source]
102− /example-path
103− ==
104− ==
105− ?: &(=(%off non) !val)
106− :_ +>.$(val &)
107− ~[[ost.bow %pull /subscribe [our.bow %source] ~]]
108− ~& ?: val
109− sink+unsubscribed+'You are now unsubscribed!'
110− sink+subscribed+'You are now subscribed!'
111− [~ +>.$]
112−::
113−++ diff-noun
114− |= [wir=wire non=*]
115− ^- [(list move) _+>.$]
116− ~& sink+received-data+'You got something!'
117− ~& sink+data+non
118− [~ +>.$]
119−::
120−++ coup
121− |= [wir=wire err=(unit tang)]
122− ^- [(list move) _+>.$]
123− ?~ err
124− ~& sink+success+'Poke succeeded!'
125− [~ +>.$]
126− ~& sink+error+'Poke failed. Error:'
127− ~& sink+error+err
128− [~ +>.$]
129−::
130−++ reap
131− |= [wir=wire err=(unit tang)]
132− ^- [(list move) _+>.$]
133− ?~ err
134− ~& sink+success+'Peer succeeded!'
135− [~ +>.$]
136− ~& sink+error+'Peer failed. Error:'
137− ~& sink+error+err
138− [~ +>.$]
139−::
140−--
141−```
142−
143−Save this as `sink.hoon` in the `/app` directory of your urbit's pier (make sure both `source` and `sink` are on the same ship).
144−
145−Two notes:
146−
147−- `bowl` is the type of the system state within our app. For example, it includes things like `our`, the name of the host urbit, and `now`, the current time.
148−
149−- You may have noticed the separate `|%` above the application core `|_`. We usually put our types in another core on top of the application core. We can access these type from our `|_` because in `hoon.hoon` files, all cores are called against each other. (The shorthand for 'called' is `=>`.) Thus, the `|%` with the types is in the context of the `|_`, as it lies above it: `hoon.hoon` `=> |% w types => |_`
150−
151−Here's some sample output of the two working together:
152−
153−```
154−~fintud-macrep:dojo> |start %source
155−>=
156−
157−~fintud-macrep:dojo> |start %sink
158−>=
159−
160−~fintud-macrep:dojo> :sink %on
161−[%source %peer-notify 'Someone subscribed to you!']
162−[%source [%ship ~fintud-macrep] %path /]
163−[%sink %success 'Peer succeeded!']
164−>=
165−
166−~fintud-macrep:dojo> :source 5
167−[%sink %received-data 'You got something!']
168−[%sink %data 5]
169−>=
170−
171−~fintud-macrep:dojo> :sink %off
172−>=
173−
174−~fintud-macrep:dojo> :source 6
175−>=
176−
177−~fintud-macrep:dojo> :sink %on
178−[%source %peer-notify 'Someone subscribed to you!']
179−[%source [%ship ~fintud-macrep] %path /]
180−[%sink %success 'Peer succeeded!']
181−>=
182−
183−~fintud-macrep:dojo> :source 7
184−[%sink %received-data 'You got something!']
185−[%sink %data 7]
186−>=
187−```
188−
189−### :source
190−
191−Hopefully you can get a sense for what's happening here. When we poke
192−`:sink` with `%on`, `:sink` subscribes to `:source`,
193−and so whenever we poke `:source`, `:sink` gets the update and
194−prints it out. Then we unsubscribe by poking `:sink` with `%off`, and
195−`:sink` stops getting updates. We then resubscribe.
196−
197−There's a fair bit going on in this code. Let's look at `:source`
198−first.
199−
200−Our definition of `move` is fairly specific, since we're only going to
201−sending one kind of move. The `%diff` move is a subscription update, and
202−its content is marked data which gall routes to our subscribers.
203−
204−This is a slightly different kind of move than we've dealt with so
205−far. It's producing a result rather than calling other
206−code (i.e. it's a return rather than a function call), so if you recall
207−the discussion of ducts, a layer gets popped off the duct rather than
208−added to it. This is why no wire is needed for the move -- we won't
209−receive anything in response to it.
210−
211−Anyways, there are four functions (arms) inside the `|_`. We already know when
212−`++poke-noun` is called. `++peer-example-path` is called when someone tries to
213−subscribe to our app. Of course, you don't just subscribe to an app; you
214−subscribe to a path on that app. This path comes in as the argument to `++peer`.
215−
216−In our case, we don't care what path you subscribed on, and all we do is print
217−out that you subscribed. Arvo keeps track of your subscriptions, so you don't
218−have to. You can access your subscribers by looking at `sup` in the bowl that's
219−passed in. `sup` is of type `(map bone {@p path})`, which associates bones with
220−the urbit who subscribed, and which path they subscribed on. If you want to
221−communicate with your subscribers, send them messages along their bone.
222−
223−`++poke-noun` "spams" the given argument to all our subscribers.
224−There's a few things we haven't seen before. Firstly, `:_(a b)` is the
225−same as `[b a]`. It's just a convenient way of formatting things when
226−the first thing in a cell is much more complicated than the second.
227−Thus, we're producing our state unchanged.
228−
229−Our list of moves is the result of a call to `++turn`. `++turn` is what many
230−languages call "map" -- it runs a function on every item in a list and collects
231−the results in a list. The list is `(prey /example-path bow)` and the function
232−is the `|=` line right after it.
233−
234−`prey:pubsub:userlib` is a standard library function defined in `zuse.hoon`. It takes a path
235−and a bowl and gives you a list of the subscribers who are subscribed on a path
236−that begins with the given path. "Prey" is short for "prefix".
237−
238−Now we have the list of relevant subscribers. This a list of triples,
239−`[bone @p path]`, where the only thing we really need is the bone, because we
240−don't need to know their urbit or what exact path they subscribed on. Thus, our
241−transformer function takes `[o=bone *]` and produces `[o %diff %noun non]`,
242−which is a move that provides bone `o` with this subscription update:
243−`[%noun non]`". This is fairly dense code, but what it's doing is
244−straightforward!
245−
246−### :sink
247−
248−`:source` should now make sense. `:sink` is a little longer, but not much more
249−complicated.
250−
251−In `:sink`, our definition of of `++move` is different. All moves start
252−with a `bone`, and we conventionally refer to the second half as the "card", so
253−that we can say a move is an action that sends a card along a bone.
254−
255−We have two kinds of cards here: we `%peer` to start a subscription, and we
256−`%pull` to stop it. Both of these are "forward" moves that may receive a
257−response, so they need a wire to tack onto the duct before they pass it on. They
258−also need a target, which is a pair of an urbit and an app name. Additionally,
259−`%peer` needs a path on that app to subscribe too. `%pull` doesn't need this,
260−because its semantics are to cancel any subscriptions coming over this duct. If
261−your bone and wire are the same as when you subscribed, then the cancellation
262−will happen correctly.
263−
264−The only state we need for `:sink` is a boolean to indicate whether
265−we're already subscribed to `:source`. We use `val=?`, where `?`
266−is the sign of type boolean (similar to `*`, `@`), which defaults to true (that
267−is, `0`).
268−
269−In `++poke-noun` we check our input to see both if it's `%on` and we're
270−available (`val` is true). If so, we produce the move to subscribe to
271−`:source`:
272−
273−```
274−:~ :* ost.bow
275− %peer
276− /subscribe
277− [our.bow %source]
278− /example-path
279− ==
280−==
281−```
282−
283−Also, in the preceding lines, we set `val` to false (`|`) with `+>.$(val |)`.
284−Remember that the `:_` constructs an inverted cell, with the first child
285−(`+>.$(val |` in our case) as the tail and the second child as the head. Here,
286−the cell we produce when our subscription is `%on` and `val` is true has a
287−head with our new state where `val` is set to false and a tail of our list of
288−moves, which is shown in the code block above.
289−
290−Otherwise, if our input is `%off` and we're already subscribed (i.e. `val`
291−is false), then we unsubscribe from `:source` and set `val` back to true (`&`),
292−again using our handy inverted cell constructor mold `:_`:
293−
294−```
295−:_ +>.$(val &)
296−~[[ost.bow %pull /subscribe [our.bow %source] ~]]
297−```
298−
299−It's important to send over the same bone and wire (`/subscribe`) as the
300−one we originally subscribed on.
301−
302−If neither of these cases are true, then we print our current subscription
303−state, based on whether `val` is true or false, and return a cell containing
304−a null list of moves and our unchanged app state:
305−
306−```
307−~& ?: val
308− sink+unsubscribed+'You are now unsubscribed!'
309− sink+subscribed+'You are now subscribed!'
310−[~ +>.$]
311−```
312−
313−`++diff-noun` is called when we get a `%diff` update along a subscription with a
314−mark of `noun`. `++diff-noun` is given the wire that we originally passed with
315−the `%peer` subscription request along and the data we got back. In our case we
316−just print out the data:
317−
318−```
319−~& sink+received-data+'You got something!'
320−~& sink+data+non
321−```
322−
323−`++reap` is called when we receive an acknowledgment as to whether the
324−subscription was handled successfully. You can remember that `++reap` is the
325−counterpart to `++peer` as it's pronounced like 'peer' backwards. Similarly,
326−`coup` is similar to 'poke' backwards.
327−
328−Moving forward, `++reap` is given the wire we attempted to subscribe over,
329−possibly along with an error message in cases of failure. `(unit type)` means
330−"either `~` or `[~ type]`, which means it's used like Haskell's "maybe" or C's
331−nullability. If `err` is `~`, then the subscription was successful and we tell
332−that to the user. Otherwise, we print out the error message.
learn/arvo/arvo-internals/gall/web-apps.udondeleted−254
@@ -1,254 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− next/'true'
4− sort/'5'
5− title/'Web apps'
6− ==
7−;>
8−
9−# Backend
10−
11−We've done purely functional web pages as hook files, and we've
12−done command line apps, so now let's interact with an app over
13−the web. The fundamental concepts are no different than from the
14−command line -- you send "poke" messages to apps and subscribe to
15−data streams. The only difference is that you do it with
16−javascript.
17−
18−Let's create a small web app that counts the number of times you
19−poke it. There'll be a button to poke the app, and line of text
20−below it saying how many times the app has been poked. We can
21−update this by subscribing our page to the relevant path on its app.
22−
23−Save the following as `click.hoon` in the `/app` directory of your urbit's pier.
24−
25−```
26−/? 314
27−!:
28−|%
29−++ move [bone %diff %mark *]
30−--
31−!:
32−|_ [hid=bowl:gall clicks=@]
33−++ poke-click
34− |= click=%click
35− ~& [%poked +(clicks)]
36− :_ +>.$(clicks +(clicks))
37− %+ turn (prey:pubsub:userlib /the-path hid)
38− |=([o=bone *] [o %diff %clicks +(clicks)])
39−++ peer-the-path
40− |= pax=path
41− [[[ost.hid %diff %clicks clicks] ~] +>.$]
42−--
43−```
44−
45−There's nothing really new here, except that we use a couple of
46−new marks, `click` and `clicks`. When we get poked with a
47−`click`, we increment the variable `clicks` in our state and tell
48−all our subscribers the new value. When someone subscribes to us
49−on the path `/the-path`, we immediately give them the current
50−number of clicks.
51−
52−Let's take a look at the new marks. Save this as `/mar/click.hoon`:
53−
54−```
55−|_ click=%click
56−++ grab
57− |%
58− ++ noun |=(* %click)
59− ++ json
60− |= jon=^json
61− ?> =('click' (need (so:dejs-soft:format jon)))
62− %click
63− --
64−--
65−```
66−
67−The mark `click` has type `%click`, which means the only
68−valid value is `%click`. We can convert from `noun` by just
69−producing `%click`.
70−
71−We also convert from json by parsing a json string with `so:dejs-soft:format`,
72−asserting the parsing succeeded with `need`, and asserting the
73−result was 'click' with `?>`, which asserts that its first child
74−is true.
75−
76−> Note the argument to `++json`is `jon=^json`. Why `^json`? `++json` shadows the type definition, so if we want to refer to the type, we have to prepend a `^`. This extends to multiple levels: `^^^foo` means the fourth most innermost instance of `foo`.
77−
78−> `dejs-soft:format` in `zuse` is a useful library for parsing complex json into hoon structures. In this case, the `:` between `dejs-soft` and `format` means 'inside of', because `dejs-soft` is an arm contained within the core `format`. Our case is actually simple enough that the `?>` line could have been `?> =([%s 'click'] jon)`.
79−
80−We can test this mark from the command line (don't forget to start your app with `|start %click`)
81−
82−```
83−~fintud-macrep:dojo> &click %click
84−%click
85−
86−~fintud-macrep:dojo> &click &json [%s 'click']
87−%click
88−
89−~fintud-macrep:dojo> &click &json &mime [/text/json (as-octs:mimes:html '"click"')]
90−%click
91−
92−~fintud-macrep:dojo> &click &json &mime [/text/json (as-octs:mimes:html '"clickety"')]
93−/~fintud-macrep/home/0/mar/click:<[7 5].[8 11]>
94−ford: casting %json to %click
95−ford: cast %click
96−```
97−
98−And save the following as `/mar/clicks.hoon`:
99−
100−```
101−|_ clicks=@
102−++ grab
103− |%
104− ++ noun @
105− --
106−++ grow
107− |%
108− ++ json
109− (frond:enjs:format %clicks (numb:enjs:format clicks))
110− --
111−--
112−```
113−
114−`clicks` is just an atom. We convert to json by creating an
115−object with a single field "clicks" with our value.
116−
117−> Be sure to check out section 3bD, JSON and XML, in zuse.hoon `frond:enjs:format` is just a function that takes a key-value pair and produces a JSON object with one element.
118−
119−```
120−~fintud-macrep:dojo> &json &clicks 6
121−[%o p={[p='clicks' q=[%n p=~.6]]}]
122−```
123−
124−Now that we know the marks involved, take another look at the app
125−above. Everything should be pretty straightforward. Let's poke
126−the app from the command line.
127−
128−```
129−~fintud-macrep:dojo> |start %click
130−>=
131−~fintud-macrep:dojo> :click &click %click
132−[%poked 1]
133−>=
134−~fintud-macrep:dojo> :click &click %click
135−[%poked 2]
136−>=
137−```
138−
139−*Exercise*:
140−
141−- Modify `:sink` from the subscriptions chapter to listen to `:click` and print out the subscription updates on the command line.
142−
143−# Frontend
144−
145−> Note: the instructions below are outdated and do not work in the current version of Urbit. Feel free to experiment though.
146−
147−That's all that's needed for the back end. The front end is just
148−some "sail" html (Hoon markup for XML) and javascript. Here's `/web/pages/click.hoon`:
149−
150−```
151−;html
152− ;head
153− ;script(type "text/javascript", src "//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js");
154− ;script(type "text/javascript", src "/~/at/lib/js/urb.js");
155− ;title: Clickety!
156− ==
157− ;body
158− ;div#cont
159− ;input#go(type "button", value "Poke!");
160− ;div#err(class "disabled");
161− ;div#clicks;
162− ==
163− ;script(type "text/javascript", src "/pages/click/click.js");
164− ==
165−==
166−```
167−
168−You should recognize the sail syntax from an earlier chapter.
169−Aside from jquery, we also include `urb.js`, which is a framework
170−for interacting with urbit.
171−
172−To view the frontend, point your browser at `ship-name.urbit.org/~~/pages/click` if you're on the live network. If you're running a fake galaxy, navigate to whatever port it's running on, which is usually: `https://localhost:8443/~~/pages/click`.
173−
174−We have a button labeled "Poke!" and a div with id `clicks` where
175−we'll put the number of clicks. We also include a small
176−javascript file where the client-side application logic can be
177−found. It's in `/web/pages/click.js`:
178−
179−```
180−$(function() {
181− var clicks, $go, $clicks, $err
182−
183− $go = $('#go')
184− $clicks = $('#clicks')
185− $err = $('#err')
186−
187− $go.on("click",
188− function() {
189− window.urb.send(
190− "click", {mark: "click-click"}
191− ,function(err,res) {
192− if(err)
193− return $err.text("There was an error. Sorry!")
194− if(res.data !== undefined &&
195− res.data.ok !== undefined &&
196− res.data.ok !== true)
197− $err.text(res.data.res)
198− else
199− console.log("poke succeeded");
200− })
201− })
202−
203− window.urb.appl = "click"
204− window.urb.bind('/the-path',
205− function(err,dat) {
206− clicks = dat.data.clicks
207− $clicks.text(clicks)
208− }
209− )
210−})
211−```
212−
213−We set up two event handlers. When we click the button, we run
214−`window.urb.send`, which sends a poke to the app specified as the first argument, in this case our :click app. The arguments
215−are data, parameters, and the callback. The data is the specific
216−data we want to send. The parameters are all optional, but here's a list
217−of the available ones:
218−
219−- `ship`: target urbit. Defaults to `window.urb.ship`, which
220− defaults to the urbit which served the page.
221−- `appl`: target app. Defaults to `window.urb.appl`, which
222− defaults to null.
223−- `mark`: mark of the data. Defaults to `window.urb.send.mark`,
224− which defaults to "json".
225−- `wire`: wire of the poke. Defaults to `/`.
226−
227−In our case, we specify only that the mark is "click".
228−
229−The callback function is called when we receive an
230−acknowledgment. If there was an error, we put it in the `err`
231−div that we defined above. Otherwise, we printf to the console a
232−message saying the poke succeeded. As is common, we gray
233−out the button when it is clicked. It is only reenabled when positive acknowledgement is received.
234−
235−Our second event handler is `window.urb.bind`, which is called immediately when the page is loaded, subscribing the page to the specified data stream on the app set with `urb.appl` (which is, in this case, :click). It also takes three arguments: path, parameters, and callback. The path is the path on the app to subscribe to. The parameters are all optional (indeed, we omit them entirely here), but are similar to those for `send`:
236−
237−- `ship`: target urbit. Defaults to `window.urb.ship`, which defaults to the urbit which served the page.
238−- `appl`: target app. Defaults to `window.urb.appl`, which defaults to null.
239−- `mark`: mark of expected data. Data of other marks is converted to this mark on the server before coming to the web front end. Defaults to `window.urb.bind.mark`, which defaults to "json".
240−- `wire`: wire of the subscription. Defaults to the given path.
241−
242−The callback function here just updates the data in the `clicks`
243−div. A truly robust app would intelligently handle errors, of
244−course.
245−
246−Note that the app doesn't have anything web-specific in itself.
247−As far as it knows, it's just receiving pokes and subscriptions.
248−The javascript is fairly pure as well, sending and receiving json
249−everywhere. The marks are the translation layer, and they're the
250−only things that need to know how the hoon types map to json.
251−
252−*Exercise*:
253−
254−- Open the app in multiple tabs, click the button, and verify that all the tabs stay in sink. Poke it manually from the command line and verify the tabs are updated as well.
learn/arvo/arvo-internals/hall.udon+1354−4
@@ -8,10 +8,1360 @@
88
99# Hall
1010
11−> Last major revision of this tutorial: 2017. Some of the information here may
11+> Last major revision of this tutorial: 2017. Some of the information and Hoon syntax here may
1212 be outdated.
1313
14−Hall is the Urbit messaging and notifications protocol. Read up on Hall's
15−architecture, its interfaces and the new Gall model it's built to target.
1614
17−;list;
15+Hall is the Urbit messaging and notifications protocol. This document details Hall's architecture, its interfaces, and the new Gall model it's built to target.
16+
17+## Table of contents
18+
19+- #### [Hall Architecture](#architecture)
20+
21+- #### [The Hall Interface](#interface)
22+
23+- #### [The New Gall Model](#new-gall)
24+
25+;=
26+ ;h1
27+ ;div(id "architecture"): Hall Architecture
28+ ==
29+==
30+
31+This document is complemented by Hall's source code, but doesn't require it. Definitions of data structures, code snippets and diagrams will be provided where useful.
32+
33+Hall's implementation is structured according to the new Gall model. Familiarity with its concepts is assumed. See [the new Gall model](#new-gall).
34+
35+## Talk
36+
37+Talk was Urbit's first big user-facing application. It continues to enjoy a prominent role in the Urbit landscape, but now does so as two separate applications.
38+
39+The messaging parts of Talk have been separated from its user-interface parts. What we ended up with is a shiny new generic messaging bus, and the chat interface we all know and love. The messaging bus, which should now prove useful to many different applications, will be named `Hall`. Applications that use it are referred to as *clients*. One such application, as you might have guessed, is `:talk`.
40+
41+
42+## Structures & functionality
43+
44+### Circles
45+
46+```
47+++ circle {hos/ship nom/term} :: native target
48+```
49+
50+A `circle` is essentially a named collection of messages created by and hosted on a ship's Hall, usually represented as `~ship-name/circle-name`. Most of Hall revolves around doing things with circles.
51+
52+### Messages
53+
54+When we subscribe to a circle, the primary thing we're interested in is its messages. Message data itself isn't that complicated, but a fair amount of metadata comes into play when actually sending a message. Let's work our way up, starting at the contents.
55+
56+```
57+++ speech :> content body
58+ $% {$lin pat/? msg/cord} :< no/@ text line
59+ {$url url/purf:eyre} :< parsed url
60+ {$exp exp/cord res/(list tank)} :< hoon line
61+ {$ire top/serial sep/speech} :< in reply to
62+ {$fat tac/attache sep/speech} :< attachment
63+ {$app app/term sep/speech} :< app message
64+ {$inv inv/? cir/circle} :< inv/ban for circle
65+ == ::
66+```
67+
68+At the heart of every message lies a `speech` that describes the message body. There's a large number of different speech types, from simple text messages to parsed URLs, Hoon expressions and more.
69+
70+```
71+++ audience (set circle) :< destinations
72+++ serial @uvH :< unique identifier
73+++ thought :> inner message
74+ $: uid/serial :< unique identifier
75+ aud/audience :< destinations
76+ wen/@da :< timestamp
77+ sep/speech :< content
78+ == ::
79+```
80+
81+A `speech` is always accompanied by various bits of metadata. We include a unique identifier, a message timestamp and an `audience`, the set of all intended recipients of the message.
82+
83+```
84+++ telegram {aut/ship thought} :< whose message
85+++ envelope {num/@ud gam/telegram} :< outward message
86+```
87+
88+Finally, before sending the message over the wire, we add on the message's original author. In most cases, we also include a sequence number, the index of the message in the originating circle's list of messages. This can be a useful point of reference for clients.
89+
90+### Participant metadata
91+
92+Messages aren't the only thing a subscription gets us. We're also kept up to date with relevant metadata.
93+
94+```
95+++ crowd {loc/group rem/(map partner group)} :< our & srcs presences
96+++ group (map ship status) :< presence map
97+++ status {pec/presence man/human} :< participant
98+++ presence :> status type
99+ $? $gone :< absent
100+ $idle :< idle
101+ $hear :< present
102+ $talk :< typing
103+ == ::
104+++ human :> human identifier
105+ $: han/(unit cord) :< handle
106+ tru/(unit truename) :< true name
107+ == ::
108+++ truename {fir/cord mid/(unit cord) las/cord} :< real-life name
109+```
110+
111+`status` is user-set metadata that describes, well, the status of users in a circle. This encompasses their `presence`, which shows their activity, and their `human` identity, which includes their display handle.
112+
113+For reasons we'll discover shortly, circles keep track of both their own `group` and those of the circles they're subscribed to. `crowd` encapsulates this.
114+
115+### Configurations
116+
117+```
118+++ lobby {loc/config rem/(map circle config)} :< our & srcs configs
119+++ config :> circle config
120+ $: src/(set circle) :< active sources
121+ cap/cord :< description
122+ fit/filter :< message rules
123+ con/control :< restrictions
124+ == ::
125+++ filter :> content filters
126+ $: cas/? :< dis/allow capitals
127+ utf/? :< dis/allow non-ascii
128+ == ::
129+++ control {sec/security ses/(set ship)} :< access control
130+```
131+
132+Another part of metadata we get from circle subscriptions is configurations. Again, circles want to remember their own configuration, as well as those of their subscriptions. But why, precisely?
133+
134+The `config` structure contains `src`, a set of partners. These indicate the different sources a circle is currently pulling content from. This allows circles to aggregate messages from multiple places. In doing so, it also receives metadata from those places, hence why we have structures for storing "remote" presences and configurations alongside local ones.
135+
136+Aside from that, `config` contains a description for the circle, which is exactly what it sounds like. It also specifies a `filter`, which are content formatting rules all messages passing through this circle are made to adhere to.
137+
138+Lastly, there's a `control` structure that contains both a security mode and a list of ships, which is either a white- or blacklist depending on the aforementioned mode. There are four such modes available.
139+
140+```
141+++ security :> security mode
142+ $? $channel :< blacklist
143+ $village :< whitelist
144+ $journal :< pub r, whitelist w
145+ $mailbox :< our r, blacklist w
146+ == ::
147+```
148+
149+A `channel` is publicly readable and writable, with a blacklist for blocking.
150+A `village` is privately readable and writable, with a whitelist for inviting.
151+A `journal` is publicly readable and privately writable, with a whitelist for authors.
152+A `mailbox` is readable by its owner and publicly writable, with a blacklist for blocking.
153+
154+### Stories
155+
156+To see how that all ties together, we're going to take a look at Hall's state.
157+
158+```
159+++ state :> hall state
160+ $: stories/(map term story) :< conversations
161+ :: ... ::
162+ == ::
163+++ story :> wire content
164+ $: grams/(list telegram) :< all messages
165+ locals/group :< local presence
166+ remotes/(map circle group) :< remote presence
167+ shape/config :< configuration
168+ mirrors/(map circle config) :< remote config
169+ :: ... ::
170+ == ::
171+```
172+
173+Stories are the primary driver behind Hall. They are the structures that are used to power circles, which we can now say are named stories hosted on ships.
174+
175+With the configuration described above in mind, we can try and imagine the things we can do with stories. Knowing that we can subscribe them to any number of sources, they can function as central hubs for our messaging, aggregate specific kinds of data feeds, or simply accept whatever messages get sent to it like a regular old chatroom.
176+
177+### General use
178+
179+Upon initial startup, Hall creates a default story, a mailbox named `inbox`. This mailbox is the primary target for anyone and anything that wants to reach its owner. Applications can use it to send notifications and other information to the user (Hall itself does this as well), and users can use it to send direct messages to each other.
180+
181+Applications that use Hall, especially clients, are encouraged to use the default mailbox as the primary messaging hub. This way, users can easily switch between different applications without "losing" their subscriptions, message backlog, etc.
182+
183+As an example, Talk operates like this, serving as an interface for reading from and managing the user's mailbox. Local stories are subscribed to through the `inbox`, which ends up containing all messages the user receives.
184+
185+### Federation
186+
187+Some places, like `urbit-meta`, will want to be easily accessible to everyone on the network, and actually support the load that comes with that. Both of these desires can be achieved through federation.
188+
189+With federation, stories and any changes to them trickle down from ~zod, to other galaxies, to their stars. Only changes to messages and presence can also move upstream, from stars, to galaxies, to ~zod (and then back down again).
190+
191+This way, all planets and comets will be able to subscribe to `/urbit-meta` (that is, the `urbit-meta` circle on their parent ship) and get all updates on the story, regardless of where on the network they originated.
192+
193+### Public membership
194+
195+To aid in discoverability of circles, it is possible for users to make their participation in any given circle public. This data can then be used by things like profile widgets, or read out directly by other users.
196+
197+
198+## Interfaces for applications
199+
200+Applications can interact with Hall in two complementary ways: they can tell it what actions to perform, and they can subscribe to its state and the changes made to it.
201+
202+### Interactions
203+
204+Hall can be commanded by poking it with `action`s.
205+
206+```
207+++ action :> user action
208+ $% :: circle configuration ::
209+ {$create nom/term des/cord sec/security} :< create circle
210+ {$delete nom/term why/(unit cord)} :< delete + announce
211+ {$depict nom/term des/cord} :< change description
212+ {$filter nom/term fit/filter} :< change message rules
213+ {$permit nom/term inv/? sis/(set ship)} :< invite/banish
214+ {$source nom/term sub/? srs/(set source)} :< un/sub to/from src
215+ :: messaging ::
216+ {$convey tos/(list thought)} :< post exact
217+ {$phrase aud/audience ses/(list speech)} :< post easy
218+ :: personal metadata ::
219+ {$notify aud/audience pes/(unit presence)} :< our presence update
220+ {$naming aud/audience man/human} :< our name update
221+ :: changing shared ui ::
222+ {$glyph gyf/char aud/audience bin/?} :< un/bind a glyph
223+ {$nick who/ship nic/cord} :< new identity
224+ :: misc changes ::
225+ {$public add/? cir/circle} :< show/hide membership
226+ == ::
227+```
228+
229+The largest part of these actions concern themselves with managing local circles. `nom` is always the name used to identify the relevant story. To disambiguate between "add" and "delete" type actions (for permissions and subscriptions), a loob `?` is used.
230+
231+To send messages, two interfaces are available. `%convey` lets you specify all details of the messages, including its timestamp, serial, and fully assembled audience. `%phrase`, on the other hand, takes care of that for you, allowing you to specify just the target partners and message contents.
232+
233+`%notify` and `%naming` are useful for setting your own presence and nickname in a circle respectively, so others can see if you're active and what to call you by.
234+
235+"Shared UI" encompasses UI data that should be consistent across applications. For example, if the user sets a local nickname for an identity, they expect to see that nickname regardless of the application they're currently using. The same goes for glyph bindings, for easy audience targeting.
236+
237+### Queries, prizes and rumors
238+
239+To receive data from Hall, applications will have to query it. There are two paths that are useful for clients to query. Let's look at them and their results.
240+
241+```
242+++ query :> query paths
243+ $% {$client $~} :< shared ui state
244+ $: $circle :> story query
245+ nom/naem :< circle name
246+ wat/(set circle-data) :< data to get
247+ ran/range :< query duration
248+ == ::
249+ :: ... ::
250+ == ::
251+++ circle-data :> kinds of circle data
252+ $? $grams :< messages
253+ $group-l :< local presence
254+ $group-r :< remote presences
255+ $config-l :< local config
256+ $config-r :< remote configs
257+ == ::
258+++ range :> inclusive msg range
259+ %- unit :< ~ means everything
260+ $: hed/place :< start of range
261+ tal/(unit place) :< opt end of range
262+ == ::
263+++ place :> range indicators
264+ $% {$da @da} :< date
265+ {$ud @ud} :< message number
266+ == ::
267+++ prize :> query result
268+ $% $: $client :< /client
269+ gys/(jug char (set partner)) :< glyph bindings
270+ nis/(map ship cord) :< nicknames
271+ == ::
272+ {$circle burden} :< /circle
273+ :: ... ::
274+ == ::
275+++ burden :< full story state
276+ $: gaz/(list telegram) :< all messages
277+ cos/lobby :< loc & rem configs
278+ pes/crowd :< loc & rem presences
279+ == ::
280+```
281+
282+To be clear, the paths for those queries are `/client` and `/circle/[name]/[data]/[start]/[end]`, where data is at least one `circle-data`, and `start` and `end` are optional and can be either a date or a message number.
283+
284+`/client` queries produce shared UI state. That is, glyph bindings and nicknames.
285+`/circle` queries produce the entire public state of the requested story, including remotes.
286+
287+Any changes to the results of these queries are communicated via the following `rumor`s. It's a fairly long list of potential changes,
288+
289+```
290+++ rumor :< query result change
291+ $% {$client rum/rumor-client} :< /client
292+ {$circle rum/rumor-story} :< /circle
293+ :: ... ::
294+ == ::
295+++ rumor-client :< changed ui state
296+ $% {$glyph diff-glyph} :< un/bound glyph
297+ {$nick diff-nick} :< changed nickname
298+ == ::
299+++ diff-glyph {bin/? gyf/char aud/audience} :< un/bound glyph
300+++ diff-nick {who/ship nic/cord} :< changed nickname
301+++ diff-story :> story change
302+ $% {$new cof/config} :< new story
303+ {$config cir/circle dif/diff-config} :< new/changed config
304+ {$status cir/circle who/ship dif/diff-status} :< new/changed status
305+ {$remove $~} :< removed story
306+ :: ... ::
307+ == ::
308+++ rumor-story ::> story rumor
309+ $? diff-story ::< both in & outward
310+ $% {$gram nev/envelope} ::< new/changed msgs
311+ == == ::
312+++ diff-config :> config change
313+ $% {$full cof/config} :< set w/o side-effects
314+ {$source add/? src/source} :< add/rem sources
315+ {$caption cap/cord} :< changed description
316+ {$filter fit/filter} :< changed filter
317+ {$secure sec/security} :< changed security
318+ {$permit add/? sis/(set ship)} :< add/rem to b/w-list
319+ {$remove $~} :< removed config
320+ == ::
321+++ diff-status :> status change
322+ $% {$full sat/status} :< fully changed status
323+ {$presence pec/presence} :< changed presence
324+ {$human dif/diff-human} :< changed name
325+ {$remove $~} :< removed status
326+ == ::
327+++ diff-human :> name change
328+ $% {$full man/human} :< fully changed name
329+ {$handle han/(unit cord)} :< changed handle
330+ {$true tru/(unit truename)} :< changed true name
331+ == ::
332+```
333+
334+These are, as enforced by Gall, the changes as they happen. This makes it possible for very minimal Hall clients to be implemented that only display a stream of changes, rather than keeping state themselves.
335+
336+
337+## Communication between Halls
338+
339+Halls can communicate with other Halls by sending commands and subscription updates.
340+
341+### Commands
342+
343+To request changes to a story, Halls can send `command`s.
344+
345+```
346+++ command :> effect on story
347+ $% {$publish tos/(list thought)} :< deliver
348+ {$present nos/(set term) dif/diff-status} :< status update
349+ :: ... ::
350+ == ::
351+```
352+
353+A `%publish` command contains messages. These are sent to foreign Halls to be published to their stories.
354+
355+The `%present` command is used for sending status updates about our ship.
356+
357+### Querying
358+
359+Halls can query other halls. Here's the peer move we send when we open a query on a foreign circle:
360+
361+```
362+:* ost.bol :< bone
363+ %peer :< move type
364+ /[our-circle]/[host]/[query-path] :< rumor path
365+ [host %hall] :< query target
366+ /circle/[their-circle]/[data]/[start]/[end] :< query path
367+== ::
368+```
369+
370+Again, the rumor path is what our Hall uses to identify what query a received message originates from. Our circle is specified so that we know what story is interested in the changes we get.
371+
372+The query path is slightly more interesting. Of course it specifies the name of their story we want to subscribe our story to, but also a "start" and "end". These can (optionally) be used to specify the range of messages we want to get from our query. Once that range has passed, we stop receiving updates.
373+
374+### Federation implementation
375+
376+Along the way so far, we've skipped some parts of structures. Most of those relate to federation. Let's see what we missed.
377+
378+```
379+++ query :> query paths
380+ $% {$burden who/ship} :< duties to share
381+ {$report $~} :< duty reports
382+ :: ... ::
383+ == ::
384+++ prize :> query result
385+ $% {$burden sos/(map term burden)} :< /burden
386+ :: ... ::
387+ == ::
388+++ rumor :< query result change
389+ $% {$burden nom/term rum/rumor-story} :< /burden
390+ :: ... ::
391+ == ::
392+++ diff-story ::
393+ $% {$bear bur/burden} :< new inherited story
394+ :: ... ::
395+ == ::
396+++ burden :> full story state
397+ $: gaz/(list telegram) :< all messages
398+ cos/lobby :< loc & rem configs
399+ pes/crowd :< loc & rem presences
400+ == ::
401+```
402+
403+We briefly touched upon how federation works on the higher level. On the lower, this is how things go down.
404+
405+1. When Hall boots on a star or galaxy, it starts querying its parent's `/burden` path. (Galaxies query ~zod.)
406+2. Upon receiving that query, the parent sends a `%burden` prize containing all state of its channels (fully public circles) to the child. It also subscribes to `/report` on that child.
407+3. When a new story gets created on the parent, its children get a `%burden` rumor with a `%bear` story diff, and they create a local copy of that channel.
408+4. When something about a parent's story changes, a `%burden` rumor is sent to all its children (because they're querying `/burden`). The children apply this change to their local version of the story.
409+5. When a child's story has a `%grams` or `%status` change, a `%burden` rumor is sent to the parent (because they're querying `/report`). The parent applies this change to their local version of the story, and #4 happens.
410+
411+
412+## Hall implementation
413+
414+Now that we know what gets sent over the wire and why, let's see what happens whenever such events happen. We won't be covering everything, but enough to illustrate the general flow.
415+
416+First though, it's useful to understand how Hall's code is structured. It consists of primary cores, designed to work optimally with Gall.
417+
418+- `++ta` is the transaction core. For every event that happens, be it a poke, peer or diff, the transaction core gets put to work to process it. Once it's done, it produces a list of deltas that describe how our state needs to be modified.
419+- `++da` is the delta application core. It is used to apply `++ta`'s deltas to our application state, and produce a list of side-effects.
420+
421+Both those cores also have a core within themselves dedicated solely to dealing with stories, `++so` and `++sa` respectively.
422+
423+Once all work in an engine core has finished, its `-done` arm is called to produce the result of all the core's computation.
424+
425+In the diagrams that follow, regular lines indicate flows that always happen. Dashed lines indicate flows that are traversed if the described condition is met.
426+Below the diagrams you will find brief explanations of the involved arms. In a particularly bright future, these might be available on-hover instead.
427+For brevity, utility arms that aren't a direct and important part of the flow have been omitted.
428+
429+(You will find that the origins still use old Gall arms, with some glue code in between. At the time of writing, new Gall has not yet been implemented, so this will have to do.)
430+
431+We will only display the delta generation parts of the flow. Delta application is usually implemented simply enough to deduce what it does from looking at the label.
432+
433+### Subscriptions
434+
435+Hall-to-Hall subscriptions happen when a source gets added to a story. This is done with a `%source` action, and results in a `%peer` move being sent (prompted by a `%story %follow` delta).
436+Upon receiving a valid peer on a `/circle` path, the subscribing ship is added to that circle's presence map.
437+
438+![subscriptions implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-subscriptions.png "subscriptions implementation flow")
439+
440+```
441+++ poke-talk-action :< we got poked with an action.
442+ ++ ta-action :< applies an action.
443+ ++ ta-config :< (re)configures a story.
444+:: ::
445+++ peer :< we got peered.
446+ ++ g-query :< resolves query to prize.
447+ ++ ta-subscribe :< act upon subscription.
448+ ++ so-attend :< adds a ship's status to the story.
449+```
450+
451+### Rumors
452+
453+Once a query has opened, Hall will receive updates on it, rumors. The changes describes in these rumors are applied via the following flow.
454+
455+![rumor implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-rumors.png "report diff implementation flow")
456+
457+```
458+++ diff-talk-rumor :< we got a query update.
459+ ++ ta-hear :< applies a rumor to the story it's intended for.
460+ ++ so-hear :< applies a %circle rumor to the story.
461+ ++ so-config-full :< splits a %full diff-config into separate changes.
462+ ++ so-bear :< accept burden, assimilate into the story's state.
463+ ++ so-lesson :< sends a report with presences.
464+```
465+
466+### Messaging
467+
468+To send messages, the user sends a `%convey` or `%phrase` action, resulting in a `%publish` command being sent to the involved partners. Receiving a `%publish` command causes its messages to be added to the story through the creation of a `%story %grams` delta.
469+
470+![messaging implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-messaging.png "messaging implementation flow")
471+
472+```
473+++ poke-talk-action :< we got poked with an action.
474+ ++ ta-action :< applies an action.
475+:: ::
476+++ poke-talk-command :< we get poked with a command.
477+ ++ ta-apply :< applies a command.
478+ ++ ta-think :< consumes each message in the given list.
479+ ++ ta-consume :< conducts a message to each partner in audience.
480+ ++ ta-conduct :< records or sends a message.
481+ ++ ta-transmit :< sends a message to a partner.
482+ ++ ta-record :< stores a message in a story.
483+ ++ so-learn :< either adds or modifies a message.
484+```
485+
486+
487+## The future
488+
489+Hall is neither complete nor perfect. There are features that need to be implemented, varying from small quality of life changes to broad-reaching functionality.
490+
491+### Features and functionality
492+
493+To turn Talk into a [sustainable social platform](https://urbit.org/fora/posts/~2017.4.26..18.00.25..b93c~/), it needs a number of things.
494+
495+We want to have some kind of discoverability for circles. This could be realized by making it possible for users to add friends, who would have their Hall subscribe to a list of circles the added friends are in. The existing public membership functionality can be leveraged for this.
496+
497+Eventually, content self-moderation might need to be implemented. Users would flag their content if it is potentially offensive. Others would easily be able to filter out content that might offend them.
498+This functionality brings its own large sets of challenges that need to be tackled.
499+
500+Additionally, federation might be put to broader use. Knowing that a circle is federated could help fall back to alternative hosts in case the one Hall originally subscribed to is unavailable. Implementation-wise, care would need to be taken for this to not get ugly. Not to mention, when/how would availability of a host be verified?
501+
502+Other changes that might have a fair impact on the functioning of Hall are un/read states for messages, and being able to use moons to allow your friends to chat with you in a local channel.
503+
504+More minor functionalities that need to be implemented include:
505+- Extended permissions management. Being able to black-/whitelist entire ship classes.
506+- Improved presence functionality. Actually using the presence system, and sending "typing", "idle", etc. statuses.
507+- Polls.
508+
509+And, of course, there's a lot that the Talk client can improve on as well.
510+
511+
512+## Further reading
513+
514+To gain a more thorough understanding of Hall's inner workings, take a look at its source code. It comes with inline documentation.
515+[On Github.](https://github.com/urbit/arvo/blob/master/app/hall.hoon)
516+
517+To see an expansive example of a Hall client, take a look at the code of Talk. It, too, comes with inline documentation.
518+[On Github.](https://github.com/urbit/arvo/blob/master/app/talk.hoon)
519+
520+;=
521+ ;h1
522+ ;div(id "interface"): The Hall Interface
523+ ==
524+==
525+
526+This document describes the different interfaces Hall provides and the data that is accessible and modifiable through them. Knowledge of the Urbit application model (including [new gall](#new-gall)) and [Hall's architecture](#architecture) is assumed.
527+
528+While the structures here are given in Hoon, they match fairly closely to their JSON equivalent. Most important to note is that `$%({$x y/z})` becomes accessible as `json.x.y`.
529+
530+## Queries
531+
532+Queries are the paths you pass into `%peer` moves. Internally, they get translated to a `++query` structure for easier handling. We'll be giving examples of valid query paths alongside the structures themselves.
533+
534+### /client
535+
536+To be able to keep certain UI elements like glyphs and local nicknames consistent across different Hall clients, they can query Hall for the current UI state.
537+
538+```
539+++ query ::
540+ $% {$client $~} :< shared ui state
541+ :: .... ::
542+ == ::
543+```
544+
545+Valid paths include:
546+
547+```
548+:> all shared ui state
549+/client
550+```
551+
552+#### /client prize
553+
554+Contains a map of glyphs and the audiences that they map to, as well as a map of ships and their locally set nicknames.
555+
556+```
557+++ prize :> query result
558+ $% {$client prize-client} :< /client
559+ :: ... ::
560+ == ::
561+++ prize-client :> shared ui state
562+ $: gys/(jug char audience) :< glyph bindings
563+ nis/(map ship nick) :< local nicknames
564+ == ::
565+```
566+
567+#### /client rumor
568+
569+Contains either a bound or unbound glyph and its target, or a ship with its new nickname. A nickname of `''` means the associated ship no longer has a nickname set for it.
570+
571+```
572+++ rumor :> query result change
573+ $% {$client rum/rumor-client} :< /client
574+ :: ... ::
575+ == ::
576+++ rumor-client :< changed ui state
577+ $% {$glyph diff-glyph} :< un/bound glyph
578+ {$nick diff-nick} :< changed nickname
579+ == ::
580+++ diff-glyph {bin/? gyf/char aud/audience} :< un/bound glyph
581+++ diff-nick {who/ship nic/nick} :< changed nickname
582+```
583+
584+
585+### /public
586+
587+To aid in circle discoverability, users can add circles to their "public membership" list. This can then be queried for by, for example, a profile page.
588+
589+```
590+++ query ::
591+ $% {$public $~} :< public memberships
592+ :: .... ::
593+ == ::
594+```
595+
596+Valid paths include:
597+
598+```
599+:> all public memberships
600+/public
601+```
602+
603+#### /public prize
604+
605+Contains the set of circles the user has on their public list.
606+
607+```
608+++ prize :> query result
609+ $% {$public cis/(set circle)} :< /public
610+ :: ... ::
611+ == ::
612+```
613+
614+#### /public rumor
615+
616+Contains a circle that was either added or removed from the public list.
617+
618+```
619+++ rumor :> query result change
620+ $% {$public add/? cir/circle} :< /public
621+ :: ... ::
622+ == ::
623+```
624+
625+### /peers
626+
627+To allow a circle owner to inspect who is currently subscribed to their stories, they can issue a query to retrieve subscription data.
628+
629+```
630+++ query ::
631+ $% {$peers nom/naem} :< readers of story
632+ :: .... ::
633+ == ::
634+```
635+
636+Query paths are structured as follows:
637+
638+```
639+/peers/[circle-name]
640+```
641+
642+Valid paths include:
643+
644+```
645+:> peers for circle %urbit-meta
646+/peers/urbit-meta
647+```
648+
649+#### /peers prize
650+
651+Contains a map of ships and the different queries they currently have active for the selected story.
652+
653+```
654+++ prize :> query result
655+ $% {$peers pes/(jar ship query)} :< /peers
656+ :: ... ::
657+ == ::
658+```
659+
660+#### /peers rumor
661+
662+Contains a ship and a query, and a flag to indicate whether that subscription has started or ended.
663+
664+```
665+++ rumor :> query result change
666+ $% {$peers add/? who/ship qer/query} :< /peers
667+ :: ... ::
668+ == ::
669+```
670+
671+### /circle
672+
673+Circle queries allow for the retrieving of data from stories. Their messages, configuration, and presences can all be accessed. Since this is a lot of data, there are lots of possibilities for filtering it built in to the query itself.
674+
675+
676+A quick refresher on the difference between "local" and "remote" presence and configuration: "local" means it pertains to the circle itself; "remote" means it pertains to one of its configured sources. The latter is primarily useful to clients when using a circle for aggregation, like the `%inbox`.
677+
678+```
679+++ query ::
680+ $% $: $circle :> story query
681+ nom/naem :< circle name
682+ wer/(unit circle) :< from source
683+ wat/(set circle-data) :< data to get
684+ ran/range :< query duration
685+ == ::
686+ :: .... ::
687+ == ::
688+++ circle-data :> kinds of circle data
689+ $? $grams :< messages
690+ $group-l :< local presence
691+ $group-r :< remote presences
692+ $config-l :< local config
693+ $config-r :< remote configs
694+ == ::
695+++ range :> inclusive msg range
696+ %- unit :< ~ means everything
697+ $: hed/place :< start of range
698+ tal/(unit place) :< opt end of range
699+ == ::
700+++ place :> range indicators
701+ $% {$da @da} :< date
702+ {$ud @ud} :< message number
703+ == ::
704+```
705+
706+Query paths are structured as follows:
707+
708+```
709+/circle/[circle-name]/(from-circle)/[what/data]/(range-start(/range-end))
710+(from-circle) : optional message source, ~ship/circle
711+[what/data] : one or more of grams, group, group-l, group-r,
712+ : config, config-l, config-r, combined using /
713+(range) : an optional range with an optional end, its points denoted
714+ : in either message number (@ud) or date (@da)
715+```
716+
717+Valid paths include:
718+
719+```
720+:> get all messages from circle %urbit-meta
721+/circle/urbit-meta/grams
722+:> get all messages, all presences and local configs from %urbit-meta
723+/circle/urbit-meta/grams/group/config-l
724+:> get all messages %urbit-meta has heard from its source ~zod/fora
725+/circle/urbit-meta/~zod/fora/grams
726+:> get the first 100 messages from %urbit-meta
727+/circle/urbit-meta/grams/0/99
728+:> get the first 100 messages %urbit-meta has heard from its source ~zod/fora
729+/circle/urbit-meta/~zod/fora/grams/0/99
730+:> get all messages from %urbit-meta, starting now
731+/circle/urbit-meta/grams/group/(scow %da now)
732+:> get all messages from %urbit-meta, starting now, ending at the 100th message
733+/circle/urbit-meta/grams/(scow %da now)/99
734+:> get local presences from %urbit-meta for a week
735+/circle/urbit-meta/group-l/(scow %da now)/(scow %da (add now ~d7))
736+```
737+
738+#### /circle prize
739+
740+Contains (where applicable) messages in envelopes (with message numbers), as well as local and remote configurations and presences.
741+
742+```
743+++ prize :> query result
744+ $% {$circle package} :< /circle
745+ :: ... ::
746+ == ::
747+++ package :> story state
748+ $: nes/(list envelope) :< messages
749+ cos/lobby :< loc & rem configs
750+ pes/crowd :< loc & rem presences
751+ == ::
752+```
753+
754+#### /circle rumor
755+
756+Contains a detailed change description of the data relevant to the query that changed.
757+
758+Messages are wrapped in envelopes to include their sequence number, and note the source they were heard from. Configuration and status changes specify the circle they apply to.
759+
760+```
761+++ rumor :> query result change
762+ $% {$circle rum/rumor-story} :< /circle
763+ :: ... ::
764+ == ::
765+++ rumor-story :> story rumor
766+ $% {$new cof/config} :< new story
767+ {$gram src/circle nev/envelope} :< new/changed message
768+ {$config cir/circle dif/diff-config} :< new/changed config
769+ {$status cir/circle who/ship dif/diff-status} :< new/changed status
770+ {$remove $~} :< removed story
771+ == ::
772+++ diff-config :> config change
773+ $% {$full cof/config} :< set w/o side-effects
774+ {$source add/? src/source} :< add/rem sources
775+ {$caption cap/cord} :< changed description
776+ {$filter fit/filter} :< changed filter
777+ {$secure sec/security} :< changed security
778+ {$permit add/? sis/(set ship)} :< add/rem to b/w-list
779+ {$remove $~} :< removed config
780+ == ::
781+++ diff-status :> status change
782+ $% {$full sat/status} :< fully changed status
783+ {$presence pec/presence} :< changed presence
784+ {$human dif/diff-human} :< changed name
785+ {$remove $~} :< removed status
786+ == ::
787+++ diff-human :> name change
788+ $% {$full man/human} :< fully changed name
789+ {$handle han/(unit cord)} :< changed handle
790+ {$true tru/(unit truename)} :< changed true name
791+ == ::
792+```
793+
794+
795+## Actions
796+
797+Actions can be sent by poking Hall with data marked as `%hall-action`. Actions are used for all user operations. If an error or other unexpected behavior occurs while executing an action, Hall notifies the user by sending an `%app` message to their `%inbox`.
798+
799+### Circle configuration
800+
801+Since all of these apply to a specific circle, they all specify a name `nom` of the circle to operate on.
802+
803+```
804+++ action :> user action
805+ $% {$create nom/naem des/cord sec/security} :< create circle
806+ {$delete nom/naem why/(unit cord)} :< delete + announce
807+ {$depict nom/naem des/cord} :< change description
808+ {$filter nom/naem fit/filter} :< change message rules
809+ {$permit nom/naem inv/? sis/(set ship)} :< invite/banish
810+ {$source nom/naem sub/? srs/(set source)} :< un/sub to/from src
811+ :: ... ::
812+ ==
813+```
814+
815+`%create`: Creates a circle with description `des` and security mode `sec`. If this mode is a whitelist, the user is automatically added to it.
816+
817+`%delete`: Deletes the circle. If a reason `why` is provided, posts that as the last message to the circle before deleting it.
818+
819+`%depict`: Set the description of the circle to `des`.
820+
821+`%filter`: Set the filter (message sanitation rules) for the circle to `fit`.
822+
823+`%permit`: Either invite or banish ships to/from the circle, modifying the access control list accordingly. Regardless of whether this actually makes any changes, sends an `%inv` message to the involved ships' `%inbox`es.
824+
825+`%source`: Add or remove sources to/from the circle, un/subscribing it to/from the `grams`, `group-l` and `config-l` each one.
826+
827+### Messaging
828+
829+There are two interfaces for telling Hall to send a message. The first takes entire `thought`s, the second only `speech`es and the audience to send them to.
830+
831+```
832+++ action :> user action
833+ $% {$convey tos/(list thought)} :< post exact
834+ {$phrase aud/audience ses/(list speech)} :< post easy
835+ :: ...
836+ ==
837+```
838+
839+`%convey`: Sends the thoughts to their audiences.
840+
841+`%phrase`: Turns the speeches into thoughts by applying sane defaults for metadata (auto-generated `uid`, `now` for `wen`), and then sends those thoughts.
842+
843+### Personal metadata
844+
845+These concern the presence users have in circles they are participating in.
846+
847+```
848+++ action :> user action
849+ $% {$notify aud/audience pes/(unit presence)} :< our presence update
850+ {$naming aud/audience man/human} :< our name update
851+ :: ... ::
852+ ==
853+```
854+
855+`%notify`: Sets the user's presence in the audience circles to `pes`. A good client will automatically set these based on the user's activity. (`%talk` on typing, `%idle` on idle, `%gone` on sign-off.)
856+
857+`%naming`: Sets the user's name (handle and real name) for the given audience. Good clients can display these in place of ship names.
858+
859+### Changing shared UI
860+
861+When the user makes any changes to shared UI elements (elements that should persist between clients), this has to be communicated to Hall.
862+
863+```
864+++ action :> user action
865+ $% {$glyph gyf/char aud/audience bin/?} :< un/bind a glyph
866+ {$nick who/ship nic/nick} :< new identity
867+ :: ... ::
868+ ==
869+```
870+
871+`%glyph`: Adds or removes a binding of a glyph to an audience.
872+
873+`%nick`: Sets a local nickname for a ship. An empty nickname `''` means the ship has no nickname.
874+
875+### Miscellaneous changes
876+
877+```
878+++ action :> user action
879+ $% {$public add/? cir/circle} :< show/hide membership
880+ :: ... ::
881+ ==
882+```
883+
884+`%public`: Adds or removes a circle to/from the user's public membership list.
885+
886+;=
887+ ;h1
888+ ;div(id "new-gall"): The New Gall Model
889+ ==
890+==
891+
892+This document is complemented by the source code of applications that use the new Gall model (like [Hall](https://github.com/urbit/arvo/blob/master/app/hall.hoon)), but doesn't require it. Code snippets will be provided where useful. Some knowledge of Hoon and the functioning of Hoon apps is assumed.
893+
894+New `%gall` has not yet fully solidified. As such, its structure and naming are tentative.
895+
896+## Renewing a pillar of Arvo
897+
898+When you write an app, Gall is responsible for making sure its event arms like `++poke` get called when they need to. In essence, it provides developers with a consistent interface for hooking their app up to the operating system.
899+
900+It's not doing a lot to make sure this is done in a structured way, though, which results in apps (especially larger ones) feeling like big, tangled messes. Something needs to be done about this.
901+
902+### Problems
903+
904+Imagine a `++poke`, `++diff`, or even a `++peer` arm. In current implementations, you'll often see their product defined through cast as the following:
905+`^- (quip move +>)`
906+Or (sadly) more commonly:
907+`^- {(list move) _+>.$}`
908+
909+These arms are producing both side-effects and new state. To do this, their code has to simultaneously figure out "how does this poke/diff/whatever change our state?" and "what side-effects does this change have?"
910+
911+You'll find that the logic relating to these two often becomes tangled, making the flow of the whole more difficult to understand. And the side-effects more often than not relate to subscriptions, for which the developer may be writing a lot of boilerplate code. Gall currently does not help in either of these places.
912+
913+> The main significant cost of software development is the cost of untangling what the computer is doing, and or is supposed to be doing, over and over again in your head. Any way of lowering this untangling cost is extremely welcome.
914+
915+*~sorreg-namtyv*
916+
917+### Solutions
918+
919+Let's imagine a world in which Gall *does* help, in both of those places.
920+
921+It would be wonderful if Gall could take care of all standard subscription management logic for you, and direct the flow of code as it concludes is appropriate. Applications, then, would have to help Gall by providing the different parts of this flow, and providing the checks that allow Gall to make the right decisions. This takes some work out of the developer's hands and results in more structured application code.
922+
923+If we expand on that a bit, then we can even have Gall help us in untangling state changes from side effects. We do so by separating state changes into two phases: *analyzing* what changes need to be made, and *applying* those changes.
924+
925+But where do the side-effects go, then? We need to realize there's two kinds: side-effects that are subscription updates, and side-effects that aren't. The latter get produces by applying state changes, while the former get integrated into the Gall flow we described above.
926+
927+Since subscriptions are essentially queries to an app, requesting a specific part of its data/state, we can deduce subscription updates from state changes. We merely provide the logic, and Gall chains it all together. Having Gall support all this allows us to cleanly and structurally untangle state change analysis, application, and subscription logic into their own arms.
928+
929+For trivial apps, this might result in some arms with trivial code. Though it may feel like writing cruft, it makes understanding the app just as simple as it actually as. For more complex apps, all logic is no longer a big chunk of "what do we do when x happens?" Rather, it's a few smaller chunks, like "x happened, how does that change our state?" and "if our state changes like y, what does that mean for subscription z?" These are precisely the kinds of questions that application developers should be asked.
930+
931+
932+## As seen in new Gall
933+
934+Of course, for the above to be made into reality, Gall will need to see some changes. Let's outline the new structures and the arms they get passed between.
935+
936+### Structures
937+
938+This wouldn't be Urbit if we didn't have cool terminology for people to learn. These ones are (for the most part) semantically sensible, and you might already see how they relate to the story above.
939+
940+`brain`: application state.
941+`delta`: change to application state.
942+`opera`: side-effect, operation, move.
943+`query`: request (to an app) for data on a specific path.
944+`prize`: query result.
945+`rumor`: change to a query result.
946+
947+These should be fairly straightforward. Like packets are to Urbits, `delta`s are to `brain`s and `rumor`s are to `prize`s. If one diligently updates the `prize` they received using all the `rumor`s that are relevant to it, they will always have the same `prize` as if they queried for it all over again.
948+
949+### Arms
950+
951+This also wouldn't be Urbit if we couldn't boil that down to a few simple pseudocode functions. Let's try, shall we?
952+
953+```
954+++ bake |= {brain delta} ^- {brain opera}
955+++ peek |= {brain query} ^- (unit (unit prize))
956+++ feel |= {query delta} ^- (unit rumor)
957+++ gain |= {prize rumor} ^- prize
958+
959+:: for any given brain, delta and query:
960+.= (peek brain:(bake brain delta) query)
961+ (gain rumor:(feel query delta) prize:(peek brain query))
962+```
963+
964+There. In the first three arms we already have the bulk of new Gall! `++gain` won't be part of it, since most applications don't need to keep track of `prize`s directly. Those that do may still implement and hook it up themselves though.
965+
966+Of course, these aren't all of the new Gall arms. Most important to still mention is `++leak`, which takes a `ship` and `query` and checks if the former has permission to ask for the latter.
967+
968+There's also `++look` for asynchronous reads, `++hear` for subscription updates (rumors), `++fail` for dealing with process errors, `++cope` for dealing with transaction results, and `++pour` for dealing with responses from Arvo.
969+`++prep`, `++poke` and `++pull` continue to function as they do right now.
970+
971+For a more verbose specification of all of these, see the new Gall spec.
972+
973+
974+## By example
975+
976+To help solidify this and see what this would looks like in the wild, let's make a very simple example app. It's a counter that can go up and down, and can be queried for its value, or whether or not its value is a multiple of x. First we write all the structures that will support our app, and then we implement the arms that operate on them.
977+(The app code in its entirety can be found [here](example).)
978+
979+### State & deltas
980+
981+Below is the application state, and the deltas we'll be using to modify it.
982+
983+```
984+|%
985+++ brain {num/@ud $~} :< application state
986+++ delta :> state change
987+ $% {$increment $~} :< +1
988+ {$decrement $~} :< -1
989+ == ::
990+```
991+
992+Fairly simple, right? We store a number, and every change either in- or decrements it.
993+
994+### Queries & rumors
995+
996+Let's also define the queries we'll be supporting, their results, and the changes to their results. Instead of only allowing people to query the current number, let's make it a tad more interesting by allowing them to query whether or not the current number is a multiple of something.
997+
998+```
999+++ query :> valid queries
1000+ $% {$number $~} :< current number
1001+ {$mul-of val/@ud} :< is num multiple of?
1002+ == ::
1003+++ prize :> query results
1004+ $% {$number num/@ud} :< /number
1005+ {$mul-of mul/?} :< /mul-of
1006+ == ::
1007+++ rumor :> query result changes
1008+ $% {$number delta} :< /number
1009+ {$mul-of mul/?} :< /mul-of
1010+ == ::
1011+--
1012+```
1013+
1014+You'll see the `rumor` for a `/number` query just contains a delta. In this specific case, a change in state maps directly to a change to `prize`. For `/mul-of` queries, things aren't that simple.
1015+
1016+### Responding to queries
1017+
1018+Now, let's implement all the arms that will be called as things start happening. First, we want to implement `++leak`, which checks if a given `ship` is allowed to make a certain `query`. In this case, we're fine with everyone checking out our application's data.
1019+
1020+```
1021+|_ {bol/bowl brain}
1022+::
1023+++ leak :> read permission
1024+ |= {who/ship qer/query}
1025+ ^- ?
1026+ & :: everyone's allowed
1027+```
1028+
1029+Next, let's create the `prize`s for the folks that make it through `++leak`. We'll be producing a `(unit (unit prize))` so we can potentially say `~` for "unavailable" and `[~ ~]` for "invalid query."
1030+
1031+```
1032+++ peek :> synchronous read
1033+ |= qer/query
1034+ ^- (unit (unit prize))
1035+ ?- -.qer
1036+ $number ``[%number num]
1037+ $mul-of ?: =(0 mul.qer) [~ ~]
1038+ ``[%mul-of =(0 (mod num mul.qer))]
1039+ ==
1040+```
1041+
1042+
1043+### Updating state & query results
1044+
1045+Our app can be queried! If they're interested enough, they'll want to receive updates on that whenever relevant state changes. First, let's see how state changes happen. We still have regular old `++poke` arms, let's use that to prompt our application to change its state.
1046+
1047+```
1048+++ poke-loob :> regular old poke
1049+ |= inc/?
1050+ ^- (list delta)
1051+ :_ ~
1052+ ?: inc [%increment ~]
1053+ [%decrement ~]
1054+::
1055+++ bake :> apply delta to state
1056+ |= del/delta
1057+ ^- (quip opera +>)
1058+ :- ~
1059+ ?- -.del
1060+ $increment +>(num +(num))
1061+ $decrement +>(num (dec num))
1062+ ==
1063+```
1064+
1065+`delta`s get redirected into `++bake` so that our state can get changed as described. After this happens the same `delta`s get, for each active query, routed into `++feel`. That then figures out what the `rumor` relevant to the query is, if applicable.
1066+
1067+```
1068+++ feel :> delta to rumor
1069+ |= {qer/query del/delta}
1070+ ^- (unit rumor)
1071+ ?- -.qer
1072+ $number
1073+ `[%number del]
1074+ ::
1075+ $mul-of
1076+ :: since we only want to send a rumor if result
1077+ :: changed, we need to deduce the old state from
1078+ :: the current state and the delta. depends on the
1079+ :: fact that state changes before ++feel. funky!
1080+ :: we could, of course, store mul/? in state, and
1081+ :: make a delta for it, but should we need to?
1082+ =/ old
1083+ .= 0
1084+ %+ mod
1085+ ?- -.del
1086+ $increment (dec num)
1087+ $decrement +(num)
1088+ ==
1089+ mul.qer
1090+ =/ new =(0 (mod num mul.qer))
1091+ ?: =(old new) ~
1092+ `[%mul-of new]
1093+ ==
1094+```
1095+
1096+As we saw earlier, for `/number` queries the `delta`s match one-on-one with the relevant `rumor`s. For `/mul-of` queries we do a little bit of work to see if anything actually changed. No need to send a `rumor` if it hasn't.
1097+
1098+
1099+## Criticism
1100+
1101+- Where event arms currently get passed a `wire`, and the new Gall described above passes them a custom `query` structure, the original new Gall spec gave them `(list coin)`, a "pre-parsed wire". These structures (eg `[%$ p=[p=~.ud q=123]]`) are uncomfortable to work with. Even with a "coin list parsing library" it still doesn't feel ideal. Because of custom structures being easier to work with than lists of `++knot`s or `++coin`s, writing a `++path-to-query` arm by hand is a small cost for huge gains.
1102+
1103+- Why do `prize` units mean what they do? One would expect `~` to mean "invalid" and `[~ ~]` to mean "unavailable" as opposed to the other way around.
1104+
1105+- The original new Gall spec mentions output lists (like `(list delta)` etc.) to be in reverse order. This was done because adding to the head of a list (`[item list]`) is easier than appending to the tail of a list (`(weld list [item ~])` or other). While it's technically easier to produce a list in reverse order, semantically it's yet another thing to keep in mind. Luckily, most of the "add to x, produce all of it later" code is set-and-forget, so probably not a huge deal. But do we really fear a few stray `++flop`s that much?
1106+
1107+- There's some weirdness with relation to relying on old state in `++feel` to determine whether a query result actually changed. Just relying on state in general for delta-to-rumor conversion may or may not violate the new Gall spec.
1108+
1109+- The original new Gall spec specifies `++leak` as taking a `(unit (set ship))`, where `~` means public. Is there a use case for checking more than just a single ship?
1110+
1111+- Gall should probably cache `++feel` results during a single pass, to avoid the cycles of generating what it can be certain of is the same `(unit rumor)`. (But then for eg `/circle/nom/13` and `/circle/nom/14` it would still recalculate. Better than nothing.)
1112+
1113+
1114+;=
1115+ ;h2
1116+ ;div(id "spec"): The original new-Gall spec
1117+ ==
1118+==
1119+
1120+`~sorreg-namtyv`
1121+
1122+```
1123+=> |%
1124+ --
1125+|* $: :> vinyl: historical state (including version)
1126+ :> brain: working state of the application (not including version)
1127+ :> delta: grain of change across all state
1128+ :> prize: (pair mark noun) for namespace value
1129+ :> rumor: (pair mark noun) for namespace diff
1130+ :> opera: (pair bone card) for operation (old ++move)
1131+ :>
1132+ vinyl/mold
1133+ brain/mold
1134+ delta/mold
1135+ prize/mold
1136+ rumor/mold
1137+ opera/mold
1138+ ==
1139+|_ $: :> ops: pending operations, in reverse order
1140+ :> ego: current state
1141+ :>
1142+ ops/(list opera)
1143+ ego/brain
1144+ ==
1145+:: :: ++bake
1146+++ bake :< apply delta
1147+ |= $: :> del: change
1148+ :>
1149+ del/delta
1150+ ==
1151+ :> core after change (including operations)
1152+ ^- _+>
1153+ !!
1154+:: :: ++cope
1155+++ cope :< transaction result
1156+ |= $: :> weg: forward identity
1157+ :> het: success or error report
1158+ :>
1159+ weg/(list coin)
1160+ het/(unit tang)
1161+ ==
1162+ :> actions in reverse order
1163+ :>
1164+ ^- (list delta)
1165+ !!
1166+:: :: ++fail
1167+++ fail :< process error
1168+ |= $: :> why: error dump
1169+ :>
1170+ why/tang
1171+ ==
1172+ :> actions in reverse order
1173+ :>
1174+ ^- (list delta)
1175+ !!
1176+:: :: ++feel
1177+++ feel :< update
1178+ |= $: :> del: change
1179+ :> pex: preparsed path, inside-first
1180+ :>
1181+ del/delta
1182+ pex/(list coin)
1183+ ==
1184+ :> query updates in reverse order
1185+ :>
1186+ ^- (list rumor)
1187+ !!
1188+:: :: ++hear
1189+++ hear :< subscription update
1190+ |= $: :> weg: forward identity
1191+ :>
1192+ weg/(list coin)
1193+ ==
1194+ :> actions in reverse order
1195+ :>
1196+ ^- (list delta)
1197+ !!
1198+:: :: ++pull
1199+++ pull :< subscription cancel
1200+ |= $: :> weg: forward identity
1201+ :> het: error report, if any
1202+ :>
1203+ weg/(list coin)
1204+ het/(unit tang)
1205+ ==
1206+ :> actions in reverse order
1207+ :>
1208+ ^- (list delta)
1209+ !!
1210+:: :: ++leak
1211+++ leak :< check access
1212+ |= $: :> lec: leakset (~ means public)
1213+ :> pex: preparsed path, inside-first
1214+ :>
1215+ lec/(unit (set ship))
1216+ pex/(list coin)
1217+ ==
1218+ :> if path `pex` is visible to ships in `lec`
1219+ ^- ?
1220+ !!
1221+:: :: ++load
1222+++ look :< asynchronous read
1223+ |= $: :> pex: preparsed path, inside-first
1224+ :>
1225+ pex/(list coin)
1226+ ==
1227+ :> actions in reverse order
1228+ ^- _+>
1229+ !!
1230+:: :: ++prep
1231+++ prep :< load system
1232+ |= $: old/vinyl
1233+ ==
1234+ :> core after boot
1235+ ^- _+>
1236+ !!
1237+:: :: ++peek
1238+++ peek :< synchronous read
1239+ |= $: :> pex: preparsed path, inside-first
1240+ :>
1241+ pex/(list coin)
1242+ ==
1243+ :> value at `pec`; ~ for unavailable, [~ ~] for invalid
1244+ :>
1245+ ^- (unit (unit prize))
1246+ !!
1247+:: :: ++poke
1248+++ poke :< generic poke
1249+ |= $: :> ost: opaque cause
1250+ :> msg: message with mark and vase
1251+ :>
1252+ ost/bone
1253+ msg/cage
1254+ ==
1255+ :> actions in reverse order
1256+ :>
1257+ ^- (list delta)
1258+ !!
1259+:: :: ++pour
1260+++ pour :< arvo response
1261+ |= $: :> weg: forward identity
1262+ :> sin: response card
1263+ :>
1264+ weg/(list coin)
1265+ sin/sign
1266+ ==
1267+ :> actions in reverse order
1268+ :>
1269+ ^- (list delta)
1270+ !!
1271+--
1272+```
1273+
1274+;=
1275+ ;h2
1276+ ;div(id "example"): A new-Gall example app
1277+ ==
1278+==
1279+
1280+```
1281+:: counter app
1282+:: new gall example, may or may not compile.
1283+::
1284+|%
1285+++ query :> valid queries
1286+ $% {$number $~} :< current number
1287+ {$mul-of val/@ud} :< is num multiple of?
1288+ == ::
1289+++ prize :> query results
1290+ $% {$number num/@ud} :< /number
1291+ {$mul-of mul/?} :< /mul-of
1292+ == ::
1293+++ rumor :> query result changes
1294+ $% {$number delta} :< /number
1295+ {$mul-of mul/?} ::TODO or just flip? :< /mul-of
1296+ == ::
1297+:: the above would ordinarily be placed in sur/, ::
1298+:: since other apps might want to use it. ::
1299+++ brain {num/@ud $~} :< application state
1300+++ delta :> state change
1301+ $% {$increment $~} :< +1
1302+ {$decrement $~} :< -1
1303+ == ::
1304+--
1305+::
1306+|_ {bol/bowl brain}
1307+::
1308+++ leak :> read permission
1309+ |= {who/ship qer/query}
1310+ ^- ?
1311+ & :: everyone's allowed
1312+::
1313+++ peek :> synchronous read
1314+ |= qer/query
1315+ ^- (unit (unit prize))
1316+ ?- -.qer
1317+ $number ``[%number num]
1318+ $mul-of ?: =(0 mul.qer) [~ ~]
1319+ ``[%mul-of =(0 (mod num mul.qer))]
1320+ ==
1321+::
1322+++ poke-loob :> regular old poke
1323+ |= inc/?
1324+ ^- (list delta)
1325+ :_ ~
1326+ ?: inc [%increment ~]
1327+ [%decrement ~]
1328+::
1329+++ bake :> apply delta to state
1330+ |= del/delta
1331+ ^- (quip opera +>)
1332+ :- ~
1333+ ?- -.del
1334+ $increment +>(num +(num))
1335+ $decrement +>(num (dec num))
1336+ ==
1337+::
1338+++ feel :> delta to rumor
1339+ |= {qer/query del/delta}
1340+ ^- (unit rumor)
1341+ ?- -.qer
1342+ $number
1343+ `[%number del]
1344+ ::
1345+ $mul-of
1346+ :: since we only want to send a rumor if result
1347+ :: changed, we need to deduce the old state from
1348+ :: the current state and the delta. depends on the
1349+ :: fact that state changes before ++feel. funky!
1350+ :: we could, of course, store mul/? in state, and
1351+ :: make a delta for it, but should we need to?
1352+ =/ old
1353+ .= 0
1354+ %+ mod
1355+ ?- -.del
1356+ $increment (dec num)
1357+ $decrement +(num)
1358+ ==
1359+ mul.qer
1360+ =/ new =(0 (mod num mul.qer))
1361+ ?: =(old new) ~
1362+ `[%mul-of new]
1363+ ==
1364+::
1365+:: not pictured: ++path-to-query
1366+--
1367+```
learn/arvo/arvo-internals/hall/architecture.udondeleted−527
@@ -1,527 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− next/'true'
4− sort/'1'
5− title/'Hall architecture'
6− ==
7−;>
8−
9−# Hall architecture
10−
11−This document is complemented by Hall's source code, but doesn't require it. Definitions of data structures, code snippets and diagrams will be provided where useful.
12−
13−Hall's implementation is structured according to the new Gall model. Familiarity with its concepts is assumed. See [the new Gall model](new-gall).
14−
15−Note: This documentation was written in mid-2017 and uses certain outdated Hoon syntax. We are planning to update it soon, but for now, beware!
16−
17−## Table of contents
18−
19−- [Introduction](#introduction)
20−- [Structures & functionality](#structures--functionality)
21− - [Circles](#circles)
22− - [Messages](#messages)
23− - [Participant metadata](#participant-metadata)
24− - [Configurations](#configurations)
25− - [Stories](#stories)
26− - [General use](#general-use)
27− - [Federation](#federation)
28− - [Public membership](#public-membership)
29−- [Interfaces for applications](#interfaces-for-applications)
30− - [Interactions](#interactions)
31− - [Queries, prizes and rumors](#queries-prizes-and-rumors)
32−- [Communication between Halls](#communication-between-halls)
33− - [Commands](#commands)
34− - [Querying](#querying)
35− - [Federation implementation](#federation-implementation)
36−- [Hall implementation](#hall-implementation)
37− - [Subscriptions](#subscriptions)
38− - [Rumors](#rumors)
39− - [Messaging](#messaging)
40−- [The future](#the-future)
41− - [Features and functionality](#features-and-functionality)
42−- [Further reading](#further-reading)
43−
44−## Introduction
45−
46−Talk was Urbit's first big user-facing application. It continues to enjoy a prominent role in the Urbit landscape, but now does so as two separate applications.
47−
48−The messaging parts of Talk have been separated from its user-interface parts. What we ended up with is a shiny new generic messaging bus, and the chat interface we all know and love. The messaging bus, which should now prove useful to many different applications, will be named `Hall`. Applications that use it are referred to as *clients*. One such application, as you might have guessed, is `:talk`.
49−
50−
51−## Structures & functionality
52−
53−### Circles
54−
55−```
56−++ circle {hos/ship nom/term} :: native target
57−```
58−
59−A `circle` is essentially a named collection of messages created by and hosted on a ship's Hall, usually represented as `~ship-name/circle-name`. Most of Hall revolves around doing things with circles.
60−
61−### Messages
62−
63−When we subscribe to a circle, the primary thing we're interested in is its messages. Message data itself isn't that complicated, but a fair amount of metadata comes into play when actually sending a message. Let's work our way up, starting at the contents.
64−
65−```
66−++ speech :> content body
67− $% {$lin pat/? msg/cord} :< no/@ text line
68− {$url url/purf:eyre} :< parsed url
69− {$exp exp/cord res/(list tank)} :< hoon line
70− {$ire top/serial sep/speech} :< in reply to
71− {$fat tac/attache sep/speech} :< attachment
72− {$app app/term sep/speech} :< app message
73− {$inv inv/? cir/circle} :< inv/ban for circle
74− == ::
75−```
76−
77−At the heart of every message lies a `speech` that describes the message body. There's a large number of different speech types, from simple text messages to parsed URLs, Hoon expressions and more.
78−
79−```
80−++ audience (set circle) :< destinations
81−++ serial @uvH :< unique identifier
82−++ thought :> inner message
83− $: uid/serial :< unique identifier
84− aud/audience :< destinations
85− wen/@da :< timestamp
86− sep/speech :< content
87− == ::
88−```
89−
90−A `speech` is always accompanied by various bits of metadata. We include a unique identifier, a message timestamp and an `audience`, the set of all intended recipients of the message.
91−
92−```
93−++ telegram {aut/ship thought} :< whose message
94−++ envelope {num/@ud gam/telegram} :< outward message
95−```
96−
97−Finally, before sending the message over the wire, we add on the message's original author. In most cases, we also include a sequence number, the index of the message in the originating circle's list of messages. This can be a useful point of reference for clients.
98−
99−### Participant metadata
100−
101−Messages aren't the only thing a subscription gets us. We're also kept up to date with relevant metadata.
102−
103−```
104−++ crowd {loc/group rem/(map partner group)} :< our & srcs presences
105−++ group (map ship status) :< presence map
106−++ status {pec/presence man/human} :< participant
107−++ presence :> status type
108− $? $gone :< absent
109− $idle :< idle
110− $hear :< present
111− $talk :< typing
112− == ::
113−++ human :> human identifier
114− $: han/(unit cord) :< handle
115− tru/(unit truename) :< true name
116− == ::
117−++ truename {fir/cord mid/(unit cord) las/cord} :< real-life name
118−```
119−
120−`status` is user-set metadata that describes, well, the status of users in a circle. This encompasses their `presence`, which shows their activity, and their `human` identity, which includes their display handle.
121−
122−For reasons we'll discover shortly, circles keep track of both their own `group` and those of the circles they're subscribed to. `crowd` encapsulates this.
123−
124−### Configurations
125−
126−```
127−++ lobby {loc/config rem/(map circle config)} :< our & srcs configs
128−++ config :> circle config
129− $: src/(set circle) :< active sources
130− cap/cord :< description
131− fit/filter :< message rules
132− con/control :< restrictions
133− == ::
134−++ filter :> content filters
135− $: cas/? :< dis/allow capitals
136− utf/? :< dis/allow non-ascii
137− == ::
138−++ control {sec/security ses/(set ship)} :< access control
139−```
140−
141−Another part of metadata we get from circle subscriptions is configurations. Again, circles want to remember their own configuration, as well as those of their subscriptions. But why, precisely?
142−
143−The `config` structure contains `src`, a set of partners. These indicate the different sources a circle is currently pulling content from. This allows circles to aggregate messages from multiple places. In doing so, it also receives metadata from those places, hence why we have structures for storing "remote" presences and configurations alongside local ones.
144−
145−Aside from that, `config` contains a description for the circle, which is exactly what it sounds like. It also specifies a `filter`, which are content formatting rules all messages passing through this circle are made to adhere to.
146−
147−Lastly, there's a `control` structure that contains both a security mode and a list of ships, which is either a white- or blacklist depending on the aforementioned mode. There are four such modes available.
148−
149−```
150−++ security :> security mode
151− $? $channel :< blacklist
152− $village :< whitelist
153− $journal :< pub r, whitelist w
154− $mailbox :< our r, blacklist w
155− == ::
156−```
157−
158−A `channel` is publicly readable and writable, with a blacklist for blocking.
159−A `village` is privately readable and writable, with a whitelist for inviting.
160−A `journal` is publicly readable and privately writable, with a whitelist for authors.
161−A `mailbox` is readable by its owner and publicly writable, with a blacklist for blocking.
162−
163−### Stories
164−
165−To see how that all ties together, we're going to take a look at Hall's state.
166−
167−```
168−++ state :> hall state
169− $: stories/(map term story) :< conversations
170− :: ... ::
171− == ::
172−++ story :> wire content
173− $: grams/(list telegram) :< all messages
174− locals/group :< local presence
175− remotes/(map circle group) :< remote presence
176− shape/config :< configuration
177− mirrors/(map circle config) :< remote config
178− :: ... ::
179− == ::
180−```
181−
182−Stories are the primary driver behind Hall. They are the structures that are used to power circles, which we can now say are named stories hosted on ships.
183−
184−With the configuration described above in mind, we can try and imagine the things we can do with stories. Knowing that we can subscribe them to any number of sources, they can function as central hubs for our messaging, aggregate specific kinds of data feeds, or simply accept whatever messages get sent to it like a regular old chatroom.
185−
186−### General use
187−
188−Upon initial startup, Hall creates a default story, a mailbox named `inbox`. This mailbox is the primary target for anyone and anything that wants to reach its owner. Applications can use it to send notifications and other information to the user (Hall itself does this as well), and users can use it to send direct messages to each other.
189−
190−Applications that use Hall, especially clients, are encouraged to use the default mailbox as the primary messaging hub. This way, users can easily switch between different applications without "losing" their subscriptions, message backlog, etc.
191−
192−As an example, Talk operates like this, serving as an interface for reading from and managing the user's mailbox. Local stories are subscribed to through the `inbox`, which ends up containing all messages the user receives.
193−
194−### Federation
195−
196−Some places, like `urbit-meta`, will want to be easily accessible to everyone on the network, and actually support the load that comes with that. Both of these desires can be achieved through federation.
197−
198−With federation, stories and any changes to them trickle down from ~zod, to other galaxies, to their stars. Only changes to messages and presence can also move upstream, from stars, to galaxies, to ~zod (and then back down again).
199−
200−This way, all planets and comets will be able to subscribe to `/urbit-meta` (that is, the `urbit-meta` circle on their parent ship) and get all updates on the story, regardless of where on the network they originated.
201−
202−### Public membership
203−
204−To aid in discoverability of circles, it is possible for users to make their participation in any given circle public. This data can then be used by things like profile widgets, or read out directly by other users.
205−
206−
207−## Interfaces for applications
208−
209−Applications can interact with Hall in two complementary ways: they can tell it what actions to perform, and they can subscribe to its state and the changes made to it.
210−
211−### Interactions
212−
213−Hall can be commanded by poking it with `action`s.
214−
215−```
216−++ action :> user action
217− $% :: circle configuration ::
218− {$create nom/term des/cord sec/security} :< create circle
219− {$delete nom/term why/(unit cord)} :< delete + announce
220− {$depict nom/term des/cord} :< change description
221− {$filter nom/term fit/filter} :< change message rules
222− {$permit nom/term inv/? sis/(set ship)} :< invite/banish
223− {$source nom/term sub/? srs/(set source)} :< un/sub to/from src
224− :: messaging ::
225− {$convey tos/(list thought)} :< post exact
226− {$phrase aud/audience ses/(list speech)} :< post easy
227− :: personal metadata ::
228− {$notify aud/audience pes/(unit presence)} :< our presence update
229− {$naming aud/audience man/human} :< our name update
230− :: changing shared ui ::
231− {$glyph gyf/char aud/audience bin/?} :< un/bind a glyph
232− {$nick who/ship nic/cord} :< new identity
233− :: misc changes ::
234− {$public add/? cir/circle} :< show/hide membership
235− == ::
236−```
237−
238−The largest part of these actions concern themselves with managing local circles. `nom` is always the name used to identify the relevant story. To disambiguate between "add" and "delete" type actions (for permissions and subscriptions), a loob `?` is used.
239−
240−To send messages, two interfaces are available. `%convey` lets you specify all details of the messages, including its timestamp, serial, and fully assembled audience. `%phrase`, on the other hand, takes care of that for you, allowing you to specify just the target partners and message contents.
241−
242−`%notify` and `%naming` are useful for setting your own presence and nickname in a circle respectively, so others can see if you're active and what to call you by.
243−
244−"Shared UI" encompasses UI data that should be consistent across applications. For example, if the user sets a local nickname for an identity, they expect to see that nickname regardless of the application they're currently using. The same goes for glyph bindings, for easy audience targeting.
245−
246−### Queries, prizes and rumors
247−
248−To receive data from Hall, applications will have to query it. There are two paths that are useful for clients to query. Let's look at them and their results.
249−
250−```
251−++ query :> query paths
252− $% {$client $~} :< shared ui state
253− $: $circle :> story query
254− nom/naem :< circle name
255− wat/(set circle-data) :< data to get
256− ran/range :< query duration
257− == ::
258− :: ... ::
259− == ::
260−++ circle-data :> kinds of circle data
261− $? $grams :< messages
262− $group-l :< local presence
263− $group-r :< remote presences
264− $config-l :< local config
265− $config-r :< remote configs
266− == ::
267−++ range :> inclusive msg range
268− %- unit :< ~ means everything
269− $: hed/place :< start of range
270− tal/(unit place) :< opt end of range
271− == ::
272−++ place :> range indicators
273− $% {$da @da} :< date
274− {$ud @ud} :< message number
275− == ::
276−++ prize :> query result
277− $% $: $client :< /client
278− gys/(jug char (set partner)) :< glyph bindings
279− nis/(map ship cord) :< nicknames
280− == ::
281− {$circle burden} :< /circle
282− :: ... ::
283− == ::
284−++ burden :< full story state
285− $: gaz/(list telegram) :< all messages
286− cos/lobby :< loc & rem configs
287− pes/crowd :< loc & rem presences
288− == ::
289−```
290−
291−To be clear, the paths for those queries are `/client` and `/circle/[name]/[data]/[start]/[end]`, where data is at least one `circle-data`, and `start` and `end` are optional and can be either a date or a message number.
292−
293−`/client` queries produce shared UI state. That is, glyph bindings and nicknames.
294−`/circle` queries produce the entire public state of the requested story, including remotes.
295−
296−Any changes to the results of these queries are communicated via the following `rumor`s. It's a fairly long list of potential changes,
297−
298−```
299−++ rumor :< query result change
300− $% {$client rum/rumor-client} :< /client
301− {$circle rum/rumor-story} :< /circle
302− :: ... ::
303− == ::
304−++ rumor-client :< changed ui state
305− $% {$glyph diff-glyph} :< un/bound glyph
306− {$nick diff-nick} :< changed nickname
307− == ::
308−++ diff-glyph {bin/? gyf/char aud/audience} :< un/bound glyph
309−++ diff-nick {who/ship nic/cord} :< changed nickname
310−++ diff-story :> story change
311− $% {$new cof/config} :< new story
312− {$config cir/circle dif/diff-config} :< new/changed config
313− {$status cir/circle who/ship dif/diff-status} :< new/changed status
314− {$remove $~} :< removed story
315− :: ... ::
316− == ::
317−++ rumor-story ::> story rumor
318− $? diff-story ::< both in & outward
319− $% {$gram nev/envelope} ::< new/changed msgs
320− == == ::
321−++ diff-config :> config change
322− $% {$full cof/config} :< set w/o side-effects
323− {$source add/? src/source} :< add/rem sources
324− {$caption cap/cord} :< changed description
325− {$filter fit/filter} :< changed filter
326− {$secure sec/security} :< changed security
327− {$permit add/? sis/(set ship)} :< add/rem to b/w-list
328− {$remove $~} :< removed config
329− == ::
330−++ diff-status :> status change
331− $% {$full sat/status} :< fully changed status
332− {$presence pec/presence} :< changed presence
333− {$human dif/diff-human} :< changed name
334− {$remove $~} :< removed status
335− == ::
336−++ diff-human :> name change
337− $% {$full man/human} :< fully changed name
338− {$handle han/(unit cord)} :< changed handle
339− {$true tru/(unit truename)} :< changed true name
340− == ::
341−```
342−
343−These are, as enforced by Gall, the changes as they happen. This makes it possible for very minimal Hall clients to be implemented that only display a stream of changes, rather than keeping state themselves.
344−
345−
346−## Communication between Halls
347−
348−Halls can communicate with other Halls by sending commands and subscription updates.
349−
350−### Commands
351−
352−To request changes to a story, Halls can send `command`s.
353−
354−```
355−++ command :> effect on story
356− $% {$publish tos/(list thought)} :< deliver
357− {$present nos/(set term) dif/diff-status} :< status update
358− :: ... ::
359− == ::
360−```
361−
362−A `%publish` command contains messages. These are sent to foreign Halls to be published to their stories.
363−
364−The `%present` command is used for sending status updates about our ship.
365−
366−### Querying
367−
368−Halls can query other halls. Here's the peer move we send when we open a query on a foreign circle:
369−
370−```
371−:* ost.bol :< bone
372− %peer :< move type
373− /[our-circle]/[host]/[query-path] :< rumor path
374− [host %hall] :< query target
375− /circle/[their-circle]/[data]/[start]/[end] :< query path
376−== ::
377−```
378−
379−Again, the rumor path is what our Hall uses to identify what query a received message originates from. Our circle is specified so that we know what story is interested in the changes we get.
380−
381−The query path is slightly more interesting. Of course it specifies the name of their story we want to subscribe our story to, but also a "start" and "end". These can (optionally) be used to specify the range of messages we want to get from our query. Once that range has passed, we stop receiving updates.
382−
383−### Federation implementation
384−
385−Along the way so far, we've skipped some parts of structures. Most of those relate to federation. Let's see what we missed.
386−
387−```
388−++ query :> query paths
389− $% {$burden who/ship} :< duties to share
390− {$report $~} :< duty reports
391− :: ... ::
392− == ::
393−++ prize :> query result
394− $% {$burden sos/(map term burden)} :< /burden
395− :: ... ::
396− == ::
397−++ rumor :< query result change
398− $% {$burden nom/term rum/rumor-story} :< /burden
399− :: ... ::
400− == ::
401−++ diff-story ::
402− $% {$bear bur/burden} :< new inherited story
403− :: ... ::
404− == ::
405−++ burden :> full story state
406− $: gaz/(list telegram) :< all messages
407− cos/lobby :< loc & rem configs
408− pes/crowd :< loc & rem presences
409− == ::
410−```
411−
412−We briefly touched upon how federation works on the higher level. On the lower, this is how things go down.
413−
414−1. When Hall boots on a star or galaxy, it starts querying its parent's `/burden` path. (Galaxies query ~zod.)
415−2. Upon receiving that query, the parent sends a `%burden` prize containing all state of its channels (fully public circles) to the child. It also subscribes to `/report` on that child.
416−3. When a new story gets created on the parent, its children get a `%burden` rumor with a `%bear` story diff, and they create a local copy of that channel.
417−4. When something about a parent's story changes, a `%burden` rumor is sent to all its children (because they're querying `/burden`). The children apply this change to their local version of the story.
418−5. When a child's story has a `%grams` or `%status` change, a `%burden` rumor is sent to the parent (because they're querying `/report`). The parent applies this change to their local version of the story, and #4 happens.
419−
420−
421−## Hall implementation
422−
423−Now that we know what gets sent over the wire and why, let's see what happens whenever such events happen. We won't be covering everything, but enough to illustrate the general flow.
424−
425−First though, it's useful to understand how Hall's code is structured. It consists of primary cores, designed to work optimally with Gall.
426−
427−- `++ta` is the transaction core. For every event that happens, be it a poke, peer or diff, the transaction core gets put to work to process it. Once it's done, it produces a list of deltas that describe how our state needs to be modified.
428−- `++da` is the delta application core. It is used to apply `++ta`'s deltas to our application state, and produce a list of side-effects.
429−
430−Both those cores also have a core within themselves dedicated solely to dealing with stories, `++so` and `++sa` respectively.
431−
432−Once all work in an engine core has finished, its `-done` arm is called to produce the result of all the core's computation.
433−
434−In the diagrams that follow, regular lines indicate flows that always happen. Dashed lines indicate flows that are traversed if the described condition is met.
435−Below the diagrams you will find brief explanations of the involved arms. In a particularly bright future, these might be available on-hover instead.
436−For brevity, utility arms that aren't a direct and important part of the flow have been omitted.
437−
438−(You will find that the origins still use old Gall arms, with some glue code in between. At the time of writing, new Gall has not yet been implemented, so this will have to do.)
439−
440−We will only display the delta generation parts of the flow. Delta application is usually implemented simply enough to deduce what it does from looking at the label.
441−
442−### Subscriptions
443−
444−Hall-to-Hall subscriptions happen when a source gets added to a story. This is done with a `%source` action, and results in a `%peer` move being sent (prompted by a `%story %follow` delta).
445−Upon receiving a valid peer on a `/circle` path, the subscribing ship is added to that circle's presence map.
446−
447−![subscriptions implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-subscriptions.png "subscriptions implementation flow")
448−
449−```
450−++ poke-talk-action :< we got poked with an action.
451− ++ ta-action :< applies an action.
452− ++ ta-config :< (re)configures a story.
453−:: ::
454−++ peer :< we got peered.
455− ++ g-query :< resolves query to prize.
456− ++ ta-subscribe :< act upon subscription.
457− ++ so-attend :< adds a ship's status to the story.
458−```
459−
460−### Rumors
461−
462−Once a query has opened, Hall will receive updates on it, rumors. The changes describes in these rumors are applied via the following flow.
463−
464−![rumor implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-rumors.png "report diff implementation flow")
465−
466−```
467−++ diff-talk-rumor :< we got a query update.
468− ++ ta-hear :< applies a rumor to the story it's intended for.
469− ++ so-hear :< applies a %circle rumor to the story.
470− ++ so-config-full :< splits a %full diff-config into separate changes.
471− ++ so-bear :< accept burden, assimilate into the story's state.
472− ++ so-lesson :< sends a report with presences.
473−```
474−
475−### Messaging
476−
477−To send messages, the user sends a `%convey` or `%phrase` action, resulting in a `%publish` command being sent to the involved partners. Receiving a `%publish` command causes its messages to be added to the story through the creation of a `%story %grams` delta.
478−
479−![messaging implementation flow](https://media.urbit.org/docs/hall/diagrams/flow-messaging.png "messaging implementation flow")
480−
481−```
482−++ poke-talk-action :< we got poked with an action.
483− ++ ta-action :< applies an action.
484−:: ::
485−++ poke-talk-command :< we get poked with a command.
486− ++ ta-apply :< applies a command.
487− ++ ta-think :< consumes each message in the given list.
488− ++ ta-consume :< conducts a message to each partner in audience.
489− ++ ta-conduct :< records or sends a message.
490− ++ ta-transmit :< sends a message to a partner.
491− ++ ta-record :< stores a message in a story.
492− ++ so-learn :< either adds or modifies a message.
493−```
494−
495−
496−## The future
497−
498−Hall is neither complete nor perfect. There are features that need to be implemented, varying from small quality of life changes to broad-reaching functionality.
499−
500−### Features and functionality
501−
502−To turn Talk into a [sustainable social platform](https://urbit.org/fora/posts/~2017.4.26..18.00.25..b93c~/), it needs a number of things.
503−
504−We want to have some kind of discoverability for circles. This could be realized by making it possible for users to add friends, who would have their Hall subscribe to a list of circles the added friends are in. The existing public membership functionality can be leveraged for this.
505−
506−Eventually, content self-moderation might need to be implemented. Users would flag their content if it is potentially offensive. Others would easily be able to filter out content that might offend them.
507−This functionality brings its own large sets of challenges that need to be tackled.
508−
509−Additionally, federation might be put to broader use. Knowing that a circle is federated could help fall back to alternative hosts in case the one Hall originally subscribed to is unavailable. Implementation-wise, care would need to be taken for this to not get ugly. Not to mention, when/how would availability of a host be verified?
510−
511−Other changes that might have a fair impact on the functioning of Hall are un/read states for messages, and being able to use moons to allow your friends to chat with you in a local channel.
512−
513−More minor functionalities that need to be implemented include:
514−- Extended permissions management. Being able to black-/whitelist entire ship classes.
515−- Improved presence functionality. Actually using the presence system, and sending "typing", "idle", etc. statuses.
516−- Polls.
517−
518−And, of course, there's a lot that the Talk client can improve on as well.
519−
520−
521−## Further reading
522−
523−To gain a more thorough understanding of Hall's inner workings, take a look at its source code. It comes with inline documentation.
524−[On Github.](https://github.com/urbit/arvo/blob/master/app/hall.hoon)
525−
526−To see an expansive example of a Hall client, take a look at the code of Talk. It, too, comes with inline documentation.
527−[On Github.](https://github.com/urbit/arvo/blob/master/app/talk.hoon)
learn/arvo/arvo-internals/hall/interface.udondeleted−391
@@ -1,391 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− next/'true'
4− sort/'2'
5− title/'Hall interface'
6− ==
7−;>
8−
9−# Hall interface
10−
11−This document describes the different interfaces Hall provides and the data that is accessible and modifiable through them. Knowledge of the Urbit application model (including [new gall](new-gall)) and [Hall's architecture](architecture) is assumed.
12−
13−While the structures here are given in Hoon, they match fairly closely to their JSON equivalent. Most important to note is that `$%({$x y/z})` becomes accessible as `json.x.y`.
14−
15−## Table of contents
16−
17−- [Queries](#queries)
18− - [/client](#client)
19− - [/client prize](#client-prize)
20− - [/client rumor](#client-rumor)
21− - [/public](#public)
22− - [/public prize](#public-prize)
23− - [/public rumor](#public-rumor)
24− - [/peers](#peers)
25− - [/peers prize](#peers-prize)
26− - [/peers rumor](#peers-rumor)
27− - [/circle](#circle)
28− - [/circle prize](#circle-prize)
29− - [/circle rumor](#circle-rumor)
30−- [Actions](#actions)
31− - [Circle configuration](#circle-configuration)
32− - [Messaging](#messaging)
33− - [Personal metadata](#personal-metadata)
34− - [Changing shared UI](#changing-shared-ui)
35− - [Miscellaneous changes](#miscellaneous-changes)
36−
37−## Queries
38−
39−Queries are the paths you pass into `%peer` moves. Internally, they get translated to a `++query` structure for easier handling. We'll be giving examples of valid query paths alongside the structures themselves.
40−
41−### /client
42−
43−To be able to keep certain UI elements like glyphs and local nicknames consistent across different Hall clients, they can query Hall for the current UI state.
44−
45−```
46−++ query ::
47− $% {$client $~} :< shared ui state
48− :: .... ::
49− == ::
50−```
51−
52−Valid paths include:
53−
54−```
55−:> all shared ui state
56−/client
57−```
58−
59−#### /client prize
60−
61−Contains a map of glyphs and the audiences that they map to, as well as a map of ships and their locally set nicknames.
62−
63−```
64−++ prize :> query result
65− $% {$client prize-client} :< /client
66− :: ... ::
67− == ::
68−++ prize-client :> shared ui state
69− $: gys/(jug char audience) :< glyph bindings
70− nis/(map ship nick) :< local nicknames
71− == ::
72−```
73−
74−#### /client rumor
75−
76−Contains either a bound or unbound glyph and its target, or a ship with its new nickname. A nickname of `''` means the associated ship no longer has a nickname set for it.
77−
78−```
79−++ rumor :> query result change
80− $% {$client rum/rumor-client} :< /client
81− :: ... ::
82− == ::
83−++ rumor-client :< changed ui state
84− $% {$glyph diff-glyph} :< un/bound glyph
85− {$nick diff-nick} :< changed nickname
86− == ::
87−++ diff-glyph {bin/? gyf/char aud/audience} :< un/bound glyph
88−++ diff-nick {who/ship nic/nick} :< changed nickname
89−```
90−
91−
92−### /public
93−
94−To aid in circle discoverability, users can add circles to their "public membership" list. This can then be queried for by, for example, a profile page.
95−
96−```
97−++ query ::
98− $% {$public $~} :< public memberships
99− :: .... ::
100− == ::
101−```
102−
103−Valid paths include:
104−
105−```
106−:> all public memberships
107−/public
108−```
109−
110−#### /public prize
111−
112−Contains the set of circles the user has on their public list.
113−
114−```
115−++ prize :> query result
116− $% {$public cis/(set circle)} :< /public
117− :: ... ::
118− == ::
119−```
120−
121−#### /public rumor
122−
123−Contains a circle that was either added or removed from the public list.
124−
125−```
126−++ rumor :> query result change
127− $% {$public add/? cir/circle} :< /public
128− :: ... ::
129− == ::
130−```
131−
132−### /peers
133−
134−To allow a circle owner to inspect who is currently subscribed to their stories, they can issue a query to retrieve subscription data.
135−
136−```
137−++ query ::
138− $% {$peers nom/naem} :< readers of story
139− :: .... ::
140− == ::
141−```
142−
143−Query paths are structured as follows:
144−
145−```
146−/peers/[circle-name]
147−```
148−
149−Valid paths include:
150−
151−```
152−:> peers for circle %urbit-meta
153−/peers/urbit-meta
154−```
155−
156−#### /peers prize
157−
158−Contains a map of ships and the different queries they currently have active for the selected story.
159−
160−```
161−++ prize :> query result
162− $% {$peers pes/(jar ship query)} :< /peers
163− :: ... ::
164− == ::
165−```
166−
167−#### /peers rumor
168−
169−Contains a ship and a query, and a flag to indicate whether that subscription has started or ended.
170−
171−```
172−++ rumor :> query result change
173− $% {$peers add/? who/ship qer/query} :< /peers
174− :: ... ::
175− == ::
176−```
177−
178−### /circle
179−
180−Circle queries allow for the retrieving of data from stories. Their messages, configuration, and presences can all be accessed. Since this is a lot of data, there are lots of possibilities for filtering it built in to the query itself.
181−
182−
183−A quick refresher on the difference between "local" and "remote" presence and configuration: "local" means it pertains to the circle itself; "remote" means it pertains to one of its configured sources. The latter is primarily useful to clients when using a circle for aggregation, like the `%inbox`.
184−
185−```
186−++ query ::
187− $% $: $circle :> story query
188− nom/naem :< circle name
189− wer/(unit circle) :< from source
190− wat/(set circle-data) :< data to get
191− ran/range :< query duration
192− == ::
193− :: .... ::
194− == ::
195−++ circle-data :> kinds of circle data
196− $? $grams :< messages
197− $group-l :< local presence
198− $group-r :< remote presences
199− $config-l :< local config
200− $config-r :< remote configs
201− == ::
202−++ range :> inclusive msg range
203− %- unit :< ~ means everything
204− $: hed/place :< start of range
205− tal/(unit place) :< opt end of range
206− == ::
207−++ place :> range indicators
208− $% {$da @da} :< date
209− {$ud @ud} :< message number
210− == ::
211−```
212−
213−Query paths are structured as follows:
214−
215−```
216−/circle/[circle-name]/(from-circle)/[what/data]/(range-start(/range-end))
217−(from-circle) : optional message source, ~ship/circle
218−[what/data] : one or more of grams, group, group-l, group-r,
219− : config, config-l, config-r, combined using /
220−(range) : an optional range with an optional end, its points denoted
221− : in either message number (@ud) or date (@da)
222−```
223−
224−Valid paths include:
225−
226−```
227−:> get all messages from circle %urbit-meta
228−/circle/urbit-meta/grams
229−:> get all messages, all presences and local configs from %urbit-meta
230−/circle/urbit-meta/grams/group/config-l
231−:> get all messages %urbit-meta has heard from its source ~zod/fora
232−/circle/urbit-meta/~zod/fora/grams
233−:> get the first 100 messages from %urbit-meta
234−/circle/urbit-meta/grams/0/99
235−:> get the first 100 messages %urbit-meta has heard from its source ~zod/fora
236−/circle/urbit-meta/~zod/fora/grams/0/99
237−:> get all messages from %urbit-meta, starting now
238−/circle/urbit-meta/grams/group/(scow %da now)
239−:> get all messages from %urbit-meta, starting now, ending at the 100th message
240−/circle/urbit-meta/grams/(scow %da now)/99
241−:> get local presences from %urbit-meta for a week
242−/circle/urbit-meta/group-l/(scow %da now)/(scow %da (add now ~d7))
243−```
244−
245−#### /circle prize
246−
247−Contains (where applicable) messages in envelopes (with message numbers), as well as local and remote configurations and presences.
248−
249−```
250−++ prize :> query result
251− $% {$circle package} :< /circle
252− :: ... ::
253− == ::
254−++ package :> story state
255− $: nes/(list envelope) :< messages
256− cos/lobby :< loc & rem configs
257− pes/crowd :< loc & rem presences
258− == ::
259−```
260−
261−#### /circle rumor
262−
263−Contains a detailed change description of the data relevant to the query that changed.
264−
265−Messages are wrapped in envelopes to include their sequence number, and note the source they were heard from. Configuration and status changes specify the circle they apply to.
266−
267−```
268−++ rumor :> query result change
269− $% {$circle rum/rumor-story} :< /circle
270− :: ... ::
271− == ::
272−++ rumor-story :> story rumor
273− $% {$new cof/config} :< new story
274− {$gram src/circle nev/envelope} :< new/changed message
275− {$config cir/circle dif/diff-config} :< new/changed config
276− {$status cir/circle who/ship dif/diff-status} :< new/changed status
277− {$remove $~} :< removed story
278− == ::
279−++ diff-config :> config change
280− $% {$full cof/config} :< set w/o side-effects
281− {$source add/? src/source} :< add/rem sources
282− {$caption cap/cord} :< changed description
283− {$filter fit/filter} :< changed filter
284− {$secure sec/security} :< changed security
285− {$permit add/? sis/(set ship)} :< add/rem to b/w-list
286− {$remove $~} :< removed config
287− == ::
288−++ diff-status :> status change
289− $% {$full sat/status} :< fully changed status
290− {$presence pec/presence} :< changed presence
291− {$human dif/diff-human} :< changed name
292− {$remove $~} :< removed status
293− == ::
294−++ diff-human :> name change
295− $% {$full man/human} :< fully changed name
296− {$handle han/(unit cord)} :< changed handle
297− {$true tru/(unit truename)} :< changed true name
298− == ::
299−```
300−
301−
302−## Actions
303−
304−Actions can be sent by poking Hall with data marked as `%hall-action`. Actions are used for all user operations. If an error or other unexpected behavior occurs while executing an action, Hall notifies the user by sending an `%app` message to their `%inbox`.
305−
306−### Circle configuration
307−
308−Since all of these apply to a specific circle, they all specify a name `nom` of the circle to operate on.
309−
310−```
311−++ action :> user action
312− $% {$create nom/naem des/cord sec/security} :< create circle
313− {$delete nom/naem why/(unit cord)} :< delete + announce
314− {$depict nom/naem des/cord} :< change description
315− {$filter nom/naem fit/filter} :< change message rules
316− {$permit nom/naem inv/? sis/(set ship)} :< invite/banish
317− {$source nom/naem sub/? srs/(set source)} :< un/sub to/from src
318− :: ... ::
319− ==
320−```
321−
322−`%create`: Creates a circle with description `des` and security mode `sec`. If this mode is a whitelist, the user is automatically added to it.
323−
324−`%delete`: Deletes the circle. If a reason `why` is provided, posts that as the last message to the circle before deleting it.
325−
326−`%depict`: Set the description of the circle to `des`.
327−
328−`%filter`: Set the filter (message sanitation rules) for the circle to `fit`.
329−
330−`%permit`: Either invite or banish ships to/from the circle, modifying the access control list accordingly. Regardless of whether this actually makes any changes, sends an `%inv` message to the involved ships' `%inbox`es.
331−
332−`%source`: Add or remove sources to/from the circle, un/subscribing it to/from the `grams`, `group-l` and `config-l` each one.
333−
334−### Messaging
335−
336−There are two interfaces for telling Hall to send a message. The first takes entire `thought`s, the second only `speech`es and the audience to send them to.
337−
338−```
339−++ action :> user action
340− $% {$convey tos/(list thought)} :< post exact
341− {$phrase aud/audience ses/(list speech)} :< post easy
342− :: ...
343− ==
344−```
345−
346−`%convey`: Sends the thoughts to their audiences.
347−
348−`%phrase`: Turns the speeches into thoughts by applying sane defaults for metadata (auto-generated `uid`, `now` for `wen`), and then sends those thoughts.
349−
350−### Personal metadata
351−
352−These concern the presence users have in circles they are participating in.
353−
354−```
355−++ action :> user action
356− $% {$notify aud/audience pes/(unit presence)} :< our presence update
357− {$naming aud/audience man/human} :< our name update
358− :: ... ::
359− ==
360−```
361−
362−`%notify`: Sets the user's presence in the audience circles to `pes`. A good client will automatically set these based on the user's activity. (`%talk` on typing, `%idle` on idle, `%gone` on sign-off.)
363−
364−`%naming`: Sets the user's name (handle and real name) for the given audience. Good clients can display these in place of ship names.
365−
366−### Changing shared UI
367−
368−When the user makes any changes to shared UI elements (elements that should persist between clients), this has to be communicated to Hall.
369−
370−```
371−++ action :> user action
372− $% {$glyph gyf/char aud/audience bin/?} :< un/bind a glyph
373− {$nick who/ship nic/nick} :< new identity
374− :: ... ::
375− ==
376−```
377−
378−`%glyph`: Adds or removes a binding of a glyph to an audience.
379−
380−`%nick`: Sets a local nickname for a ship. An empty nickname `''` means the ship has no nickname.
381−
382−### Miscellaneous changes
383−
384−```
385−++ action :> user action
386− $% {$public add/? cir/circle} :< show/hide membership
387− :: ... ::
388− ==
389−```
390−
391−`%public`: Adds or removes a circle to/from the user's public membership list.
learn/arvo/arvo-internals/hall/new-gall.udondeleted−250
@@ -1,250 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− sort/'3'
4− title/'The new Gall model'
5− ==
6−;>
7−
8−# The new Gall model
9−
10−This document is complemented by the source code of applications that use the new Gall model (like [Hall](https://github.com/urbit/arvo/blob/master/app/hall.hoon)), but doesn't require it. Code snippets will be provided where useful. Some knowledge of Hoon and the functioning of Hoon apps is assumed.
11−
12−New `%gall` has not yet fully solidified. As such, its structure and naming are tentative.
13−
14−## Table of contents
15−
16−- [Renewing a pillar of Arvo](#renewing-a-pillar-of-arvo)
17− - [Problems](#problems)
18− - [Solutions](#solutions)
19−- [As seen in new Gall](#as-seen-in-new-gall)
20− - [Structures](#structures)
21− - [Arms](#arms)
22−- [By example](#by-example)
23− - [State & deltas](#state--deltas)
24− - [Queries & rumors](#queries--rumors)
25− - [Responding to queries](#responding-to-queries)
26− - [Updating state & query results](#updating-state--query-results)
27−- [Criticism](#criticism)
28−- [Further reading](#further-reading)
29−
30−## Renewing a pillar of Arvo
31−
32−When you write an app, Gall is responsible for making sure its event arms like `++poke` get called when they need to. In essence, it provides developers with a consistent interface for hooking their app up to the operating system.
33−
34−It's not doing a lot to make sure this is done in a structured way, though, which results in apps (especially larger ones) feeling like big, tangled messes. Something needs to be done about this.
35−
36−### Problems
37−
38−Imagine a `++poke`, `++diff`, or even a `++peer` arm. In current implementations, you'll often see their product defined through cast as the following:
39−`^- (quip move +>)`
40−Or (sadly) more commonly:
41−`^- {(list move) _+>.$}`
42−
43−These arms are producing both side-effects and new state. To do this, their code has to simultaneously figure out "how does this poke/diff/whatever change our state?" and "what side-effects does this change have?"
44−
45−You'll find that the logic relating to these two often becomes tangled, making the flow of the whole more difficult to understand. And the side-effects more often than not relate to subscriptions, for which the developer may be writing a lot of boilerplate code. Gall currently does not help in either of these places.
46−
47−> The main significant cost of software development is the cost of untangling what the computer is doing, and or is supposed to be doing, over and over again in your head. Any way of lowering this untangling cost is extremely welcome.
48−
49−*~sorreg-namtyv*
50−
51−### Solutions
52−
53−Let's imagine a world in which Gall *does* help, in both of those places.
54−
55−It would be wonderful if Gall could take care of all standard subscription management logic for you, and direct the flow of code as it concludes is appropriate. Applications, then, would have to help Gall by providing the different parts of this flow, and providing the checks that allow Gall to make the right decisions. This takes some work out of the developer's hands and results in more structured application code.
56−
57−If we expand on that a bit, then we can even have Gall help us in untangling state changes from side effects. We do so by separating state changes into two phases: *analyzing* what changes need to be made, and *applying* those changes.
58−
59−But where do the side-effects go, then? We need to realize there's two kinds: side-effects that are subscription updates, and side-effects that aren't. The latter get produces by applying state changes, while the former get integrated into the Gall flow we described above.
60−
61−Since subscriptions are essentially queries to an app, requesting a specific part of its data/state, we can deduce subscription updates from state changes. We merely provide the logic, and Gall chains it all together. Having Gall support all this allows us to cleanly and structurally untangle state change analysis, application, and subscription logic into their own arms.
62−
63−For trivial apps, this might result in some arms with trivial code. Though it may feel like writing cruft, it makes understanding the app just as simple as it actually as. For more complex apps, all logic is no longer a big chunk of "what do we do when x happens?" Rather, it's a few smaller chunks, like "x happened, how does that change our state?" and "if our state changes like y, what does that mean for subscription z?" These are precisely the kinds of questions that application developers should be asked.
64−
65−
66−## As seen in new Gall
67−
68−Of course, for the above to be made into reality, Gall will need to see some changes. Let's outline the new structures and the arms they get passed between.
69−
70−### Structures
71−
72−This wouldn't be Urbit if we didn't have cool terminology for people to learn. These ones are (for the most part) semantically sensible, and you might already see how they relate to the story above.
73−
74−`brain`: application state.
75−`delta`: change to application state.
76−`opera`: side-effect, operation, move.
77−`query`: request (to an app) for data on a specific path.
78−`prize`: query result.
79−`rumor`: change to a query result.
80−
81−These should be fairly straightforward. Like packets are to Urbits, `delta`s are to `brain`s and `rumor`s are to `prize`s. If one diligently updates the `prize` they received using all the `rumor`s that are relevant to it, they will always have the same `prize` as if they queried for it all over again.
82−
83−### Arms
84−
85−This also wouldn't be Urbit if we couldn't boil that down to a few simple pseudocode functions. Let's try, shall we?
86−
87−```
88−++ bake |= {brain delta} ^- {brain opera}
89−++ peek |= {brain query} ^- (unit (unit prize))
90−++ feel |= {query delta} ^- (unit rumor)
91−++ gain |= {prize rumor} ^- prize
92−
93−:: for any given brain, delta and query:
94−.= (peek brain:(bake brain delta) query)
95− (gain rumor:(feel query delta) prize:(peek brain query))
96−```
97−
98−There. In the first three arms we already have the bulk of new Gall! `++gain` won't be part of it, since most applications don't need to keep track of `prize`s directly. Those that do may still implement and hook it up themselves though.
99−
100−Of course, these aren't all of the new Gall arms. Most important to still mention is `++leak`, which takes a `ship` and `query` and checks if the former has permission to ask for the latter.
101−
102−There's also `++look` for asynchronous reads, `++hear` for subscription updates (rumors), `++fail` for dealing with process errors, `++cope` for dealing with transaction results, and `++pour` for dealing with responses from Arvo.
103−`++prep`, `++poke` and `++pull` continue to function as they do right now.
104−
105−For a more verbose specification of all of these, see the new Gall spec.
106−
107−
108−## By example
109−
110−To help solidify this and see what this would looks like in the wild, let's make a very simple example app. It's a counter that can go up and down, and can be queried for its value, or whether or not its value is a multiple of x. First we write all the structures that will support our app, and then we implement the arms that operate on them.
111−(The app code in its entirety can be found [here](example).)
112−
113−### State & deltas
114−
115−Below is the application state, and the deltas we'll be using to modify it.
116−
117−```
118−|%
119−++ brain {num/@ud $~} :< application state
120−++ delta :> state change
121− $% {$increment $~} :< +1
122− {$decrement $~} :< -1
123− == ::
124−```
125−
126−Fairly simple, right? We store a number, and every change either in- or decrements it.
127−
128−### Queries & rumors
129−
130−Let's also define the queries we'll be supporting, their results, and the changes to their results. Instead of only allowing people to query the current number, let's make it a tad more interesting by allowing them to query whether or not the current number is a multiple of something.
131−
132−```
133−++ query :> valid queries
134− $% {$number $~} :< current number
135− {$mul-of val/@ud} :< is num multiple of?
136− == ::
137−++ prize :> query results
138− $% {$number num/@ud} :< /number
139− {$mul-of mul/?} :< /mul-of
140− == ::
141−++ rumor :> query result changes
142− $% {$number delta} :< /number
143− {$mul-of mul/?} :< /mul-of
144− == ::
145−--
146−```
147−
148−You'll see the `rumor` for a `/number` query just contains a delta. In this specific case, a change in state maps directly to a change to `prize`. For `/mul-of` queries, things aren't that simple.
149−
150−### Responding to queries
151−
152−Now, let's implement all the arms that will be called as things start happening. First, we want to implement `++leak`, which checks if a given `ship` is allowed to make a certain `query`. In this case, we're fine with everyone checking out our application's data.
153−
154−```
155−|_ {bol/bowl brain}
156−::
157−++ leak :> read permission
158− |= {who/ship qer/query}
159− ^- ?
160− & :: everyone's allowed
161−```
162−
163−Next, let's create the `prize`s for the folks that make it through `++leak`. We'll be producing a `(unit (unit prize))` so we can potentially say `~` for "unavailable" and `[~ ~]` for "invalid query."
164−
165−```
166−++ peek :> synchronous read
167− |= qer/query
168− ^- (unit (unit prize))
169− ?- -.qer
170− $number ``[%number num]
171− $mul-of ?: =(0 mul.qer) [~ ~]
172− ``[%mul-of =(0 (mod num mul.qer))]
173− ==
174−```
175−
176−
177−### Updating state & query results
178−
179−Our app can be queried! If they're interested enough, they'll want to receive updates on that whenever relevant state changes. First, let's see how state changes happen. We still have regular old `++poke` arms, let's use that to prompt our application to change its state.
180−
181−```
182−++ poke-loob :> regular old poke
183− |= inc/?
184− ^- (list delta)
185− :_ ~
186− ?: inc [%increment ~]
187− [%decrement ~]
188−::
189−++ bake :> apply delta to state
190− |= del/delta
191− ^- (quip opera +>)
192− :- ~
193− ?- -.del
194− $increment +>(num +(num))
195− $decrement +>(num (dec num))
196− ==
197−```
198−
199−`delta`s get redirected into `++bake` so that our state can get changed as described. After this happens the same `delta`s get, for each active query, routed into `++feel`. That then figures out what the `rumor` relevant to the query is, if applicable.
200−
201−```
202−++ feel :> delta to rumor
203− |= {qer/query del/delta}
204− ^- (unit rumor)
205− ?- -.qer
206− $number
207− `[%number del]
208− ::
209− $mul-of
210− :: since we only want to send a rumor if result
211− :: changed, we need to deduce the old state from
212− :: the current state and the delta. depends on the
213− :: fact that state changes before ++feel. funky!
214− :: we could, of course, store mul/? in state, and
215− :: make a delta for it, but should we need to?
216− =/ old
217− .= 0
218− %+ mod
219− ?- -.del
220− $increment (dec num)
221− $decrement +(num)
222− ==
223− mul.qer
224− =/ new =(0 (mod num mul.qer))
225− ?: =(old new) ~
226− `[%mul-of new]
227− ==
228−```
229−
230−As we saw earlier, for `/number` queries the `delta`s match one-on-one with the relevant `rumor`s. For `/mul-of` queries we do a little bit of work to see if anything actually changed. No need to send a `rumor` if it hasn't.
231−
232−
233−## Criticism
234−
235−- Where event arms currently get passed a `wire`, and the new Gall described above passes them a custom `query` structure, the original new Gall spec gave them `(list coin)`, a "pre-parsed wire". These structures (eg `[%$ p=[p=~.ud q=123]]`) are uncomfortable to work with. Even with a "coin list parsing library" it still doesn't feel ideal. Because of custom structures being easier to work with than lists of `++knot`s or `++coin`s, writing a `++path-to-query` arm by hand is a small cost for huge gains.
236−
237−- Why do `prize` units mean what they do? One would expect `~` to mean "invalid" and `[~ ~]` to mean "unavailable" as opposed to the other way around.
238−
239−- The original new Gall spec mentions output lists (like `(list delta)` etc.) to be in reverse order. This was done because adding to the head of a list (`[item list]`) is easier than appending to the tail of a list (`(weld list [item ~])` or other). While it's technically easier to produce a list in reverse order, semantically it's yet another thing to keep in mind. Luckily, most of the "add to x, produce all of it later" code is set-and-forget, so probably not a huge deal. But do we really fear a few stray `++flop`s that much?
240−
241−- There's some weirdness with relation to relying on old state in `++feel` to determine whether a query result actually changed. Just relying on state in general for delta-to-rumor conversion may or may not violate the new Gall spec.
242−
243−- The original new Gall spec specifies `++leak` as taking a `(unit (set ship))`, where `~` means public. Is there a use case for checking more than just a single ship?
244−
245−- Gall should probably cache `++feel` results during a single pass, to avoid the cycles of generating what it can be certain of is the same `(unit rumor)`. (But then for eg `/circle/nom/13` and `/circle/nom/14` it would still recalculate. Better than nothing.)
246−
247−## Further reading
248−
249−- [Original new-Gall spec by ~sorreg-namtyv](spec)
250−- [A new-Gall example app](example)
learn/arvo/arvo-internals/hall/new-gall/example.udondeleted−97
@@ -1,97 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− sort/'2'
4− title/'A new-Gall example app'
5− ==
6−;>
7−
8−# A new-Gall example app
9−
10−```
11−:: counter app
12−:: new gall example, may or may not compile.
13−::
14−|%
15−++ query :> valid queries
16− $% {$number $~} :< current number
17− {$mul-of val/@ud} :< is num multiple of?
18− == ::
19−++ prize :> query results
20− $% {$number num/@ud} :< /number
21− {$mul-of mul/?} :< /mul-of
22− == ::
23−++ rumor :> query result changes
24− $% {$number delta} :< /number
25− {$mul-of mul/?} ::TODO or just flip? :< /mul-of
26− == ::
27−:: the above would ordinarily be placed in sur/, ::
28−:: since other apps might want to use it. ::
29−++ brain {num/@ud $~} :< application state
30−++ delta :> state change
31− $% {$increment $~} :< +1
32− {$decrement $~} :< -1
33− == ::
34−--
35−::
36−|_ {bol/bowl brain}
37−::
38−++ leak :> read permission
39− |= {who/ship qer/query}
40− ^- ?
41− & :: everyone's allowed
42−::
43−++ peek :> synchronous read
44− |= qer/query
45− ^- (unit (unit prize))
46− ?- -.qer
47− $number ``[%number num]
48− $mul-of ?: =(0 mul.qer) [~ ~]
49− ``[%mul-of =(0 (mod num mul.qer))]
50− ==
51−::
52−++ poke-loob :> regular old poke
53− |= inc/?
54− ^- (list delta)
55− :_ ~
56− ?: inc [%increment ~]
57− [%decrement ~]
58−::
59−++ bake :> apply delta to state
60− |= del/delta
61− ^- (quip opera +>)
62− :- ~
63− ?- -.del
64− $increment +>(num +(num))
65− $decrement +>(num (dec num))
66− ==
67−::
68−++ feel :> delta to rumor
69− |= {qer/query del/delta}
70− ^- (unit rumor)
71− ?- -.qer
72− $number
73− `[%number del]
74− ::
75− $mul-of
76− :: since we only want to send a rumor if result
77− :: changed, we need to deduce the old state from
78− :: the current state and the delta. depends on the
79− :: fact that state changes before ++feel. funky!
80− :: we could, of course, store mul/? in state, and
81− :: make a delta for it, but should we need to?
82− =/ old
83− .= 0
84− %+ mod
85− ?- -.del
86− $increment (dec num)
87− $decrement +(num)
88− ==
89− mul.qer
90− =/ new =(0 (mod num mul.qer))
91− ?: =(old new) ~
92− `[%mul-of new]
93− ==
94−::
95−:: not pictured: ++path-to-query
96−--
97−```
learn/arvo/arvo-internals/hall/new-gall/spec.udondeleted−163
@@ -1,163 +0,0 @@
1−:- :~ navhome/'/docs/'
2− navuptwo/'true'
3− next/'true'
4− sort/'1'
5− title/'The original new-Gall spec'
6− ==
7−;>
8−
9−# The original new-Gall spec
10−
11−`~sorreg-namtyv`
12−
13−```
14−=> |%
15− --
16−|* $: :> vinyl: historical state (including version)
17− :> brain: working state of the application (not including version)
18− :> delta: grain of change across all state
19− :> prize: (pair mark noun) for namespace value
20− :> rumor: (pair mark noun) for namespace diff
21− :> opera: (pair bone card) for operation (old ++move)
22− :>
23− vinyl/mold
24− brain/mold
25− delta/mold
26− prize/mold
27− rumor/mold
28− opera/mold
29− ==
30−|_ $: :> ops: pending operations, in reverse order
31− :> ego: current state
32− :>
33− ops/(list opera)
34− ego/brain
35− ==
36−:: :: ++bake
37−++ bake :< apply delta
38− |= $: :> del: change
39− :>
40− del/delta
41− ==
42− :> core after change (including operations)
43− ^- _+>
44− !!
45−:: :: ++cope
46−++ cope :< transaction result
47− |= $: :> weg: forward identity
48− :> het: success or error report
49− :>
50− weg/(list coin)
51− het/(unit tang)
52− ==
53− :> actions in reverse order
54− :>
55− ^- (list delta)
56− !!
57−:: :: ++fail
58−++ fail :< process error
59− |= $: :> why: error dump
60− :>
61− why/tang
62− ==
63− :> actions in reverse order
64− :>
65− ^- (list delta)
66− !!
67−:: :: ++feel
68−++ feel :< update
69− |= $: :> del: change
70− :> pex: preparsed path, inside-first
71− :>
72− del/delta
73− pex/(list coin)
74− ==
75− :> query updates in reverse order
76− :>
77− ^- (list rumor)
78− !!
79−:: :: ++hear
80−++ hear :< subscription update
81− |= $: :> weg: forward identity
82− :>
83− weg/(list coin)
84− ==
85− :> actions in reverse order
86− :>
87− ^- (list delta)
88− !!
89−:: :: ++pull
90−++ pull :< subscription cancel
91− |= $: :> weg: forward identity
92− :> het: error report, if any
93− :>
94− weg/(list coin)
95− het/(unit tang)
96− ==
97− :> actions in reverse order
98− :>
99− ^- (list delta)
100− !!
101−:: :: ++leak
102−++ leak :< check access
103− |= $: :> lec: leakset (~ means public)
104− :> pex: preparsed path, inside-first
105− :>
106− lec/(unit (set ship))
107− pex/(list coin)
108− ==
109− :> if path `pex` is visible to ships in `lec`
110− ^- ?
111− !!
112−:: :: ++load
113−++ look :< asynchronous read
114− |= $: :> pex: preparsed path, inside-first
115− :>
116− pex/(list coin)
117− ==
118− :> actions in reverse order
119− ^- _+>
120− !!
121−:: :: ++prep
122−++ prep :< load system
123− |= $: old/vinyl
124− ==
125− :> core after boot
126− ^- _+>
127− !!
128−:: :: ++peek
129−++ peek :< synchronous read
130− |= $: :> pex: preparsed path, inside-first
131− :>
132− pex/(list coin)
133− ==
134− :> value at `pec`; ~ for unavailable, [~ ~] for invalid
135− :>
136− ^- (unit (unit prize))
137− !!
138−:: :: ++poke
139−++ poke :< generic poke
140− |= $: :> ost: opaque cause
141− :> msg: message with mark and vase
142− :>
143− ost/bone
144− msg/cage
145− ==
146− :> actions in reverse order
147− :>
148− ^- (list delta)
149− !!
150−:: :: ++pour
151−++ pour :< arvo response
152− |= $: :> weg: forward identity
153− :> sin: response card
154− :>
155− weg/(list coin)
156− sin/sign
157− ==
158− :> actions in reverse order
159− :>
160− ^- (list delta)
161− !!
162−--
163−```
learn/arvo/arvo-internals/udon.udon+297−7
@@ -5,9 +5,21 @@
55 ==
66;>
77
8−# Udon: A Guide
8+# Udon
99
10−### What is Udon?
10+## Table of Contents
11+
12+- #### [Udon: A Guide](#guide)
13+
14+- #### [A Simple Udon Blog](#blog)
15+
16+- #### [A Static Site](#static)
17+
18+;=
19+ ;h2
20+ ;div(id "guide"): Udon: A Guide
21+ ==
22+==
1123
1224Udon is a way to write content for the web. It's a minimalist
1325markup language for creating and rendering text documents, with a
@@ -30,7 +42,6 @@ Markdown: some syntax errors will prevent the file from being parsed at all.
3042We provide a few simple examples [here](#examples) of how to publish
3143Udon files using our web interface.
3244
33−
3445### Getting Started
3546
3647Before starting, make sure that your urbit is
@@ -616,11 +627,290 @@ Produces:
616627 ;small: [reactive publishing intensifies]
617628 ==
618629==
619−;h2
620− ;div(id "examples"): Examples
630+
631+
632+;=
633+ ;h2
634+ ;div(id "blog"): A Simple Udon Blog
635+ ==
621636==
622637
623−We've created a few simple examples of how to get set up publishing content from
624−your Urbit. Feel free to ask questions in the comments.
638+Publishing using Udon is really easy. It uses the file extension `.udon`. Here we'll create a very simple blog and publish our first posts.
639+
640+First, let's setup a desk to serve our posts from:
641+
642+```
643+|merge %site ~your-urbit %home
644+```
645+
646+Then let's mount that desk to unix:
647+
648+```
649+|mount /=site=
650+```
651+
652+You should now be able to find a `/site` folder inside of your pier
653+directory (either `comet/` or `your-urbit/`).
654+
655+To begin serving files from this new desk use `|serve`:
656+
657+```
658+|serve %site
659+```
660+
661+First let's create the landing page for our blog. Create the file
662+`site/web/blog.udon`:
663+
664+```
665+:- :~ anchor/'none'
666+ ==
667+;>
668+
669+# Hello
670+
671+This is a simple blog I built on Urbit.
672+
673+;list(dataType "post");
674+```
675+
676+Try viewing this file at `http://localhost:8080`. Note that `8080` might be
677+`8081`, `8082`, and so on, depending if those ports were being used when you
678+started your urbit.
679+
680+The only special thing about this page is the `anchor/'none'` front-matter
681+which simply turns off the Tree navigation. Normally Tree gives navigation
682+controls for walking around the filesystem, but taking them away makes
683+the page seem more like a landing page.
684+
685+The page looks pretty boring now. Let's add our first post. From
686+unix run `mkdir your-urbit/site/web/blog; touch
687+your-urbit/site/web/blog/post-1.udon`. (Currently [there's a
688+bug](https://github.com/urbit/urbit/issues/321) that prevents empty
689+directories from getting created, so we have to `touch` a file inside
690+them first.) In `blog/post-1.udon` let's add some filler content:
691+
692+```
693+:- :~ navhome/'/blog'
694+ type/'post'
695+ date/'~2016.6.20'
696+ title/'My first post!'
697+ ==
698+;>
699+
700+Is this a decentralized Medium? Let's find out.
701+
702+But first, how about a long quote from Paramenides:
703+
704+> True, he said; and therefore when ideas are what they are in
705+ relation to one another, their essence is determined by a relation
706+ among themselves, and has nothing to do with the resemblances, or
707+ whatever they are to be termed, which are in our sphere, and from
708+ which we receive this or that name when we partake of them. And
709+ the things which are within our sphere and have the same names
710+ with them, are likewise only relative to one another, and not to
711+ the ideas which have the same names with them, but belong to
712+ themselves and not to them.
713+
714+Good to get that out of the way.
715+```
716+
717+You should be able to view this file at:
718+`http://localhost:8080/blog/post-1.udon`.
719+
720+You'll also notice that
721+now the list of posts here: `http://localhost:8080/blog` has
722+updated.
723+
724+Here we use two pieces of front-matter worth noting: `type` and `navhome`.
725+
726+- `type` implies that the page has some special handling by Tree. When `type` is
727+ `post` we automatically put in the `date`, `title` and `author` when they're
728+ specified and add some styles.
729+
730+- `navhome` sets the path used by the home button (the circle in the top left).
731+ Since we want to send people back to the root of our blog, we set this to `/blog`
732+
733+Adding posts is as easy as dropping Udon files into the `blog/`
734+directory. Pretty easy!
735+
736+### Blog comments
737+
738+Now let's enable comments on a blog post.
739+
740+First, turn comments on by editing the frontmatter in `post-1.udon`. Your
741+frontmatter should look like this:
742+
743+```
744+:- :~ navhome/'/blog'
745+ type/'post'
746+ date/'~2018.6.20'
747+ title/'Blog comments'
748+ comments/'true'
749+ ==
750+;>
751+```
752+
753+Now try loading your post here: `your-urbit.urbit.org/blog/post-1`.
754+You should see a comments box at the bottom of the page.
755+
756+Try posting a comment! When you do you should see the following in
757+your console:
758+
759+```
760++ /~your-urbit/home/55/web/blog/post-1/comments/~2016.6.20..23.20.54..0b88/md
761+------------[0]
762+~your-urbit[tree]: receiving comments, ;join %comments for details
763+```
764+
765+Comments are written into the filesystem in the `comments/` folder
766+relative to the page they're enabled on. When a new comment is posted
767+a notification is also posted to the `/comments` `:talk` channel.
768+
769+Use `;join` to keep up with comments as they get posted:
770+
771+```
772+;join ~your-urbit/comments
773+```
774+
775+That's it! Easy.
776+
777+;=
778+ ;h2
779+ ;div(id "static"): A Static Site
780+ ==
781+==
782+
783+Hosting a static tree of content is easy. Let's put together a really
784+simple site for an imaginary Urbit meetup group.
785+
786+We assume you have at least followed the beginning of [our first
787+examples](#blog) and created a desk called `site` and mounted it to
788+unix.
789+
790+Note: below we use Urbit's implementation of Markdown, [Udon](#udon).
791+This markup language allows you to use snippets of Hoon code but not HTML.
792+In particular, we use Sail, a subset of Hoon. This Sail is rendered as HTML
793+when the file is served to a client. To learn about Sail, head over to
794+the [Sail](/docs/learn/arvo/arvo-internals/sail) section of the docs.
795+
796+In `site/web/meet.udon` put:
797+
798+```
799+:- :~ navhome/'/meet'
800+ navdpad/'false'
801+ navpath/'/meet'
802+ mavmode/'navbar'
803+ ==
804+;>
805+
806+# Neo-Tokyo Urbit meetup
807+
808+;img@"https://ofheroesandcliches.files.wordpress.com/2014/06/neo-tokyo.png"(width "100%");
809+
810+Hi there! We meet once a week at The Chat to work on Urbit projects
811+together.
812+
813+You can find out more about the group on the [about](about) page and
814+follow our projects in [projects](projects).
815+```
816+
817+This is our landing page. Here we're using a few new bits of frontmatter:
818+`navdpad`, `navmode` and `navpath`. `navdpad` just turns off the nav
819+arrows. `navmode` can be set to 'navbar' to switch to a horizontal top
820+nav instead of a left bar. `navpath` sets the path to load the nav
821+items from.
822+
823+Let's create `about.udon` and `projects.udon`. From Unix use the
824+technique from before to create a new directory: `mkdir
825+your-urbit/site/web/meet/; touch your-urbit/site/web/meet/about.udon`.
826+Then put the following in `site/web/about.udon`:
827+
828+```
829+:- :~ navhome/'/meet'
830+ navdpad/'false'
831+ navpath/'/meet'
832+ mavmode/'navbar'
833+ title/'About'
834+ ==
835+;>
836+
837+# About
838+
839+## Mission statement
840+
841+The existing framework cannot subdue the new human force that is increasing day
842+by day alongside the irresistible development of technology and the
843+dissatisfaction of its possible uses in our senseless social life.
844+
845+## Members
846+
847+Membership is open to anyone. Just send a message to `~talsur-todres`.
848+
849+- Shōtarō Kaneda
850+- Motoko Kusanagi
851+- Ishikawa
852+- Faye Valentine
853+- Spike Spiegel
854+```
855+
856+And `site/web/projects.udon`:
857+
858+```
859+:- :~ navhome/'/meet'
860+ navdpad/'false'
861+ navpath/'/meet'
862+ mavmode/'navbar'
863+ title/'Projects'
864+ ==
865+;>
866+
867+# Projects
868+
869+## Active
625870
626871;list;
872+
873+## Discussion
874+
875+;div(class "mini-module")
876+ ;script(src "/~/at/lib/js/urb.js");
877+ ;script(src "https://cdn.rawgit.com/seatgeek/react-infinite/0.8.0/dist/react-infinite.js");
878+ ;script(src "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.2/moment-with-locales.js");
879+ ;script(src "https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.1/moment-timezone.js");
880+ ;script(src "/talk/main.js");
881+ ;link(href "/talk/main.css", rel "stylesheet");
882+ ;talk(readonly "", chrono="reverse", station="comments");
883+==
884+```
885+
886+This page introduces a new thing: the `:talk` module. Inside of the
887+`mini-module` div we load the scripts needed by the `;talk`
888+component. The `;talk` component is a static component for
889+displaying a feed from a talk channel inline. Here we're going to
890+display the discussion from our active projects inline.
891+
892+We'll need a few active projects though. From unix: `mkdir
893+your-urbit/site/web/meet/projects; touch
894+your-urbit/site/web/meet/projects/bike.udon`.
895+
896+In `site/web/meet/projects/bike.udon`:
897+
898+```
899+:- :~ navhome/'/meet'
900+ navdpad/'false'
901+ navpath/'/meet'
902+ mavmode/'navbar'
903+ title/'Kaneda's Bike'
904+ comments/'true'
905+ ==
906+;>
907+
908+# Urbit on a Motorcycle
909+
910+Discussion on getting urbit to power Kaneda's motorcycle.
911+```
912+
913+Here we just use the `comments` frontmatter to enable comments on the page.
914+Adding other imaginary projects is left to the reader.
915+
916+Building a static site takes only a few minutes and a few Udon files. Have fun!
learn/arvo/arvo-internals/udon/blog.udondeleted−109
@@ -1,109 +0,0 @@
1−:- :~ navhome/'/docs/'
2− next/'true'
3− sort/'1'
4− title/'A simple blog'
5− ==
6−;>
7−
8−# A simple blog
9−
10−[Udon](../../tutorials/udon) (file extension `.udon`) is our markup
11−language that is able to run Hoon code. Publishing using Udon is really easy. It
12−uses the file extension `.udon`. Here we'll create a very simple blog and publish
13−our first posts.
14−
15−First, let's setup a desk to serve our posts from:
16−
17−```
18−|merge %site ~your-urbit %home
19−```
20−
21−Then let's mount that desk to unix:
22−
23−```
24−|mount /=site=
25−```
26−
27−You should now be able to find a `/site` folder inside of your pier
28−directory (either `comet/` or `your-urbit/`).
29−
30−To begin serving files from this new desk use `|serve`:
31−
32−```
33−|serve %site
34−```
35−
36−First let's create the landing page for our blog. Create the file
37−`site/web/blog.udon`:
38−
39−```
40−:- :~ anchor/'none'
41− ==
42−;>
43−
44−# Hello
45−
46−This is a simple blog I built on Urbit.
47−
48−;list(dataType "post");
49−```
50−
51−Try viewing this file at `http://localhost:8080`. Note that `8080` might be
52−`8081`, `8082`, and so on, depending if those ports were being used when you
53−started your urbit.
54−
55−The only special thing about this page is the `anchor/'none'` front-matter
56−which simply turns off the Tree navigation. Normally Tree gives navigation
57−controls for walking around the filesystem, but taking them away makes
58−the page seem more like a landing page.
59−
60−The page looks pretty boring now. Let's add our first post. From
61−unix run `mkdir your-urbit/site/web/blog; touch
62−your-urbit/site/web/blog/post-1.udon`. (Currently [there's a
63−bug](https://github.com/urbit/urbit/issues/321) that prevents empty
64−directories from getting created, so we have to `touch` a file inside
65−them first.) In `blog/post-1.udon` let's add some filler content:
66−
67−```
68−:- :~ navhome/'/blog'
69− type/'post'
70− date/'~2016.6.20'
71− title/'My first post!'
72− ==
73−;>
74−
75−Is this a decentralized Medium? Let's find out.
76−
77−But first, how about a long quote from Paramenides:
78−
79−> True, he said; and therefore when ideas are what they are in
80− relation to one another, their essence is determined by a relation
81− among themselves, and has nothing to do with the resemblances, or
82− whatever they are to be termed, which are in our sphere, and from
83− which we receive this or that name when we partake of them. And
84− the things which are within our sphere and have the same names
85− with them, are likewise only relative to one another, and not to
86− the ideas which have the same names with them, but belong to
87− themselves and not to them.
88−
89−Good to get that out of the way.
90−```
91−
92−You should be able to view this file at:
93−`http://localhost:8080/blog/post-1.udon`.
94−
95−You'll also notice that
96−now the list of posts here: `http://localhost:8080/blog` has
97−updated.
98−
99−Here we use two pieces of front-matter worth noting: `type` and `navhome`.
100−
101−- `type` implies that the page has some special handling by Tree. When `type` is
102− `post` we automatically put in the `date`, `title` and `author` when they're
103− specified and add some styles.
104−
105−- `navhome` sets the path used by the home button (the circle in the top left).
106− Since we want to send people back to the root of our blog, we set this to `/blog`
107−
108−Adding posts is as easy as dropping Udon files into the `blog/`
109−directory. Pretty easy!
learn/arvo/arvo-internals/udon/comments.udondeleted−49
@@ -1,49 +0,0 @@
1−:- :~ navhome/'/docs/'
2− next/'true'
3− sort/'2'
4− title/'Blog comments'
5− ==
6−;>
7−
8−# Blog comments
9−
10−If you followed [our previous example](../blog) you should have a
11−simple blog accessible at `your-urbit.urbit.org/blog`. Here we'll
12−enable comments on a post.
13−
14−First, turn comments on by editing the frontmatter in `post-1.udon`. Your
15−frontmatter should look like this:
16−
17−```
18−:- :~ navhome/'/blog'
19− type/'post'
20− date/'~2018.6.20'
21− title/'Blog comments'
22− comments/'true'
23− ==
24−;>
25−```
26−
27−Now try loading your post here: `your-urbit.urbit.org/blog/post-1`.
28−You should see a comments box at the bottom of the page.
29−
30−Try posting a comment! When you do you should see the following in
31−your console:
32−
33−```
34−+ /~your-urbit/home/55/web/blog/post-1/comments/~2016.6.20..23.20.54..0b88/md
35−------------[0]
36−~your-urbit[tree]: receiving comments, ;join %comments for details
37−```
38−
39−Comments are written into the filesystem in the `comments/` folder
40−relative to the page they're enabled on. When a new comment is posted
41−a notification is also posted to the `/comments` `:talk` channel.
42−
43−Use `;join` to keep up with comments as they get posted:
44−
45−```
46−;join ~your-urbit/comments
47−```
48−
49−That's it! Easy.
learn/arvo/arvo-internals/udon/static.udondeleted−142
@@ -1,142 +0,0 @@
1−:- :~ navhome/'/docs/'
2− sort/'3'
3− title/'A static site'
4− ==
5−;>
6−
7−# A static site
8−
9−Hosting a static tree of content is easy. Let's put together a really
10−simple site for an imaginary Urbit meetup group.
11−
12−We assume you have at least followed the beginning of [our first
13−examples](/../blog) and created a desk called `site` and mounted it to
14−unix.
15−
16−Note: below we use Urbit's implementation of Markdown, [Udon](/docs/tutorials/udon).
17−This markup language allows you to use snippets of Hoon code but not HTML.
18−In particular, we use Sail, a subset of Hoon. This Sail is rendered as HTML
19−when the file is served to a client. To learn about Udon and Sail, head over to
20−the [Tutorial](/docs/tutorials) section of the docs.
21−
22−In `site/web/meet.udon` put:
23−
24−```
25−:- :~ navhome/'/meet'
26− navdpad/'false'
27− navpath/'/meet'
28− mavmode/'navbar'
29− ==
30−;>
31−
32−# Neo-Tokyo Urbit meetup
33−
34−;img@"https://ofheroesandcliches.files.wordpress.com/2014/06/neo-tokyo.png"(width "100%");
35−
36−Hi there! We meet once a week at The Chat to work on Urbit projects
37−together.
38−
39−You can find out more about the group on the [about](about) page and
40−follow our projects in [projects](projects).
41−```
42−
43−This is our landing page. Here we're using a few new bits of frontmatter:
44−`navdpad`, `navmode` and `navpath`. `navdpad` just turns off the nav
45−arrows. `navmode` can be set to 'navbar' to switch to a horizontal top
46−nav instead of a left bar. `navpath` sets the path to load the nav
47−items from.
48−
49−Let's create `about.udon` and `projects.udon`. From Unix use the
50−technique from before to create a new directory: `mkdir
51−your-urbit/site/web/meet/; touch your-urbit/site/web/meet/about.udon`.
52−Then put the following in `site/web/about.udon`:
53−
54−```
55−:- :~ navhome/'/meet'
56− navdpad/'false'
57− navpath/'/meet'
58− mavmode/'navbar'
59− title/'About'
60− ==
61−;>
62−
63−# About
64−
65−## Mission statement
66−
67−The existing framework cannot subdue the new human force that is increasing day
68−by day alongside the irresistible development of technology and the
69−dissatisfaction of its possible uses in our senseless social life.
70−
71−## Members
72−
73−Membership is open to anyone. Just send a message to `~talsur-todres`.
74−
75−- Shōtarō Kaneda
76−- Motoko Kusanagi
77−- Ishikawa
78−- Faye Valentine
79−- Spike Spiegel
80−```
81−
82−And `site/web/projects.udon`:
83−
84−```
85−:- :~ navhome/'/meet'
86− navdpad/'false'
87− navpath/'/meet'
88− mavmode/'navbar'
89− title/'Projects'
90− ==
91−;>
92−
93−# Projects
94−
95−## Active
96−
97−;list;
98−
99−## Discussion
100−
101−;div(class "mini-module")
102− ;script(src "/~/at/lib/js/urb.js");
103− ;script(src "https://cdn.rawgit.com/seatgeek/react-infinite/0.8.0/dist/react-infinite.js");
104− ;script(src "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.2/moment-with-locales.js");
105− ;script(src "https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.1/moment-timezone.js");
106− ;script(src "/talk/main.js");
107− ;link(href "/talk/main.css", rel "stylesheet");
108− ;talk(readonly "", chrono="reverse", station="comments");
109−==
110−```
111−
112−This page introduces a new thing: the `:talk` module. Inside of the
113−`mini-module` div we load the scripts needed by the `;talk`
114−component. The `;talk` component is a static component for
115−displaying a feed from a talk channel inline. Here we're going to
116−display the discussion from our active projects inline.
117−
118−We'll need a few active projects though. From unix: `mkdir
119−your-urbit/site/web/meet/projects; touch
120−your-urbit/site/web/meet/projects/bike.udon`.
121−
122−In `site/web/meet/projects/bike.udon`:
123−
124−```
125−:- :~ navhome/'/meet'
126− navdpad/'false'
127− navpath/'/meet'
128− mavmode/'navbar'
129− title/'Kaneda's Bike'
130− comments/'true'
131− ==
132−;>
133−
134−# Urbit on a Motorcycle
135−
136−Discussion on getting urbit to power Kaneda's motorcycle.
137−```
138−
139−Here we just use the `comments` frontmatter to enable comments on the page.
140−Adding other imaginary projects is left to the reader.
141−
142−Building a static site takes only a few minutes and a few Udon files. Have fun!
learn/arvo/nock/implementations.udon+2116−6

This diff is too big to show here.

learn/arvo/nock/implementations/c.udondeleted−212

This diff is too big to show here.

learn/arvo/nock/implementations/clojure.udondeleted−125

This diff is too big to show here.

learn/arvo/nock/implementations/csharp.udondeleted−478

This diff is too big to show here.

learn/arvo/nock/implementations/groovy.udondeleted−206

This diff is too big to show here.

learn/arvo/nock/implementations/haskell.udondeleted−63

This diff is too big to show here.

learn/arvo/nock/implementations/hoon.udondeleted−55

This diff is too big to show here.

learn/arvo/nock/implementations/javascript.udondeleted−365

This diff is too big to show here.

learn/arvo/nock/implementations/python.udondeleted−95

This diff is too big to show here.

learn/arvo/nock/implementations/ruby.udondeleted−139

This diff is too big to show here.

learn/arvo/nock/implementations/scala.udondeleted−88

This diff is too big to show here.

learn/arvo/nock/implementations/scheme.udondeleted−128

This diff is too big to show here.

learn/arvo/nock/implementations/swift.udondeleted−366

This diff is too big to show here.

learn/arvo/style.udonnew file+489

This diff is too big to show here.

learn/arvo/vere/jetting.udon+6−11

This diff is too big to show here.

reference/glossary.udon+33−33

This diff is too big to show here.

reference/hoon-expressions/rune/bar.udon+664−1

This diff is too big to show here.

reference/hoon-expressions/rune/bar/cab.udondeleted−96

This diff is too big to show here.

reference/hoon-expressions/rune/bar/cen.udondeleted−66

This diff is too big to show here.

reference/hoon-expressions/rune/bar/col.udondeleted−54

This diff is too big to show here.

reference/hoon-expressions/rune/bar/dot.udondeleted−74

This diff is too big to show here.

reference/hoon-expressions/rune/bar/hep.udondeleted−62

This diff is too big to show here.

reference/hoon-expressions/rune/bar/ket.udondeleted−65

This diff is too big to show here.

reference/hoon-expressions/rune/bar/sig.udondeleted−45

This diff is too big to show here.

reference/hoon-expressions/rune/bar/tar.udondeleted−72

This diff is too big to show here.

reference/hoon-expressions/rune/bar/tis.udondeleted−66

This diff is too big to show here.

reference/hoon-expressions/rune/bar/vat.udondeleted−39

This diff is too big to show here.

reference/hoon-expressions/rune/bar/wut.udondeleted−48

This diff is too big to show here.

reference/hoon-expressions/rune/bus.udon+397−1

This diff is too big to show here.

reference/hoon-expressions/rune/bus/base.udondeleted−23

This diff is too big to show here.

reference/hoon-expressions/rune/bus/cab.udondeleted−42

This diff is too big to show here.

reference/hoon-expressions/rune/bus/cen.udondeleted−37

This diff is too big to show here.

reference/hoon-expressions/rune/bus/col.udondeleted−40

This diff is too big to show here.

reference/hoon-expressions/rune/bus/hep.udondeleted−34

This diff is too big to show here.

reference/hoon-expressions/rune/bus/ket.udondeleted−40

This diff is too big to show here.

reference/hoon-expressions/rune/bus/sig.udondeleted−69

This diff is too big to show here.

reference/hoon-expressions/rune/bus/tis.udondeleted−41

This diff is too big to show here.

reference/hoon-expressions/rune/bus/vat.udondeleted−43

This diff is too big to show here.

reference/hoon-expressions/rune/bus/wut.udondeleted−48

This diff is too big to show here.

reference/hoon-expressions/rune/cen.udon+495−1

This diff is too big to show here.

reference/hoon-expressions/rune/cen/cab.udondeleted−69

This diff is too big to show here.

reference/hoon-expressions/rune/cen/col.udondeleted−60

This diff is too big to show here.

reference/hoon-expressions/rune/cen/dot.udondeleted−47

This diff is too big to show here.

reference/hoon-expressions/rune/cen/hep.udondeleted−55

This diff is too big to show here.

reference/hoon-expressions/rune/cen/ket.udondeleted−41

This diff is too big to show here.

reference/hoon-expressions/rune/cen/lus.udondeleted−43

This diff is too big to show here.

reference/hoon-expressions/rune/cen/sig.udondeleted−58

This diff is too big to show here.

reference/hoon-expressions/rune/cen/tar.udondeleted−69

This diff is too big to show here.

reference/hoon-expressions/rune/cen/tis.udondeleted−73

This diff is too big to show here.

reference/hoon-expressions/rune/col.udon+263−1

This diff is too big to show here.

reference/hoon-expressions/rune/col/cab.udondeleted−27

This diff is too big to show here.

reference/hoon-expressions/rune/col/col.udondeleted−25

This diff is too big to show here.

reference/hoon-expressions/rune/col/hep.udondeleted−54

This diff is too big to show here.

reference/hoon-expressions/rune/col/ket.udondeleted−33

This diff is too big to show here.

reference/hoon-expressions/rune/col/lus.udondeleted−32

This diff is too big to show here.

reference/hoon-expressions/rune/col/sig.udondeleted−50

This diff is too big to show here.

reference/hoon-expressions/rune/col/tar.udondeleted−56

This diff is too big to show here.

reference/hoon-expressions/rune/constants.udon+197−1

This diff is too big to show here.

reference/hoon-expressions/rune/constants/cold.udondeleted−41

This diff is too big to show here.

reference/hoon-expressions/rune/constants/path.udondeleted−35

This diff is too big to show here.

reference/hoon-expressions/rune/constants/text.udondeleted−54

This diff is too big to show here.

reference/hoon-expressions/rune/constants/warm.udondeleted−76

This diff is too big to show here.

reference/hoon-expressions/rune/dot.udon+233−1

This diff is too big to show here.

reference/hoon-expressions/rune/dot/ket.udondeleted−80

This diff is too big to show here.

reference/hoon-expressions/rune/dot/lus.udondeleted−36

This diff is too big to show here.

reference/hoon-expressions/rune/dot/tar.udondeleted−49

This diff is too big to show here.

reference/hoon-expressions/rune/dot/tis.udondeleted−50

This diff is too big to show here.

reference/hoon-expressions/rune/dot/wut.udondeleted−28

This diff is too big to show here.

reference/hoon-expressions/rune/ket.udon+414−3

This diff is too big to show here.

reference/hoon-expressions/rune/ket/bar.udondeleted−42

This diff is too big to show here.

reference/hoon-expressions/rune/ket/col.udondeleted−42

This diff is too big to show here.

reference/hoon-expressions/rune/ket/dot.udondeleted−47

This diff is too big to show here.

reference/hoon-expressions/rune/ket/hep.udondeleted−50

This diff is too big to show here.

reference/hoon-expressions/rune/ket/lus.udondeleted−25

This diff is too big to show here.

reference/hoon-expressions/rune/ket/pad.udondeleted−59

This diff is too big to show here.

reference/hoon-expressions/rune/ket/sig.udondeleted−28

This diff is too big to show here.

reference/hoon-expressions/rune/ket/tar.udondeleted−57

This diff is too big to show here.

reference/hoon-expressions/rune/ket/tis.udondeleted−42

This diff is too big to show here.

reference/hoon-expressions/rune/ket/wut.udondeleted−41

This diff is too big to show here.

reference/hoon-expressions/rune/lus.udon+178−1

This diff is too big to show here.

reference/hoon-expressions/rune/lus/bar.udondeleted−54

This diff is too big to show here.

reference/hoon-expressions/rune/lus/bus.udondeleted−44

This diff is too big to show here.

reference/hoon-expressions/rune/lus/lus.udondeleted−41

This diff is too big to show here.

reference/hoon-expressions/rune/lus/tar.udondeleted−47

This diff is too big to show here.

reference/hoon-expressions/rune/mic.udon+393−2

This diff is too big to show here.

reference/hoon-expressions/rune/mic/col.udondeleted−56

This diff is too big to show here.

reference/hoon-expressions/rune/mic/lus.udondeleted−65

This diff is too big to show here.

reference/hoon-expressions/rune/mic/mic.udondeleted−48

This diff is too big to show here.

reference/hoon-expressions/rune/mic/net.udondeleted−23

This diff is too big to show here.

reference/hoon-expressions/rune/mic/sig.udondeleted−104

This diff is too big to show here.

reference/hoon-expressions/rune/mic/tar.udondeleted−58

This diff is too big to show here.

reference/hoon-expressions/rune/mic/tis.udondeleted−53

This diff is too big to show here.

reference/hoon-expressions/rune/sig.udon+488−1

This diff is too big to show here.

reference/hoon-expressions/rune/sig/ban.udondeleted−41

This diff is too big to show here.

reference/hoon-expressions/rune/sig/bar.udondeleted−35

This diff is too big to show here.

reference/hoon-expressions/rune/sig/bus.udondeleted−29

This diff is too big to show here.

reference/hoon-expressions/rune/sig/cab.udondeleted−35

This diff is too big to show here.

reference/hoon-expressions/rune/sig/cen.udondeleted−95

This diff is too big to show here.

reference/hoon-expressions/rune/sig/led.udondeleted−35

This diff is too big to show here.

reference/hoon-expressions/rune/sig/lus.udondeleted−46

This diff is too big to show here.

reference/hoon-expressions/rune/sig/net.udondeleted−33

This diff is too big to show here.

reference/hoon-expressions/rune/sig/pad.udondeleted−41

This diff is too big to show here.

reference/hoon-expressions/rune/sig/tis.udondeleted−38

This diff is too big to show here.

reference/hoon-expressions/rune/sig/wut.udondeleted−44

This diff is too big to show here.

reference/hoon-expressions/rune/sig/zap.udondeleted−38

This diff is too big to show here.

reference/hoon-expressions/rune/terminators.udon+77−1

This diff is too big to show here.

reference/hoon-expressions/rune/terminators/hephep.udondeleted−35

This diff is too big to show here.

reference/hoon-expressions/rune/terminators/tistis.udondeleted−47

This diff is too big to show here.

reference/hoon-expressions/rune/tis.udon+520−1

This diff is too big to show here.

reference/hoon-expressions/rune/tis/ban.udondeleted−28

This diff is too big to show here.

reference/hoon-expressions/rune/tis/bar.udondeleted−37

This diff is too big to show here.

reference/hoon-expressions/rune/tis/col.udondeleted−35

This diff is too big to show here.

reference/hoon-expressions/rune/tis/com.udondeleted−41

This diff is too big to show here.

reference/hoon-expressions/rune/tis/dot.udondeleted−42

This diff is too big to show here.

reference/hoon-expressions/rune/tis/hep.udondeleted−35

This diff is too big to show here.

reference/hoon-expressions/rune/tis/ket.udondeleted−46

This diff is too big to show here.

reference/hoon-expressions/rune/tis/led.udondeleted−43

This diff is too big to show here.

reference/hoon-expressions/rune/tis/lus.udondeleted−37

This diff is too big to show here.

reference/hoon-expressions/rune/tis/mic.udondeleted−35

This diff is too big to show here.

reference/hoon-expressions/rune/tis/net.udondeleted−55

This diff is too big to show here.

reference/hoon-expressions/rune/tis/sig.udondeleted−41

This diff is too big to show here.

reference/hoon-expressions/rune/tis/tar.udondeleted−39

This diff is too big to show here.

reference/hoon-expressions/rune/tis/wut.udondeleted−41

This diff is too big to show here.

reference/hoon-expressions/rune/wut.udon+578−5

This diff is too big to show here.

reference/hoon-expressions/rune/wut/ban.udondeleted−44

This diff is too big to show here.

reference/hoon-expressions/rune/wut/bar.udondeleted−45

This diff is too big to show here.

reference/hoon-expressions/rune/wut/col.udondeleted−54

This diff is too big to show here.

reference/hoon-expressions/rune/wut/dot.udondeleted−43

This diff is too big to show here.

reference/hoon-expressions/rune/wut/hep.udondeleted−68

This diff is too big to show here.

reference/hoon-expressions/rune/wut/ket.udondeleted−39

This diff is too big to show here.

reference/hoon-expressions/rune/wut/led.udondeleted−44

This diff is too big to show here.

reference/hoon-expressions/rune/wut/lus.udondeleted−63

This diff is too big to show here.

reference/hoon-expressions/rune/wut/pad.udondeleted−45

This diff is too big to show here.

reference/hoon-expressions/rune/wut/sig.udondeleted−33

This diff is too big to show here.

reference/hoon-expressions/rune/wut/tis.udondeleted−42

This diff is too big to show here.

reference/hoon-expressions/rune/wut/vat.udondeleted−38

This diff is too big to show here.

reference/hoon-expressions/rune/wut/zap.udondeleted−40

This diff is too big to show here.

reference/hoon-expressions/rune/zap.udon+219−1

This diff is too big to show here.

reference/hoon-expressions/rune/zap/ban.udondeleted−36

This diff is too big to show here.

reference/hoon-expressions/rune/zap/col.udondeleted−38

This diff is too big to show here.

reference/hoon-expressions/rune/zap/dot.udondeleted−50

This diff is too big to show here.

reference/hoon-expressions/rune/zap/tis.udondeleted−47

This diff is too big to show here.

reference/hoon-expressions/rune/zap/wut.udondeleted−31

This diff is too big to show here.

reference/hoon-expressions/rune/zap/zap.udondeleted−29

This diff is too big to show here.