on master help sign in
Merge branch 'master' into update-clay-for-dist
commit5a3442c37ca95fff73d5279de42ce3f83f9d22ca authortinnus-napbus <77721746+tinnus-napbus@users.noreply.github.com> dateTue 5 Oct 2021, 23:18 (5 years ago) parent19078e23bd0fc8
42 files changed+7245−396
components/Footer.js+1−1 components/Header.js+7 content/docs/arvo/ames/_index.md+20 content/docs/arvo/ames/ames-api.md−292 content/docs/arvo/ames/cryptography.md+3−3 content/docs/arvo/ames/data-types.md+389 content/docs/arvo/ames/scry.md+126 content/docs/arvo/ames/tasks.md+193 content/docs/arvo/clay/architecture.md+3−78 content/docs/arvo/clay/clay.md+4−1 content/docs/arvo/clay/marks/_index.md+23 content/docs/arvo/clay/marks/examples.md+248 content/docs/arvo/clay/marks/marks.md+59 content/docs/arvo/clay/marks/using-marks.md+240 content/docs/arvo/clay/marks/writing-marks.md+333 content/docs/hoon/reference/_index.md+6−3 content/docs/hoon/reference/rune/ket.md+12−3 content/docs/hoon/reference/zuse/2d_1-5.md+587 content/docs/hoon/reference/zuse/2d_6.md+1551 content/docs/hoon/reference/zuse/2d_7.md+1307 content/docs/hoon/reference/zuse/2e_2-3.md+67 content/docs/hoon/reference/zuse/_index.md+31 content/docs/hoon/reference/zuse/table-of-contents.md+247 content/docs/userspace/_index.md+3 content/docs/userspace/dist/_index.md+29 content/docs/userspace/dist/dist.md+105 content/docs/userspace/dist/docket.md+296 content/docs/userspace/dist/glob.md+102 content/docs/userspace/dist/guide.md+286 content/docs/userspace/dist/tools.md+342 content/getting-started/_index.md+9 content/getting-started/planet.md+1−1 content/grants/network-explorer-data-pipeline-http-api.md+2−2 content/grants/overhaul-the-urbitorg-website.md+2−2 content/grants/urbian-a-customized-linux-distribution-for-urbit-appliances.md+1−1 content/grants/urbit-event-series.md+1−1 content/using/_index.md+3−3 content/using/os/_index.md+1−1 content/using/os/getting-started.md → content/using/os/basics.md+1−1 lib/glossary.js+596 pages/using/[[...slug]].js+3−3 vercel.json+5
components/Footer.js+1−1
@@ -17,7 +17,7 @@ export default function Footer() {
1717 </Link>
1818 <Link href="/using">
1919 <div>
20− <a className="type-bold text-wall-500">Operator's Manual</a>
20+ <a className="type-bold text-wall-500">User's Manual</a>
2121 </div>
2222 </Link>
2323 <Link href="https://github.com/urbit/port/releases">
components/Header.js+7
@@ -72,6 +72,13 @@ export default function Header(props) {
7272 >
7373 Docs
7474 </ActiveLink>
75+ <ActiveLink
76+ currentPath={currentPath}
77+ className="mr-5 type-ui"
78+ href="/using"
79+ >
80+ Manual
81+ </ActiveLink>
7582 <ActiveLink
7683 currentPath={currentPath}
7784 className="mr-5 type-ui"
content/docs/arvo/ames/_index.md+20
@@ -5,3 +5,23 @@ sort_by = "weight"
55template = "sections/docs/chapters.html"
66insert_anchor_links = "right"
77+++
8+
9+## [Overview](/docs/arvo/ames/ames)
10+
11+An overview of Ames and its capabilities.
12+
13+## [Cryptography](/docs/arvo/ames/cryptography)
14+
15+A technical overview of how Ames implements cryptography.
16+
17+## [API Reference](/docs/arvo/ames/tasks)
18+
19+The `task`s Ames takes and the `gift`s it returns.
20+
21+## [Scry Reference](/docs/arvo/ames/scry)
22+
23+The scry endpoints of Ames.
24+
25+## [Data Types](/docs/arvo/ames/data-types)
26+
27+Reference documentation of the various data types used by Ames.
content/docs/arvo/ames/ames-api.mddeleted−292
@@ -1,292 +0,0 @@
1−+++
2−title = "API Reference"
3−weight = 10
4−template = "doc.html"
5−+++
6−
7−In this document we describe the public interface for Ames. Namely, we describe
8−each `task` that Ames can be `%pass`ed, and which `gift`(s) Ames can `%give` in return.
9−
10−Some `task`s appear to have more than one arm associated to them, e.g. there are
11−four `+on-hear` arms. We denote this where it occurs, but always refer to the
12−`on-hear:event-core` arm.
13−
14−Ames `task`s can be naturally divided into two categories: messaging tasks and
15−system/lifecycle tasks.
16−
17−## Messaging Tasks
18−
19−### `%hear`
20−
21−`%hear` handles raw packet receipt. This `task` only ever originates from Unix.
22−It does the initial processing of a packet, namely by passing the raw packet
23−information to `+decode-packet` which deserializes the packet and giving that data and the origin of the
24−packet to `+on-hear-packet`, which begins the transformation of the packet into
25−a new event in the form of a `+event-core`.
26−
27−There are multiple `+on-hear` arms in `ames.hoon`. Here we refer to
28−`on-hear:event-core`, as that is the one called by a `%hear` `task`. The other ones are used
29−primarily for ack and nack processing, or receiving message fragments.
30−
31−#### Accepts
32−
33−```hoon
34−[=lane =blob]
35−```
36−
37−`%hear` takes in a `blob`, which is essentially a large atom (around 1kB or less)
38−that is the raw data of the message, and a `lane`, which is the origin of the
39−message (typically an IP address).
40−
41−#### Returns
42−
43−`%hear` can trigger a number of possible returns. It can trigger the release of
44−zero or more additional packets via `%send` `gift`s. It may also trigger a `%boon`
45−or `%plea` `gift` (collectively referred to as a `%memo` within Ames) to a local vane in the case of a completed message.
46−
47−
48−### `%heed`
49−
50−A vane can pass Ames a `%heed` `task` to request Ames track a peer's
51−responsiveness. If our `%boon`s to it start backing up locally,
52−Ames will `give` a `%clog` back to the requesting vane containing the
53−unresponsive peer's Urbit address.
54−
55−Stop tracking a peer by sending Ames a
56−`%jilt` `task`.
57−
58−
59−#### Accepts
60−
61−```hoon
62−=ship
63−```
64−
65−The ship to be tracked.
66−
67−#### Returns
68−
69−If the `ship` is indeed being unresponsive, as measured by backed up `%boon`s,
70−Ames will `give` a `%clog` `gift` to the requesting vane containing the
71−unresponsive peer's urbit address.
72−
73−
74−### `%hole`
75−
76−`%hole` handles packet crash notification. `%hole` works much like `%hear`, in
77−that it passes an incoming raw packet to `+decode-packet` to be deserialized,
78−and then passes that data along with the source of the packet to
79−`+on-hear-packet` along with a `?` set to `%.n` denoting that there is something wrong with
80−the packet.
81−
82−#### Accepts
83−
84−```hoon
85−[=lane =blob]
86−```
87−`%hole` takes in a `blob`, which is essentially a large atom (around 1kB or less)
88−that is the raw data of the message, and a `lane`, which is the origin of the
89−message (typically an IP address).
90−
91−#### Returns
92−
93−Like `%hear`, `%hole` can trigger additional packets in the form of `%send`
94−`gift`s, and may also yield a `%boon` or `%plea` `gift` to a local vane.
95−
96−
97−### `%jilt`
98−
99−`%jilt` stops tracking a potentially unresponsive peer that was previously being
100−tracked as a result of the `%heed` `task`.
101−
102−There are two `+on-jilt` arms, this `task` utilizes `on-hear:event-core`.
103−
104−#### Accepts
105−
106−```hoon
107−=ship
108−```
109−
110−The `ship` we no longer wish to track.
111−
112−#### Returns
113−
114−This `task` returns no `gift`s.
115−
116−
117−### `%plea`
118−
119−`%plea` is the `task` used to instruct Ames to send a message. It extends the
120−`%pass`/`%give` semantics across the network. As such, it is the most
121−fundamental `task` in Ames and the primary reason for its existence.
122−
123−Ames also `pass`es a `%plea` `note` to another vane when it receives a message on a
124−"forward flow" from a peer, originally passed from one of the peer's vanes to the
125−peer's Ames.
126−
127−Ultimately `%plea` causes `%send` `gift`(s) to be sent to Unix, which tells
128−Unix to send packets. In terms of `%pass`/`%give` semantics, this is in
129−response to the `%born` `task`, which came along the Unix `duct`, rather than a
130−response to the `%plea`.
131−
132−#### Accepts
133−
134−```hoon
135−[=ship =plea]
136−```
137−
138−A `%plea` `task` takes in the `ship` the `plea` is addressed to, and a `$plea`,
139−which is
140−
141−```hoon
142− +$ plea [vane=@tas =path payload=*]
143−```
144−Here, `vane` is the destination vane on the remote ship, `path` is the internal
145−route on the receiving ship, and `payload` is the semantic message content.
146−
147−#### Returns
148−
149−This `task` returns no `gift`s.
150−
151−## System and Lifecycle Tasks
152−
153−### `%born`
154−
155−Each time you start your Urbit, the Arvo kernel calls the `%born` task for Ames.
156−
157−#### Accepts
158−
159−`%born` takes no arguments.
160−
161−#### Returns
162−
163−In response to a `%born` `task`, Ames `%give`s Jael a `%turf` `gift`.
164−
165−The `duct` along which `%born` comes is Ames' only duct to Unix, so `%send`
166−`gift`s (which are instructions for Unix to send a packet) are also returned in
167−response to `%born`.
168−
169−
170−### `%crud`
171−
172−`%crud` is called whenever an error involving Ames occurs. It produces a crash
173−report in response.
174−
175−#### Accepts
176−
177−```hoon
178−=error
179−```
180−
181−A `$error` is a `[tag=@tas =tang]`.
182−
183−#### Returns
184−
185−Ames does not `give` a `gift` in response to a `%crud` `task`, but it does
186−`%pass` Dill a `%flog` `task` instructing it to print `error`.
187−
188−
189−## `%init`
190−
191−`%init` is called a single time during the very first boot process, immediately
192−after the [larval stage](/docs/arvo/overview#larval-stage-core)
193−is completed. This initializes the vane. Jael is initialized first, followed by
194−other vanes such as Ames.
195−
196−In response to receiving the `%init` `task`, Ames subscribes to the information
197−contained by Jael.
198−
199−#### Accepts
200−
201−```hoon
202−our=ship
203−```
204−
205−`%init` takes in the name of our ship, which is a `@p`.
206−
207−#### Returns
208−
209−```hoon
210− =~ (emit duct %pass /turf %j %turf ~)
211− (emit duct %pass /private-keys %j %private-keys ~)
212−```
213−
214−`%init` sends two moves that subscribe to `%turf` and `%private-keys` in Jael.
215−
216−
217−### `%sift`
218−
219−This `task` filters debug output by ship.
220−
221−#### Accepts
222−
223−```hoon
224−ships=(list ship)
225−```
226−
227−The list of ships for which debug output is desired.
228−
229−#### Returns
230−
231−This `task` returns no `gift`s.
232−
233−
234−### `%spew`
235−
236−Sets verbosity toggles on debug output. These toggles are as follows.
237−
238−* `%snd` - sending packets
239−* `%rcv` - receiving packets
240−* `%odd` - unusual events
241−* `%msg` - message-level events
242−* `%ges` - congestion control
243−* `%for` - packet forwarding
244−* `%rot` - routing attempts
245−
246−Each toggle is a flag set to `%.n` by default.
247−
248−#### Accepts
249−
250−```hoon
251−verbs=(list verb)
252−```
253−
254−`%spew` takes in a `list` of `verb`, which are verbosity flags for Ames.
255−
256−```hoon
257−+$ verb ?(%snd %rcv %odd %msg %ges %for %rot)
258−```
259−
260−`%spew` flips each toggle given in `verbs`.
261−
262−#### Returns
263−
264−This `task` returns no `gift`s.
265−
266−
267−### `%vega`
268−
269−`%vega` is called whenever the kernel is updated. Ames currently does not do
270−anything in response to this.
271−
272−#### Accepts
273−
274−`%vega` takes no arguments.
275−
276−#### Returns
277−
278−This `task` returns no `gift`s.
279−
280−
281−### `%wegh`
282−
283−This `task` is a request to Ames to produce a memory usage report.
284−
285−#### Accepts
286−
287−This `task` has no arguments.
288−
289−#### Returns
290−
291−In response to this `task,` Ames `%give`s a `%mass` `gift` containing Ames'
292−current memory usage.
content/docs/arvo/ames/cryptography.md+3−3
@@ -1,6 +1,6 @@
11+++
22title = "Cryptography"
3−weight = 5
3+weight = 2
44template = "doc.html"
55+++
66
@@ -34,7 +34,7 @@ Algorithm](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algori
3434is used for authentication
3535
3636The encrypted payload of each packet is a `$shut-packet`, which is the `+jam` of
37−a cell with the `bone`, message number, and message fragment or ack (see
37+a cell with the [$bone](/docs/arvo/ames/data-types#bone), message number, and message fragment or ack (see
3838[Ames](/docs/arvo/ames/ames) for more information on packet structure). The
3939message fragment is signed using the authentication key. It is encrypted using
4040[`+en:crub:crypto`](/docs/arvo/reference/cryptography#en) found in
@@ -43,7 +43,7 @@ message fragment is signed using the authentication key. It is encrypted using
4343## Diffie-Hellman key exchange {#key-exchange}
4444
4545For each foreign ship a given ship has communicated with, `$ames-state` contains a
46−`$peer-state`, inside which the `$symmetric-key` (an atom which nests under
46+[$peer-state](/docs/arvo/ames/data-types#peer-state), inside which the [$symmetric-key](/docs/arvo/ames/data-types#symmetric-key) (an atom which nests under
4747`@uw`) is utilized for encrypting all Ames packets shared between the two ships.
4848The `symmetric-key` is derived using [`+shar:ed:crypto`](/docs/arvo/reference/cryptography#ed) found in `sys/zuse.hoon`,
4949which is an arm utilized for generating the symmetric key for elliptic curve
content/docs/arvo/ames/data-types.mdnew file+389
@@ -0,0 +1,389 @@
1++++
2+title = "Data Types"
3+weight = 5
4+template = "doc.html"
5++++
6+
7+Here are the data types used by Ames, as defined in `lull.hoon`.
8+
9+## `$address`
10+
11+```hoon
12++$ address @uxaddress
13+```
14+
15+Opaque atomic transport address to or from Unix. For Ames over UDP, it will encode the IP address and port.
16+
17+## `$verb`
18+
19+```hoon
20++$ verb ?(%snd %rcv %odd %msg %ges %for %rot)
21+```
22+
23+Verbosity flag for Ames. Use with `|ames-verb %flag1 %flag2 ...` and turn off with `|ames-verb`.
24+
25+- `%snd` - Sending packets.
26+- `%rcv` - Receiving packets.
27+- `%odd` - Unusual events.
28+- `%msg` - Message-level events.
29+- `%ges` - Congestion control.
30+- `%for` - Packet forwarding.
31+- `%rot` - Routing attempts.
32+
33+## `$blob`
34+
35+```hoon
36++$ blob @uxblob
37+```
38+
39+Raw atom to or from Unix, representing a packet.
40+
41+## `$error`
42+
43+```hoon
44++$ error [tag=@tas =tang]
45+```
46+
47+Tagged diagnostic trace.
48+
49+## `$lane`
50+
51+```hoon
52++$ lane (each @pC address)
53+```
54+
55+Ship transport address; either opaque [$address](#address) or galaxy. The runtime knows how to look up galaxies, so we don't need to know their transport addresses.
56+
57+## `$plea`
58+
59+```hoon
60++$ plea [vane=@tas =path payload=*]
61+```
62+
63+Application-level message, as a `%pass`.
64+
65+- `vane` - Destination vane on remote ship.
66+- `path` - Internal route on the receiving ship.
67+- `payload` - Semantic message contents.
68+
69+## `$bone`
70+
71+```hoon
72++$ bone @udbone
73+```
74+
75+Message flow index - mapped to `duct`s in the [$ossuary](#ossuary).
76+
77+The first `bone` is 0. They increment by 4, since each flow includes a bit for each message determining forward vs. backward and a second bit for whether the message is on the normal flow or the associated diagnostic flow (for naxplanations).
78+
79+The least significant bit of a `bone` is:
80+
81+- 1 if "forward", i.e. we send `%plea`s on this flow.
82+- 0 if "backward", i.e. we receive `%plea`s on this flow.
83+
84+The second-least significant bit is 1 if the `bone` is a naxplanation `bone`, and 0 otherwise. Only naxplanation messages can be sent on a naxplanation `bone`, as `%boon`s.
85+
86+## `$fragment`
87+
88+```hoon
89++$ fragment @uwfragment
90+```
91+
92+A message fragment.
93+
94+## `$fragment-num`
95+
96+```hoon
97++$ fragment-num @udfragmentnum
98+```
99+
100+Message fragment count.
101+
102+## `$message-blob`
103+
104+```hoon
105++$ message-blob @udmessageblob
106+```
107+
108+Unfragmented message blob.
109+
110+## `$message-num`
111+
112+```hoon
113++$ message-num @udmessagenum
114+```
115+
116+Message count.
117+
118+## `$public-key`
119+
120+```hoon
121++$ public-key @uwpublickey
122+```
123+
124+A peer's public key.
125+
126+## `$symmetric-key`
127+
128+```hoon
129++$ symmetric-key @uwsymmetrickey
130+```
131+
132+A symmetric key for encrypting messages to a peer. This is produced by performing an elliptic curve Diffie-Hellman using our private key and the peer's public key.
133+
134+## `$ack`
135+
136+```hoon
137++$ ack
138+ $% [%ok ~]
139+ [%nack ~]
140+ [%naxplanation =error]
141+ ==
142+```
143+
144+A message acknowledgement.
145+
146+- `%ok` - Positive acknowledgement.
147+- `%nack` - Negative acknowledgement.
148+- `%naxplanation` - Nack trace.
149+
150+## `$ship-state`
151+
152+```hoon
153++$ ship-state
154+ $% [%alien alien-agenda]
155+ [%known peer-state]
156+ ==
157+```
158+
159+All Ames knows about a peer.
160+
161+- `%alien` - No PKI data, so enqueue actions to perform once we learn it.
162+- `%known` - We know their `life` and public keys, so we have a channel.
163+
164+## `$alien-agenda`
165+
166+```hoon
167++$ alien-agenda
168+ $: messages=(list [=duct =plea])
169+ packets=(set =blob)
170+ heeds=(set duct)
171+ ==
172+```
173+
174+What to do when Ames learns a peer's life and keys.
175+
176+- `messages` - [$plea](#plea)s local vanes have asked Ames to send.
177+- `packets` - Packets we've tried to send.
178+- `heeds` - Local tracking requests; passed through into [$peer-state](#peer-state).
179+
180+## `$peer-state`
181+
182+```hoon
183++$ peer-state
184+ $: $: =symmetric-key
185+ =life
186+ =public-key
187+ sponsor=ship
188+ ==
189+ route=(unit [direct=? =lane])
190+ =qos
191+ =ossuary
192+ snd=(map bone message-pump-state)
193+ rcv=(map bone message-sink-state)
194+ nax=(set [=bone =message-num])
195+ heeds=(set duct)
196+ ==
197+```
198+
199+State for a peer with known life and keys.
200+
201+- `route` - Transport-layer destination for packets to the peer.
202+- `qos` - Quality of service; connection status to the peer.
203+- `ossuary` - [$bone](#bone) to `duct` mapper.
204+- `snd` - Per-`bone` message pumps to send messages as fragments.
205+- `rcv` - Per-`bone` message sinks to assemble messages from fragments.
206+- `nax` - Unprocessed nacks (negative acknowledgments).
207+- `heeds` - Listeners for `%clog` notifications.
208+
209+## `$qos`
210+
211+```hoon
212++$ qos
213+ $~ [%unborn *@da]
214+ [?(%live %dead %unborn) last-contact=@da]
215+```
216+
217+Quality of service; how is the connection to a peer doing?
218+
219+- `%live` - Peer is ok.
220+- `%dead` - Peer is not responding.
221+- `%unborn` - Peer is sunken.
222+- `last-contact` - Last time Ames heard from the peer, or if `%unborn`, the time when we first started tracking then.
223+
224+## `$ossuary`
225+
226+```hoon
227++$ ossuary
228+ $: =next=bone
229+ by-duct=(map duct bone)
230+ by-bone=(map bone duct)
231+ ==
232+```
233+
234+[$bone](#bone) to `duct` mapping, `next` is the next `bone` to map to a `duct`.
235+
236+## `$message-pump-state`
237+
238+```hoon
239++$ message-pump-state
240+ $: current=_`message-num`1
241+ next=_`message-num`1
242+ unsent-messages=(qeu message-blob)
243+ unsent-fragments=(list static-fragment)
244+ queued-message-acks=(map message-num ack)
245+ =packet-pump-state
246+ ==
247+```
248+
249+Persistent state for a `|message-pump`.
250+
251+- `current`- Sequence number of earliest message sent or being sent.
252+- `next` - Sequence number of next message to send.
253+- `unsent-messages` - Messages to be sent after current message.
254+- `unsent-fragments` - Fragments of current message waiting for sending.
255+- `queued-message-acks` - Future message acks to be applied after current.
256+- `packet-pump-state` - State of corresponding `|packet-pump`.
257+
258+## `$static-fragment`
259+
260+```hoon
261++$ static-fragment
262+ $: =message-num
263+ num-fragments=fragment-num
264+ =fragment-num
265+ =fragment
266+ ==
267+```
268+
269+A packet; a fragment of a message and metadata.
270+
271+## `$packet-pump-state`
272+
273+```hoon
274++$ packet-pump-state
275+ $: next-wake=(unit @da)
276+ live=(tree [live-packet-key live-packet-val])
277+ metrics=pump-metrics
278+ ==
279+```
280+
281+Persistent state for a `|packet-pump`.
282+
283+- `next-wake` - Last timer we've set, or null.
284+- `live` - Packets in flight; sent but not yet acked.
285+- `metrics` - Congestion control information.
286+
287+## `$pump-metrics`
288+
289+```hoon
290++$ pump-metrics
291+ $: rto=_~s1
292+ rtt=_~s1
293+ rttvar=_~s1
294+ ssthresh=_10.000
295+ cwnd=_1
296+ num-live=@ud
297+ counter=@ud
298+ ==
299+```
300+
301+Congestion control state for a `|packet-pump`.
302+
303+- `rto` - Retransmission timeout.
304+- `rtt` - Roundtrip time estimate, low-passed using EWMA.
305+- `rttvar` - Mean deviation of `rtt`, also low-passed with EWMA.
306+- `num-live` - How many packets sent, awaiting ack.
307+- `ssthresh` - Slow-start threshold.
308+- `cwnd` - Congestion window; max unacked packets.
309+
310+## `$live-packet`
311+
312+```hoon
313++$ live-packet
314+ $: key=live-packet-key
315+ val=live-packet-val
316+ ==
317+```
318+
319+A packet in flight, as tracked in the [$packet-pump-state](#packet-pump-state).
320+
321+## `$live-packet-key`
322+
323+```hoon
324++$ live-packet-key
325+ $: =message-num
326+ =fragment-num
327+ ==
328+```
329+
330+Identifier of a packet in flight.
331+
332+## `$live-packet-val`
333+
334+```hoon
335++$ live-packet-val
336+ $: packet-state
337+ num-fragments=fragment-num
338+ =fragment
339+ ==
340+```
341+
342+Content and metadata about a packet in flight.
343+
344+## `$packet-state`
345+
346+```hoon
347++$ packet-state
348+ $: last-sent=@da
349+ retries=@ud
350+ skips=@ud
351+ ==
352+```
353+
354+Sending statistics about a packet in flight.
355+
356+## `$message-sink-state`
357+
358+```hoon
359++$ message-sink-state
360+ $: last-acked=message-num
361+ last-heard=message-num
362+ pending-vane-ack=(qeu [=message-num message=*])
363+ live-messages=(map message-num partial-rcv-message)
364+ nax=(set message-num)
365+ ==
366+```
367+
368+State of a `|message-sink` to assemble received messages.
369+
370+- `last-acked` - Highest [$message-num](#message-num) Ames has fully acknowledged.
371+- `last-heard` - Highest `message-num` Ames has heard all fragments for.
372+- `pending-vane-ack` - Heard but not processed by local vane.
373+- `live-messages` - Partially received messages.
374+
375+## `$partial-rcv-message`
376+
377+```hoon
378++$ partial-rcv-message
379+ $: num-fragments=fragment-num
380+ num-received=fragment-num
381+ fragments=(map fragment-num fragment)
382+ ==
383+```
384+
385+A message for which Ames has received some fragments.
386+
387+- `num-fragments` - Total number of fragments in the message.
388+- `num-received` - How many fragments Ames has received so far.
389+- `fragments` - The received fragments themselves.
content/docs/arvo/ames/scry.mdnew file+126
@@ -0,0 +1,126 @@
1++++
2+title = "Scry Reference"
3+weight = 4
4+template = "doc.html"
5++++
6+
7+Here are the scry endpoints of Ames. All of them take a `%x` `care` and require the `desk` in the path prefix be empty, so the general format is `.^([type] %ax /=//=/[some-path])`.
8+
9+## /protocol/version
10+
11+A scry with a `%x` `care` and a `path` of `/protocol/version` will return the current Ames protocol version as a `@`.
12+
13+#### Example
14+
15+```
16+> .^(@ %ax /=//=/protocol/version)
17+0
18+```
19+
20+## /peers
21+
22+A scry with a `%x` `care` and a `path` of `/peers` will return all ships that Ames is aware of. The type returned is a `(map ship ?(%alien %known))`, where `%known` means we have PKI data for them and `%alien` means we don't.
23+
24+#### Example
25+
26+```
27+> .^((map ship ?(%alien %known)) %ax /=//=/peers)
28+{[p=~wet q=%known] [p=~nes q=%known]}
29+```
30+
31+## /peers/[ship]
32+
33+A scry with a `%x` `care` and a `path` of `/peers/[ship]` where `[ship]` is a ship name like `~dopzod` will return everything Ames knows about that ship, or crash if the ship is unknown to Ames. The type returned is a [$ship-state](/docs/arvo/ames/data-types#ship-state).
34+
35+#### Example
36+
37+```
38+> .^(ship-state:ames %ax /=//=/peers/~nes)
39+[ %known
40+ [ symmetric-key=0wEF.5-Mp4.ehBxk.a-ktl.CAUHq.~XNVq.AfPFk.TwBbj.rc7MS
41+ life=1
42+ public-key=0w9R.IG6Km.CQfuL.lP9Da.l~kh1.lOHzV.xactk.1ybiB.hekW~.VC2d0.DDRsU.h6GHl.PKmRX.p3u2-.vO4Hg.QTOlp.A4AI0.uGPVy
43+ sponsor=~nes
44+ ]
45+ route=[~ [direct=%.y lane=[%.y p=~nes]]]
46+ qos=[%dead last-contact=~2021.8.9..16.11.36..fdbc]
47+ ossuary
48+ [ next-bone=4
49+ by-duct={[p=~[/gall/sys/way/~nes/hood /gall/use/hood/0w2.4d7EV/out/~nes/hood/helm/hi/~nes /dill //term/1] q=0]}
50+ by-bone={[p=0 q=~[/gall/sys/way/~nes/hood /gall/use/hood/0w2.4d7EV/out/~nes/hood/helm/hi/~nes /dill //term/1]]}
51+ ]
52+ snd
53+ { [ p=0
54+ q
55+ [ current=2
56+ next=3
57+ unsent-messages={}
58+ unsent-fragments=~
59+ queued-message-acks={}
60+ packet-pump-state
61+ [ next-wake=[~ ~2021.8.17..02.21.14..3d23]
62+ live={[[message-num=2 fragment-num=0] [last-sent=~2021.8.17..02.19.14..3d23 retries=2.255 skips=0] num-fragments=1 fragment=0w2.QJ1qS.JzaQn.w7rMp.IzuTJ.7M7aP.-1s~1]}
63+ metrics=[rto=~m2 rtt=~s1 rttvar=~s1 ssthresh=1 cwnd=1 num-live=1 counter=1]
64+ ]
65+ ]
66+ ]
67+ }
68+ rcv={}
69+ nax={}
70+ heeds={~[/gall/sys/lag /dill //term/1]}
71+]
72+```
73+
74+## /peers/[ship]/forward-lane
75+
76+A scry with a `%x` `care` and a `path` of `/peers/[ship]/forward-lane` where `[ship]` is a ship name like `~dopzod` will return outbound routes to the given ship, or `~` if there are none. The type returned is a `(list lane:ames)`, see [$lane](/docs/arvo/ames/data-types#lane) for type details.
77+
78+#### Examples
79+
80+```
81+> .^((list lane:ames) %ax /=//=/peers/~nes/forward-lane)
82+~[[%.y p=~nes]]
83+```
84+
85+```
86+> .^((list lane:ames) %ax /=//=/peers/~nec/forward-lane)
87+~
88+```
89+
90+## /bones/[ship]
91+
92+A scry with a `%x` `care` and a `path` of `/bones/[ship]` where `[ship]` is a ship name like `~dopzod` will return inbound and outbound [$bone](/docs/arvo/ames/data-types#bone)s, which index message flows. If the ship in question is unknown to Ames, the scry will fail. The type returned is `[snd=(set bone) rcv=(set bone)]`.
93+
94+#### Example
95+
96+```
97+> .^([snd=(set bone) rcv=(set bone)] %ax /=//=/bones/~nes)
98+[snd={0} rcv={}]
99+```
100+
101+## /snd-bones/[ship]/[bone]
102+
103+A scry with a `%x` `care` and a `path` of `/snd-bones/[ship]/[bone]`, where `[ship]` is a ship name like `~dopzod` and `[bone]` is an outbound [$bone](/docs/arvo/ames/data-types#bone), will return message flow details for that `bone`. If the ship in question is unknown to Ames or the `bone` does not exist, the scry will fail. The type returned is a [$message-pump-state](/docs/arvo/ames/data-types#message-pump-state) wrapped in a `vase`.
104+
105+#### Example
106+
107+```
108+> !< message-pump-state:ames .^(vase %ax /=//=/snd-bones/~nes/0)
109+[ current=2
110+ next=3
111+ unsent-messages={}
112+ unsent-fragments=~
113+ queued-message-acks={}
114+ packet-pump-state
115+ [ next-wake=[~ ~2021.8.17..02.27.14..aaff]
116+ live
117+ { [ [message-num=2 fragment-num=0]
118+ [last-sent=~2021.8.17..02.25.14..aaff retries=2.258 skips=0]
119+ num-fragments=1
120+ fragment=0w2.QJ1qS.JzaQn.w7rMp.IzuTJ.7M7aP.-1s~1
121+ ]
122+ }
123+ metrics=[rto=~m2 rtt=~s1 rttvar=~s1 ssthresh=1 cwnd=1 num-live=1 counter=1]
124+ ]
125+]
126+```
content/docs/arvo/ames/tasks.mdnew file+193
@@ -0,0 +1,193 @@
1++++
2+title = "API Reference"
3+weight = 3
4+template = "doc.html"
5++++
6+
7+In this document we describe the public interface for Ames. Namely, we describe
8+each `task` that Ames can be `%pass`ed, and which `gift`(s) Ames can `%give` in return.
9+
10+Some `task`s appear to have more than one arm associated to them, e.g. there are
11+four `+on-hear` arms. We denote this where it occurs, but always refer to the
12+`+on-hear:event-core` arm.
13+
14+Ames `task`s can be naturally divided into two categories: messaging tasks and
15+system/lifecycle tasks.
16+
17+## Messaging Tasks
18+
19+### `%hear`
20+
21+```hoon
22+[%hear =lane =blob]
23+```
24+
25+`%hear` handles raw packet receipt.
26+
27+This `task` only ever originates from Unix. It does the initial processing of a packet, namely by passing the raw packet information to `+decode-packet` which deserializes the packet and giving that data and the origin of the packet to `+on-hear-packet`, which begins the transformation of the packet into a new event in the form of a `+event-core`.
28+
29+There are multiple `+on-hear` arms in `ames.hoon`. Here we refer to `+on-hear:event-core`, as that is the one called by a `%hear` `task`. The other ones are used primarily for ack and nack processing, or receiving message fragments.
30+
31+`%hear` takes in a [$blob](/docs/arvo/ames/data-types#blob), which is essentially a large atom (around 1kB or less) that is the raw data of the message, and a [$lane](/docs/arvo/ames/data-types#lane), which is the origin of the message (typically an IP address).
32+
33+#### Returns
34+
35+`%hear` can trigger a number of possible returns. It can trigger the release of zero or more additional packets via `%send` `gift`s. It may also trigger a `%boon` or `%plea` `gift` (collectively referred to as a `%memo` within Ames) to a local vane in the case of a completed message.
36+
37+### `%heed`
38+
39+```hoon
40+[%heed =ship]
41+```
42+
43+A vane can pass Ames a `%heed` `task` to request Ames track a peer's responsiveness. If our `%boon`s to it start backing up locally, Ames will `give` a `%clog` back to the requesting vane containing the unresponsive peer's Urbit address.
44+
45+Stop tracking a peer by sending Ames a [%jilt](#jilt) `task`.
46+
47+The `ship` field specifies the peer to be tracked.
48+
49+#### Returns
50+
51+If the `ship` is indeed being unresponsive, as measured by backed up `%boon`s,
52+Ames will `give` a `%clog` `gift` to the requesting vane containing the
53+unresponsive peer's urbit address.
54+
55+### `%jilt`
56+
57+```hoon
58+[%jilt =ship]
59+```
60+
61+`%jilt` stops tracking a potentially unresponsive peer that was previously being
62+tracked as a result of the [%heed](#heed) `task`.
63+
64+There are two `+on-jilt` arms, this `task` utilizes `+on-hear:event-core`.
65+
66+The `ship` field specifies the peer we want to stop tracking.
67+
68+#### Returns
69+
70+This `task` returns no `gift`s.
71+
72+### `%plea`
73+
74+```hoon
75+[%plea =ship =plea:ames]
76+```
77+
78+`%plea` is the `task` used to instruct Ames to send a message. It extends the
79+`%pass`/`%give` semantics across the network. As such, it is the most
80+fundamental `task` in Ames and the primary reason for its existence.
81+
82+Ames also `pass`es a `%plea` `note` to another vane when it receives a message on a
83+"forward flow" from a peer, originally passed from one of the peer's vanes to the
84+peer's Ames.
85+
86+Ultimately `%plea` causes `%send` `gift`(s) to be sent to Unix, which tells
87+Unix to send packets. In terms of `%pass`/`%give` semantics, this is in
88+response to the `%born` `task`, which came along the Unix `duct`, rather than a
89+response to the `%plea`.
90+
91+A `%plea` `task` takes in the `ship` the `plea` is addressed to, and a [$plea](/docs/arvo/ames/data-types.md#plea).
92+
93+#### Returns
94+
95+This `task` returns no `gift`s.
96+
97+## System Tasks
98+
99+### `%born`
100+
101+```hoon
102+[%born ~]
103+```
104+
105+Each time you start your Urbit, the Arvo kernel calls the `%born` `task` for Ames.
106+
107+#### Returns
108+
109+In response to a `%born` `task`, Ames `%give`s Jael a `%turf` `gift`.
110+
111+The `duct` along which `%born` comes is Ames' only duct to Unix, so `%send`
112+`gift`s (which are instructions for Unix to send a packet) are also returned in
113+response to `%born`.
114+
115+### `%init`
116+
117+```hoon
118+[%init ~]
119+```
120+
121+`%init` is called a single time during the very first boot process, immediately
122+after the [larval stage](/docs/arvo/overview#larval-stage-core)
123+is completed. This initializes the vane. Jael is initialized first, followed by
124+other vanes such as Ames.
125+
126+In response to receiving the `%init` `task`, Ames subscribes to the information
127+contained by Jael.
128+
129+#### Returns
130+
131+```hoon
132+=~ (emit duct %pass /turf %j %turf ~)
133+ (emit duct %pass /private-keys %j %private-keys ~)
134+```
135+
136+`%init` sends two moves that subscribe to `%turf` and `%private-keys` in Jael.
137+
138+### `%sift`
139+
140+```hoon
141+[%sift ships=(list ship)]
142+```
143+
144+This `task` filters debug output by ship. This `task` is used internally when the `|ames-sift` `hood` generator is run from the dojo.
145+
146+The `ships` field specifies the ships for which debug output is desired.
147+
148+#### Returns
149+
150+This `task` returns no `gift`s.
151+
152+### `%spew`
153+
154+```hoon
155+[%spew veb=(list verb)]
156+```
157+
158+Sets verbosity toggles on debug output. This `task` is used internally when the `|ames-verb` `hood` generator is run from the dojo.
159+
160+`%spew` takes in a `list` of [$verb](/docs/arvo/ames/data-types#verb), which are verbosity flags for Ames.
161+
162+`%spew` flips each toggle given in `veb`.
163+
164+#### Returns
165+
166+This `task` returns no `gift`s.
167+
168+### `%stir`
169+
170+```hoon
171+[%stir arg=@t]
172+```
173+
174+A `%stir` `task` starts timers for any flows that lack them.
175+
176+The `arg` field is unused.
177+
178+#### Returns
179+
180+This `task` returns no `gift`s.
181+
182+### `%vega`
183+
184+```hoon
185+[%vega ~]
186+```
187+
188+`%vega` is called whenever the kernel is updated. Ames currently does not do
189+anything in response to this.
190+
191+#### Returns
192+
193+This `task` returns no `gift`s.
content/docs/arvo/clay/architecture.md+3−78
@@ -172,81 +172,6 @@ of this system in some detail.
172172
173173### Marks
174174
175−Central to a typed filesystem is the idea of types. In Clay, we
176−call these `mark`s. A `mark` is a file that defines a type,
177−conversion routines to and from the `mark`, and diff, patch, and
178−merge routines.
179−
180−For example, a `%txt` mark may be a list of lines of text, and it
181−may include conversions to `%mime` to allow it to be serialized
182−and sent to a browser or to the Unix filesystem. It will also
183−include Hunt-McIlroy diff, patch, and merge algorithms.
184−
185−A `%json` `mark` would be defined as a JSON object in the code, and
186−it would have a parser to convert from `%txt` and a printer to
187−convert back to `%txt`. The diff, patch, and merge algorithms are
188−fairly straightforward for JSON, though they're very different
189−from the text ones.
190−
191−More formally, a `mark` is a core with three [arms](/docs/glossary/arm/): `+grab`,
192−`+grow`, and `+grad`. In `+grab` is a series of functions to
193−convert from other `mark`s to the given `mark`. In `+grow` is a
194−series of functions to convert from the given `mark` to other
195−`mark`s. In `+grad` is `+diff`, `+pact`, `+join`, and `+mash`, and
196−`+form`.
197−
198−The types are as follows, in an informal pseudocode:
199−
200−```
201− ++ grab:
202− ++ mime: <mime> -> <mark-type>
203− ++ txt: <txt> -> <mark-type>
204− ...
205− ++ grow:
206− ++ mime: <mark-type> -> <mime>
207− ++ txt: <mark-type> -> <txt>
208− ...
209− ++ grad
210− ++ form: <mark-type>
211− ++ diff: (<mark-type>, <mark-type>) -> <diff-type>
212− ++ pact: (<mark-type>, <diff-type>) -> <mark-type>
213− ++ join: (<diff-type>, <diff-type>) -> <diff-type> or NULL
214− ++ mash: (<diff-type>, <diff-type>) -> <diff-type>
215−```
216−
217−These types are basically what you would expect. Not every `mark`
218−has each of these functions defined -- all of them are optional
219−in the general case.
220−
221−In general, for a particular `mark`, the `+grab` and `+grow` entries
222−(if they exist) should be inverses of each other.
223−
224−In `+grad`, `+diff` takes two instances of a `mark` and produces a diff of them
225−whose `mark` is given by `+form`. `+pact` takes an instance of a `mark` and
226−patches it with the given diff. `+join` takes two diffs and attempts to merge
227−them into a single diff. If there are conflicts, it produces null. `+mash` takes
228−two diffs and forces a merge, annotating any conflicts.
229−
230−In general, if `+diff` called with A and B produces diff D, then
231−`+pact` called with A and D should produce B. Also, if `+join`
232−of two diffs does not produce null, then `+mash` of the same
233−diffs should produce the same result.
234−
235−Alternately, instead of `+diff`, `+pact`, `+join`, and
236−`+mash`, a `mark` can provide the same functionality by defining
237−`+grad` to be the name of another `mark` to which we wish to
238−delegate the revision control responsibilities. Then, before
239−running any of those functions, Clay will convert to the other
240−`mark`, and convert back afterward. For example, the `%hoon` `mark`
241−is revision-controlled in the same way as `%txt`, so its `+grad`
242−is simply `++ grad %txt`. Of course, `+txt` must be defined in
243−`+grow` and `+grab` as well.
244−
245−Every file in Clay has a `mark`, and that `mark` must have a
246−fully-functioning `+grad`. `Mark`s are used for more than just
247−Clay, and other `mark`s don't need a `+grad`, but if a piece of
248−data is to be saved to Clay, we must know how to revision-control
249−it.
250−
251−Additionally, if a file is to be synced out to Unix, then it must
252−have conversion routines to and from the `%mime` `mark`.
175+Central to a typed filesystem is the idea of file types. In Clay, we
176+call these `mark`s. See the [Marks](/docs/arvo/clay/marks/marks)
177+section for more details.
content/docs/arvo/clay/clay.md+4−1
@@ -5,7 +5,6 @@ template = "doc.html"
55aliases = ["/docs/learn/arvo/clay/"]
66+++
77
8−
98Our filesystem.
109
1110`%clay` is version-controlled, referentially-transparent, and global.
@@ -56,3 +55,7 @@ Details of the various `task`s you can use to interact with Clay.
5655[Examples](/docs/arvo/clay/examples)
5756
5857Example usage of the various Clay `task`s.
58+
59+[Marks](/docs/arvo/clay/marks/marks)
60+
61+Details of `mark`s as well as a guide to writing them and their usage.
content/docs/arvo/clay/marks/_index.mdnew file+23
@@ -0,0 +1,23 @@
1++++
2+title = "Marks"
3+weight = 10
4+sort_by = "weight"
5+template = "sections/docs/chapters.html"
6+insert_anchor_links = "right"
7++++
8+
9+[Overview](/docs/arvo/clay/marks/marks)
10+
11+Overview of `mark`s.
12+
13+[Writing Marks](/docs/arvo/clay/marks/writing-marks)
14+
15+A practical walk-through of writing a `mark` file.
16+
17+[Using Marks](/docs/arvo/clay/marks/using-marks)
18+
19+Details of using `mark` conversion gates and `mark` cores in your own code.
20+
21+[Examples](/docs/arvo/clay/marks/examples)
22+
23+The example code used in the Writing Marks guide.
content/docs/arvo/clay/marks/examples.mdnew file+248
@@ -0,0 +1,248 @@
1++++
2+title = "Examples"
3+weight = 4
4+template = "doc.html"
5++++
6+
7+These are the files used in the [Writing Marks](/docs/arvo/clay/marks/writing-marks) guide.
8+
9+## `/lib/csv/hoon`
10+
11+```hoon
12+|%
13+++ validate :: All rows same length?
14+ |= csv=(list (list @t))
15+ ^- ?
16+ =/ result
17+ %+ roll csv
18+ |= [row=(list @t) =flag ref=(unit @ud)]
19+ ?. flag
20+ [flag ref]
21+ ?~ ref
22+ [flag `(lent row)]
23+ ?. =(u.ref (lent row))
24+ [%.n ref]
25+ [flag ref]
26+ flag.result
27+++ en-csv :: csv -> atom (to mime)
28+ |= csv=(list (list @t))
29+ |^ ^- @t
30+ (cat 3 (crip (join '\0a' (turn csv en-row))) '\0a')
31+ ++ en-row :: encode row
32+ |= row=(list @t)
33+ ^- @t
34+ (crip (join ',' (turn row en-field)))
35+ ++ en-field :: encode field
36+ |= field=@t
37+ ^- @t
38+ %+ rash
39+ field
40+ %+ cook
41+ |= =tape
42+ ^- @t
43+ ?~ tape ''
44+ ?: =('"' i.tape)
45+ (cat 3 (crip tape) '"')
46+ (crip tape)
47+ ;~ pose
48+ (full (star ;~(less (mask "\",\0a\0d") next)))
49+ ;~ plug
50+ (easy '"')
51+ (star ;~(pose (cold '""' doq) next))
52+ ==
53+ ==
54+ --
55+++ de-csv :: atom -> csv (from mime)
56+ |= dat=@t
57+ |^ ^- (list (list @t))
58+ =/ parsed (parse dat)
59+ ?. (validate parsed)
60+ ~|(%mixed-col-count !!)
61+ parsed
62+ ++ parse :: parse cord
63+ |= dat=@t
64+ |^ ^- (list (list @t))
65+ %+ rash
66+ dat
67+ %+ most
68+ ;~(pose (jest '\0d\0a') (mask "\0a\0d"))
69+ (most com parse-field)
70+ ++ parse-field :: parse field from cord
71+ |^
72+ %+ cook
73+ |=(a=tape (crip a))
74+ ;~(pose unenclosed enclosed)
75+ ++ unenclosed :: unquoted field
76+ ;~ sfix
77+ (star ;~(less (mask "\",\0a\0d") next))
78+ ;~ pose
79+ ;~ plug
80+ ;~(pose (jest '\0d\0a') (mask "\0a\0d"))
81+ ;~(less next (easy ~))
82+ ==
83+ ;~(less doq (easy ~))
84+ ==
85+ ==
86+ ++ enclosed :: quoted field
87+ |^
88+ ;~ sfix
89+ (ifix [prefix suffix] content)
90+ ;~ pose
91+ ;~(simu (mask ",\0a\0d") (easy ~))
92+ ;~ plug
93+ ;~(pose (jest '\0d\0a') (mask "\0a\0d"))
94+ ;~(less next (easy ~))
95+ ==
96+ ;~(less next (easy ~))
97+ ==
98+ ==
99+ ++ content :: quoted field contents
100+ %- star
101+ ;~ pose
102+ (cold '"' (jest '""'))
103+ %+ cold '\0a'
104+ ;~(pose (jest '\0d\0a') (just '\0d'))
105+ ;~(less doq next)
106+ ==
107+ ++ prefix ;~(pose ;~(plug (star ace) doq) doq) :: quoted field prefix
108+ ++ suffix ;~(pose ;~(plug doq (star ace)) doq) :: quoted field suffix
109+ --
110+ --
111+ --
112+ --
113+++ csv-join
114+ |= [ali=(urge:clay (list @t)) bob=(urge:clay (list @t))]
115+ ^- (unit (urge:clay (list @t)))
116+ |^
117+ =. ali (clean ali)
118+ =. bob (clean bob)
119+ |- ^- (unit (urge:clay (list @t)))
120+ ?~ ali `bob
121+ ?~ bob `ali
122+ ?- -.i.ali
123+ %&
124+ ?- -.i.bob
125+ %&
126+ ?: =(p.i.ali p.i.bob)
127+ %+ bind $(ali t.ali, bob t.bob)
128+ |=(cud=(urge:clay (list @t)) [i.ali cud])
129+ ?: (gth p.i.ali p.i.bob)
130+ %+ bind $(p.i.ali (sub p.i.ali p.i.bob), bob t.bob)
131+ |=(cud=(urge:clay (list @t)) [i.bob cud])
132+ %+ bind $(ali t.ali, p.i.bob (sub p.i.bob p.i.ali))
133+ |=(cud=(urge:clay (list @t)) [i.ali cud])
134+ ::
135+ %|
136+ ?: =(p.i.ali (lent p.i.bob))
137+ %+ bind $(ali t.ali, bob t.bob)
138+ |=(cud=(urge:clay (list @t)) [i.bob cud])
139+ ?: (gth p.i.ali (lent p.i.bob))
140+ %+ bind $(p.i.ali (sub p.i.ali (lent p.i.bob)), bob t.bob)
141+ |=(cud=(urge:clay (list @t)) [i.bob cud])
142+ ~
143+ ==
144+ ::
145+ %|
146+ ?- -.i.bob
147+ %|
148+ ?. =(i.ali i.bob)
149+ ~
150+ %+ bind $(ali t.ali, bob t.bob)
151+ |=(cud=(urge:clay (list @t)) [i.ali cud])
152+ ::
153+ %&
154+ ?: =(p.i.bob (lent p.i.ali))
155+ %+ bind $(ali t.ali, bob t.bob)
156+ |=(cud=(urge:clay (list @t)) [i.ali cud])
157+ ?: (gth p.i.bob (lent p.i.ali))
158+ %+ bind $(ali t.ali, p.i.bob (sub p.i.bob (lent p.i.ali)))
159+ |=(cud=(urge:clay (list @t)) [i.ali cud])
160+ ~
161+ ==
162+ ==
163+ ++ clean :: clean
164+ |= wig=(urge:clay (list @t))
165+ ^- (urge:clay (list @t))
166+ ?~ wig ~
167+ ?~ t.wig wig
168+ ?: ?=(%& -.i.wig)
169+ ?: ?=(%& -.i.t.wig)
170+ $(wig [[%& (add p.i.wig p.i.t.wig)] t.t.wig])
171+ [i.wig $(wig t.wig)]
172+ ?: ?=(%| -.i.t.wig)
173+ $(wig [[%| (welp p.i.wig p.i.t.wig) (welp q.i.wig q.i.t.wig)] t.t.wig])
174+ [i.wig $(wig t.wig)]
175+ --
176+--
177+```
178+
179+## `/mar/csv/hoon`
180+
181+```hoon
182+/+ *csv
183+|_ csv=(list (list @t))
184+++ grab
185+ |%
186+ ++ mime |=((pair mite octs) (de-csv q.q))
187+ ++ noun
188+ |= n=*
189+ ^- (list (list @t))
190+ =/ result ((list (list @t)) n)
191+ ?> (validate result)
192+ result
193+ --
194+++ grow
195+ |%
196+ ++ mime
197+ ?> (validate csv)
198+ [/text/csv (as-octs:mimes:html (en-csv csv))]
199+ ++ noun
200+ ?> (validate csv)
201+ csv
202+ --
203+++ grad
204+ |%
205+ ++ form %csv-diff
206+ ++ diff
207+ |= bob=(list (list @t))
208+ ^- (urge:clay (list @t))
209+ ?> (validate csv)
210+ ?> (validate bob)
211+ (lusk:differ csv bob (loss:differ csv bob))
212+ ++ pact
213+ |= dif=(urge:clay (list @t))
214+ ^- (list (list @t))
215+ =/ result (lurk:differ csv dif)
216+ ?> (validate result)
217+ result
218+ ++ join
219+ |= $: ali=(urge:clay (list @t))
220+ bob=(urge:clay (list @t))
221+ ==
222+ ^- (unit (urge:clay (list @t)))
223+ (csv-join ali bob)
224+ ++ mash
225+ |= $: [ship desk (urge:clay (list @t))]
226+ [ship desk (urge:clay (list @t))]
227+ ==
228+ ^- (urge:clay (list @t))
229+ ~|(%csv-mash !!)
230+ --
231+--
232+```
233+
234+## `/mar/csv-diff/hoon`
235+
236+```hoon
237+|_ dif=(urge:clay (list @t))
238+++ grab
239+ |%
240+ ++ noun (urge:clay (list @t))
241+ --
242+++ grow
243+ |%
244+ ++ noun dif
245+ --
246+++ grad %noun
247+--
248+```
content/docs/arvo/clay/marks/marks.mdnew file+59
@@ -0,0 +1,59 @@
1++++
2+title = "Overview"
3+weight = 1
4+template = "doc.html"
5++++
6+
7+Clay is a typed filesystem, and we call these file types `mark`s. When talking about Hoon and Arvo we'll often talk of types like `@ud`, `(list @t)`, etc. A `mark` will specify such a type for its files, but it does more than just that - it also defines conversion routines to and from other `mark`s, as well as diff, patch, and merge routines.
8+
9+For example, a `%txt` `mark` defines the type of a `%txt` file as a `wain` (a `(list @t)`). It defines a conversion function to a `%mime` `mark` to allow it to be serialized and sent to a browser or to the Unix filesystem. It also includes Hunt-McIlroy diff, patch, and merge algorithms. Conversion functions will be different for different `mark`s, as will things like diff algorithms. An image file like a `%png`, for example, just replaces the old blob of data with the new one rather than implementing a complex binary diff and patch algorithm, so how these functions are implemented depends on the file type and use case.
10+
11+`mark` files are stored in the `/mar` directory. The `path` of the `%txt` `mark`, for example, is `/mar/txt/hoon`.
12+
13+A `mark` is a door (a core with a sample) with three arms: `+grab`, `+grow`, and `+grad`. The door's sample defines its type. In `+grab` is a series of functions to convert from other `mark`s to the given `mark`. In `+grow` is a series of functions to convert from the given `mark` to other `mark`s. In `+grad` is `+diff`, `+pact`, `+join`, `+mash`, and `+form`.
14+
15+Here's its basic structure in an informal pseudocode:
16+
17+```
18+|_ <mark-type>
19+++ grab:
20+ ++ noun: <noun> -> <mark-type>
21+ ++ mime: <mime> -> <mark-type>
22+ ++ txt: <txt> -> <mark-type>
23+ ...
24+++ grow:
25+ ++ noun: <mark-type> -> <noun>
26+ ++ mime: <mark-type> -> <mime>
27+ ++ txt: <mark-type> -> <txt>
28+ ...
29+++ grad
30+ ++ form: <diff-mark>
31+ ++ diff: (<mark-type>, <mark-type>) -> <diff-type>
32+ ++ pact: (<mark-type>, <diff-type>) -> <mark-type>
33+ ++ join: (<diff-type>, <diff-type>) -> <diff-type> or NULL
34+ ++ mash: (<diff-type>, <diff-type>) -> <diff-type>
35+```
36+
37+These types are basically what you would expect. In `+grab`, only a `+noun` arm is mandatory, the rest are optional. The `+grow` arm itself is optional, as are any arms within it. In `+grad`, all arms are mandatory unless revision control is delegated to another `mark`, which we'll discuss later.
38+
39+In general, for a particular `mark`, the `+grab` and `+grow` entries should be inverses of each other. They needn't be symmetrical though - you may want to be able to convert from your `mark` to `%json` but not from `%json` to your `mark`, for example.
40+
41+In `+grad`, `+diff` takes two instances of a `mark` and produces a diff of them whose `mark` is given by `+form`. `+pact` takes an instance of a `mark` and patches it with the given diff. In general, if `+diff` called with A and B produces diff D, then `+pact` called with A and D should produce B.
42+
43+`+join` takes two diffs and attempts to merge them into a single diff. If there are conflicts, it produces null. `+mash` takes two diffs and forces a merge, even if there are conflicts. How your `+mash` function force-merges conflicting diffs is up to you. The `%txt` `mark` annotates any conflicts, for example, but there may be other ways. If `+join` of two diffs does not produce null, then `+mash` of the same diffs should produce the same result. Note that `+mash` is not used by Clay in its ordinary filesystem operations, so you may wish to leave it as a dummy arm that crashes if called.
44+
45+Alternately, instead of `+form`, `+diff`, `+pact`, `+join`, and `+mash`, a `mark` can provide the same functionality by defining `+grad` to be the name of another `mark` to which we wish to delegate the revision control responsibilities. Then, before running any of those functions, Clay will convert to the other `mark`, and convert back afterward. For example, the `%hoon` `mark` is revision-controlled in the same way as `%txt`, so its `+grad` is simply `++ grad %txt`. Of course, `+txt` must be defined in `+grow` and `+grab` as well.
46+
47+We mentioned that `+noun` is the only mandatory arm in `+grab`, but there are a couple of others that, while not mandatory, are of particular interest.
48+
49+The first is a `+mime` arm for converting to and from the `%mime` `mark`. When you `|commit` a file to a `desk` mounted to Unix, Clay will receive the data as a `%mime` `mark`, and then convert it to the `mark` matching the file extension. It will perform the same operation in reverse when mounting a `desk` to Unix. For this reason, any `mark` you wish to be able to access from the Unix filesystem should have `%mime` conversion routines. In certain cases (such as the scry interface), Eyre will also need to convert your `mark` to a `%mime` in order to encode it in an HTTP response, so you may require a `+mime` arm for that reason as well.
50+
51+The second case of interest is the `+json` arm for converting to and from a `%json` `mark`. If, for example, you want to write a Gall agent to which you can subscribe through Eyre's channel system, it must produce data with a `mark` containing `%json` conversion routines. If it doesn't, Eyre will not be able to deliver the data to the subscribed HTTP client in the SSE stream.
52+
53+## Sections
54+
55+[Writing Marks](/docs/arvo/clay/marks/writing-marks) - A practical walk-through of writing a `mark` file.
56+
57+[Using Marks](/docs/arvo/clay/marks/using-marks) - Details of using `mark` conversion gates and `mark` cores in your own code.
58+
59+[Examples](/docs/arvo/clay/marks/examples) - The example code used in the Writing Marks guide.
content/docs/arvo/clay/marks/using-marks.mdnew file+240
@@ -0,0 +1,240 @@
1++++
2+title = "Using Marks"
3+weight = 3
4+template = "doc.html"
5++++
6+
7+In the last document, [Writing Marks](/docs/arvo/clay/marks/writing-marks), we walked through writing `mark` files and touched on how Clay handles them. They needn't just be left to background vane processes though, you can also use them yourself in your code.
8+
9+There are two kinds of cores that Clay can build for you: A `mark` conversion gate and a `mark` core. Each has two kinds: Statically typed and dynamically typed. Clay has a `care` for producing each of these:
10+
11+- `%b` - Build a dynamically typed `mark` core.
12+- `%c` - Build a dynamically typed `mark` conversion gate.
13+- `%e` - Build a statically typed `mark` core.
14+- `%f` - Build a statically typed `mark` conversion gate.
15+
16+You can either use these by `%pass`ing Clay a [%warp task](/docs/arvo/clay/tasks#warp) with the appropriate `care`, or else with a [Clay scry](/docs/arvo/clay/scry). In the examples here we've used the latter.
17+
18+## mark conversion gates
19+
20+`mark` conversion gates simply convert from one `mark` to another.
21+
22+### Static
23+
24+A static `mark` conversion gate looks like `$-(a b)`, where `a` is the type of the `mark` you're converting _from_, and `b` is type of the `mark` you're converting _to_. For example, a `mark` conversion gate from `%txt` to `%mime` would look like `$-(wain mime)`. You'd simply feed it a `wain` and get a `$mime` in return.
25+
26+#### Example
27+
28+We get our `%txt` to `%mime` `mark` conversion gate with a `%f` scry like so:
29+
30+```
31+> =txt-to-mime .^($-(wain mime) %cf /===/txt/mime)
32+```
33+
34+Note we had to specify the type of the gate as `$-(wain mime)` in the scry - if the type returned by the scry doesn't match that specification it'll fail. This is where a statically typed `mark` conversion gate differs from the dynamically typed gate, which we'll discuss later.
35+
36+Now that we have our conversion gate, we can just call it with a valid `wain` and we'll get our `$mime` in return:
37+
38+```
39+> (txt-to-mime ~['foo'])
40+[p=/text/plain q=[p=3 q=7.303.014]]
41+```
42+
43+### Dynamic
44+
45+A dynamically typed `mark` conversion gate is called a `$tube:clay`, and looks like:
46+
47+```hoon
48++$ tube $-(vase vase)
49+```
50+
51+As you can see from the type definition, it takes and returns a `vase` rather than needing the types explicitly defined. Rather than failing on a type mismatch when the scry is performed, it'll instead fail when it's actually run and fed a `vase` of the wrong type. Apart from handling `vase`s, it otherwise behaves the same as a statically typed `mark` conversion gate.
52+
53+#### Example
54+
55+We get our `%txt` to `%mime` `$tube` with a `%c` scry like so:
56+
57+```
58+> =txt-mime-tube .^(tube:clay %cc /===/txt/mime)
59+```
60+
61+And then we can again feed it the `wain` that a `%txt` `mark` wants, only this time it's wrapped in a `vase`:
62+
63+```
64+> !< mime (txt-mime-tube !>(~['foo']))
65+[p=/text/plain q=[p=3 q=7.303.014]]
66+```
67+
68+We then get our `$mime` back, but also in a `vase`.
69+
70+## mark cores
71+
72+While a `mark` conversion gate is built from functions defined in `+grab` and `+grow`, a `mark` core gives you everything in `+grad` so you can create diffs, merge diffs, patch files, etc. An extra arm `+vale` is also included that lets you convert a `noun` to the type the `%mark` takes by running the `+noun` arm of `+grab` in the original `mark` file.
73+
74+### Static
75+
76+A statically typed `mark` core is a `(nave:clay a b)` where `a` is the type of the `mark` and `b` is the type for diffs (which is the type of the `mark` specified in `+form:grad`). For example, a static `mark` core for a `%txt` `mark` looks like `(nave:clay wain (urge:clay cord))`.
77+
78+`+nave:clay` looks like this in full:
79+
80+```hoon
81+++ nave
82+ |$ [typ dif]
83+ $_
84+ ^?
85+ |%
86+ ++ diff |~([old=typ new=typ] *dif)
87+ ++ form *mark
88+ ++ join |~([a=dif b=dif] *(unit (unit dif)))
89+ ++ mash
90+ |~ [a=[ship desk dif] b=[ship desk dif]]
91+ *(unit dif)
92+ ++ pact |~([typ dif] *typ)
93+ ++ vale |~(noun *typ)
94+ --
95+```
96+
97+In brief, the arms of the core do the following:
98+
99+- `+form` - `mark` for diffs.
100+- `+vale` - Clam `noun` to the `mark`'s type.
101+- `+diff` - Create diff of two files.
102+- `+pact` - Patch a file with a diff.
103+- `+join` - Merge two diffs, returning `~` if there's a conflict.
104+- `+mash` - Force merge of two diffs.
105+
106+#### Examples
107+
108+First we get the `%txt` `mark` core with a `%e` scry:
109+
110+```
111+> =txt-nave .^((nave:clay wain (urge:clay cord)) %ce /===/txt)
112+```
113+
114+Note we specified the `mark` type `wain` and diff type `(urge:clay cord)` in the `nave` returned by the scry.
115+
116+We can see the `mark` for diffs with `+form`:
117+
118+```
119+> form.txt-nave
120+%txt-diff
121+```
122+
123+To clam a noun to the type of the `mark` (a `wain` in the case of a `%txt` `mark`), we can call `+vale` with a `noun`:
124+
125+```
126+> (vale:txt-nave ~['foo' 'bar'])
127+<|foo bar|>
128+```
129+
130+We can create a diff of two files with `+diff`:
131+
132+```
133+> (diff:txt-nave ~['foo' 'bar' 'baz'] ~['foo' 'zoo' 'baz'])
134+~[[%.y p=1] [%.n p=<|bar|> q=<|zoo|>] [%.y p=1]]
135+```
136+
137+Let's create some more diffs for experimentation:
138+
139+```
140+> =diff-a (diff:txt-nave ~['foo' 'bar' 'baz'] ~['foo' 'zoo' 'baz'])
141+> =diff-b (diff:txt-nave ~['foo' 'bar' 'baz'] ~['zap' 'bar' 'baz'])
142+> =diff-c (diff:txt-nave ~['foo' 'bar' 'baz'] ~['foo' 'bla' 'baz'])
143+```
144+
145+If we try merging diffs `a` and `b` with `+join`, we get a new merged diff back in a `unit`:
146+
147+```
148+> (join:txt-nave diff-a diff-b)
149+[~ [~ ~[[%.n p=<|foo|> q=<|zap|>] [%.n p=<|bar|> q=<|zoo|>] [%.y p=1]]]]
150+```
151+
152+If we try merging diffs `a` and `c` however, we get `~` because of a conflict:
153+
154+```
155+> (join:txt-nave diff-a diff-c)
156+[~ ~]
157+```
158+
159+If we run `+mash` on `a` and `b` we get the same diff as with `+join` (sans the `unit`):
160+
161+```
162+> (mash:txt-nave [our %home diff-a] [our %blah diff-b])
163+[~ ~[[%.n p=<|foo|> q=<|zap|>] [%.n p=<|bar|> q=<|zoo|>] [%.y p=1]]]
164+```
165+
166+If we `+mash` `a` and `c`, however, we get a diff with the conflict annotated rather than just `~`:
167+
168+```
169+> (mash:txt-nave [our %home diff-a] [our %blah diff-c])
170+[ ~
171+ ~[
172+ [%.y p=1]
173+ [ %.n
174+ p=<|bar|>
175+ q
176+ <|>>>>>>>>>>>> ~zod/home zoo ++++++++++++ bar ------------ bla <<<<<<<<<<<< ~zod/blah|>
177+ ]
178+ [%.y p=1]
179+ ]
180+]
181+```
182+
183+Note that the `%txt` `mark` annotates conflicts, but there are no specific rules around how the `+mash` arm should force-merge conflicting diffs apart from that it must return a valid diff, however the `mark` specified in `+form` defines that.
184+
185+Finally, we can patch our `wain` with diff `a` and get a new, modified `wain`:
186+
187+```
188+> (pact:txt-nave ~['foo' 'bar' 'baz'] diff-a)
189+<|foo zoo baz|>
190+```
191+
192+### Dynamic
193+
194+A dynamically typed `mark` core is a `$dais:clay`, which looks like:
195+
196+```hoon
197++$ dais
198+ $_ ^|
199+ |_ sam=vase
200+ ++ diff |~(new=_sam *vase)
201+ ++ form *mark
202+ ++ join |~([a=vase b=vase] *(unit (unit vase)))
203+ ++ mash
204+ |~ [a=[ship desk diff=vase] b=[ship desk diff=vase]]
205+ *(unit vase)
206+ ++ pact |~(diff=vase sam)
207+ ++ vale |~(noun sam)
208+ --
209+```
210+
211+It has the same arms as the statically typed `mark` core, the difference is that it takes and returns `vase`s rather than the data directly. Additionally, it's a door rather than an ordinary core, and takes the type of the `mark` wrapped in a `vase` as its argument.
212+
213+#### Examples
214+
215+We can get a `%txt` `mark` `dais` with a `%b` scry:
216+
217+```
218+> =txt-dais .^(dais:clay %cb /===/txt)
219+```
220+
221+Its `+form` arm functions the same as a static core:
222+
223+```
224+> form.txt-dais
225+%txt-diff
226+```
227+
228+So does `+vale` except it returns a `vase`:
229+
230+```
231+> !< wain (vale:txt-dais ~['foo' 'bar'])
232+<|foo bar|>
233+```
234+
235+All the other arms also deal in `vase`s. Because it's a door, the `+pact` and `+diff` arms take the original file in a `vase` as the door sample rather than being given directly to the arm. Calling `+diff` arm, for example, works like so:
236+
237+```
238+> !< (urge:clay cord) (~(diff txt-dais !>(~['foo' 'bar'])) !>(~['foo' 'baz']))
239+~[[%.y p=1] [%.n p=<|bar|> q=<|baz|>]]
240+```
content/docs/arvo/clay/marks/writing-marks.mdnew file+333
@@ -0,0 +1,333 @@
1++++
2+title = "Writing Marks"
3+weight = 2
4+template = "doc.html"
5++++
6+
7+Here we'll walk through a practical example of writing a `mark` file.
8+
9+We'll create a `mark` for CSV (comma separated values) files, a simple format for storing tabular data in a text file. Note that there's already a `csv.hoon` `mark` and library, but we'll create new ones for demonstrative purposes. It shouldn't be an issue to overwrite the existing ones on a fakezod.
10+
11+CSV files separate fields with commas and rows with line breaks. They look something like:
12+
13+```
14+foo,bar,baz
15+blah,blah,blah
16+1,2,3
17+```
18+
19+There is a little complexity surrounding special characters in fields and line endings, but otherwise the only other rule is that all rows must have the same number of fields. You can refer to [RFC4180 on the IETF website](https://datatracker.ietf.org/doc/html/rfc4180) for more details.
20+
21+We'll represent such a structure in Hoon as a `(list (list @t))` like:
22+
23+```hoon
24+[['foo' 'bar' 'baz' ~] ['blah' 'blah' 'blah' ~] ['1' '2' '3' ~] ~]
25+```
26+
27+We could perhaps create the type with a `$|` rune to include row-length validation in the mold itself, but a `(list (list @t))` is simpler for demonstrative purposes.
28+
29+## A simple mark
30+
31+Let's begin with the simplest `mark` file:
32+
33+```hoon
34+|_ csv=(list (list @t))
35+++ grab
36+ |%
37+ ++ noun (list (list @t))
38+ --
39+++ grow
40+ |%
41+ ++ noun csv
42+ --
43+++ grad %noun
44+--
45+```
46+
47+The door takes a `(list (list @t))` as its sample, and we've given it a face of `csv` so we can easily reference it. Note its face could be anything, it needn't be the name of our `mark`. When we're doing something with data that has a `%csv` `mark` like converting it to another `mark` or creating a diff, this is where our data will reside.
48+
49+Next we have the `+grab` arm of our door, which contains a core with arms for converting _to_ our `mark` _from_ other `mark`s. We've given it one arm for the `%noun` `mark` - the most generic `mark` which will take any `noun`. Our `+noun` arm will simply clam whatever it's given with the `(list (list @t))` `mold`.
50+
51+Next is the `+grow` arm which does the inverse of `+grab`, converting _from_ our `mark` _to_ another `mark`. We've also given it a `+noun` arm, this time it will simply return the door's sample named `csv`, which is of course already a `noun`.
52+
53+Note that the `+noun` arm is _mandatory_ in `+grab`. Clay cannot build a `mark` core without it. Conversion arms for any other `mark`s apart from `%noun` are optional.
54+
55+Finally we have the `+grad` arm. This arm specifies functions for revision control like creating diffs, patching files and so on. In our case, rather than writing all those functions, we've just delegated those tasks to the `%noun` `mark`. We can do this because we've specified conversion routines to and from the `%noun` `mark` in our `+grow` and `+grab` arms. When we modify a file with a `%csv` `mark`, Clay will convert our data to a `%noun` `mark`, execute the necessary `+grad` functions from the `%noun` `mark` file, and then convert it back to a `%csv` `mark` again.
56+
57+So now we have a valid `%csv` `mark` file. If we save this as `csv.hoon` in the `/mar` directory we could store `%csv` data in Clay. This may be sufficient for some applications, but what if we want to import a CSV file from Unix or elsewhere? In the next section, we'll look at conversions to and from a `%mime` `mark` to address this.
58+
59+## `%mime` conversions
60+
61+The `$mime` type represents raw data from Unix or elsewhere. For example, if a text file from Unix containing the word `foo` were converted to a `$mime` type in Urbit, it would look something like:
62+
63+```hoon
64+[/text/plain q=[p=3 q=7.303.014]]
65+```
66+
67+`/text/plain` is its [MIME type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) and `p.q` is the byte-length of `q.q`, which is the data itself as an `atom`.
68+
69+The `%mime` `mark` is used by Clay to store and convert `$mime` data. It's an important `mark` for moving files from Unix to Urbit and vice versa. When you add a file to a `desk` you have mounted to Unix and `|commit` the change, Clay will first receive the file as a `%mime` `mark`, then convert from a `%mime` to whatever `mark` matches the file extension. For example, `foo.txt` will be converted from `%mime` to `%txt`. Additionally, data fetched by Iris over HTTP will come in as a `$mime-data:http`, which is an unvalidated form of `$mime` that you may wish to convert to a `%mime` `mark` and then to another `mark`. Likewise with Eyre, some of the lower-level interfaces receive HTTP requests with `$mime-data:http` in them.
70+
71+So with the nature of the `%mime` `mark` hopefully now clear, the reason we want conversion methods to and from `%mime` in our `%csv` `mark` is so we can import CSV files from Unix and vice versa.
72+
73+Since a CSV file on Unix will just be a long string with ASCII or UTF-8 encoding, we can treat `q.q` in the `$mime` as a `cord`, and thus write a parser to convert it to a `(list (list @t))`. For this purpose, here's a library: `csv.hoon`, which you can view in full on the [Examples](/docs/arvo/clay/marks/examples#libcsvhoon) page.
74+
75+The library contains four functions:
76+
77+- `+de-csv` - Parse a CSV `cord` to a `(list (list @t))`.
78+- `+en-csv` - Encode a `(list (list @t))` as a CSV `cord`.
79+- `+validate` - Check all rows of `(list (list @t))` are the same length.
80+- `+csv-join` - Ignore this for now, we'll use it later on.
81+
82+The decoding and encoding arms use parsing functions from the Hoon standard library. It's not important to be familiar with parsing in Hoon for our purposes here, but you can have a look at the [Parsing Guide](/docs/hoon/guides/parsing) in the Hoon documentation if you're interested. The important thing to note is that `+de-csv` takes a valid CSV-format `@t` and returns a `(list (list @t))`, and `+en-csv` does the reverse - it takes a `(list (list @t))` and returns a CSV-format `@t`.
83+
84+Let's try the library in the dojo. After we've added it to `/lib` and run `|commit`, we can build the file:
85+
86+```
87+> =csv -build-file %/lib/csv/hoon
88+```
89+
90+...try decode a CSV-format `@t`:
91+
92+```
93+> (de-csv:csv 'foo,bar,baz\0ablah,blah,blah\0a1,2,3')
94+~[<|foo bar baz|> <|blah blah blah|> <|1 2 3|>]
95+```
96+
97+...and try encode a `(list (list @t))` as a CSV-format `@t`:
98+
99+```
100+> (en-csv:csv [['foo' 'bar' 'baz' ~] ['blah' 'blah' 'blah' ~] ['1' '2' '3' ~] ~])
101+'foo,bar,baz\0ablah,blah,blah\0a1,2,3\0a'
102+```
103+
104+With that working, we can add an import for our library to our `%csv` `mark` defintion and add a `+mime` arm to both our `+grab` and `+grow` arms:
105+
106+```hoon
107+/+ *csv
108+|_ csv=(list (list @t))
109+++ grab
110+ |%
111+ ++ mime |=((pair mite octs) (de-csv q.q))
112+ ++ noun
113+ |= n=*
114+ ^- (list (list @t))
115+ =/ result ((list (list @t)) n)
116+ ?> (validate result)
117+ result
118+ --
119+++ grow
120+ |%
121+ ++ mime
122+ ?> (validate csv)
123+ [/text/csv (as-octs:mimes:html (en-csv csv))]
124+ ++ noun
125+ ?> (validate csv)
126+ csv
127+ --
128+++ grad %noun
129+--
130+```
131+
132+In `+grab` we've added a `+mime` arm to convert _from_ a `%mime` `mark` _to_ our `%csv` `mark`. It's a simple gate that takes a `$mime` (specified as `(pair mite octs)` to avoid conflict with the arm name), runs the data through the `+de-csv` function and returns a `(list (list @t))` of the CSV data.
133+
134+We've also added a `+mime` arm to `+grow` for converting _from_ our `%csv` `mark` _to_ a `%mime` `mark`. We encode our `(list (list @t))` `csv` sample with our `+en-csv` function and then run that through `as-octs:mimes:html` to get a `$octs` (so it has the byte-length). We also add the `/text/csv` MIME type so it's a valid `$mime`.
135+
136+Additionally, we've used the `+validate` function in a few places to make sure our CSV data has consistent row lengths.
137+
138+If we save the above mark file as `csv.hoon` in `/mar` and `|commit %home`, we should now be able to import CSV files into Urbit. Let's give it a go. In the root of our `%home` `desk`, let's add a file named `foo.csv` with the following contents:
139+
140+```
141+foo,bar,baz
142+blah,blah,blah
143+1,2,3
144+```
145+
146+If we now `|commit %home`, we should see it's been successfully added:
147+
148+```
149+> |commit %home
150+>=
151++ /~zod/home/4/foo/csv
152+```
153+
154+And if we try reading the file with the `-read` thread:
155+
156+```
157+> -read [%x our %home da+now /foo/csv]
158+~[<|foo bar baz|> <|blah blah blah|> <|1 2 3|>]
159+```
160+
161+We can see our `%csv` `mark` has successfully converted our `foo.csv` file to a `(list (list @t))` when it was imported.
162+
163+Let's try the other direction now. We can create a new `bar.csv` files in the root of `%home` from the dojo like so:
164+
165+```
166+> */bar/csv ~[['abc' 'def' ~] ['ghi' 'jkl' ~]]
167++ /~zod/home/5/bar/csv
168+```
169+
170+And if we check it in the terminal on the Unix side we can see it's been correctly encoded:
171+
172+```
173+> cat zod/home/bar.csv
174+abc,def
175+ghi,jkl
176+```
177+
178+So now our `%csv` `mark` lets us move data in and out of Urbit. In the next section, we'll look at the `+grad` arm in more detail.
179+
180+## `+grad`
181+
182+So far we've just delegated `+grad` functions to the `%noun` `mark`, but now we'll look at writing our own.
183+
184+For demonstrative purposes, we can just poach the algorithms used in the `+grad` arm of the `%txt` `mark` and modify them to take our `(list (list @t))` type instead of a `wain`. It's not the most efficient algorithm for a CSV file but it'll do the job.
185+
186+Our diff format will be a `(urge:clay (list @t))`, and we'll use some `differ` functions from `zuse.hoon` like `+loss`, `+lusk` and `+lurk` to produce diffs and apply patches.
187+
188+The [csv.hoon library](/docs/arvo/clay/marks/examples#libcsvhoon) we imported also contains a `+csv-join` function which we'll use in the `+join` arm, just to save space here.
189+
190+Here's the new `%csv` `mark` defintion:
191+
192+```hoon
193+/+ *csv
194+|_ csv=(list (list @t))
195+++ grab
196+ |%
197+ ++ mime |=((pair mite octs) (de-csv q.q))
198+ ++ noun
199+ |= n=*
200+ ^- (list (list @t))
201+ =/ result ((list (list @t)) n)
202+ ?> (validate result)
203+ result
204+ --
205+++ grow
206+ |%
207+ ++ mime
208+ ?> (validate csv)
209+ [/text/csv (as-octs:mimes:html (en-csv csv))]
210+ ++ noun
211+ ?> (validate csv)
212+ csv
213+ --
214+++ grad
215+ |%
216+ ++ form %csv-diff
217+ ++ diff
218+ |= bob=(list (list @t))
219+ ^- (urge:clay (list @t))
220+ ?> (validate csv)
221+ ?> (validate bob)
222+ (lusk:differ csv bob (loss:differ csv bob))
223+ ++ pact
224+ |= dif=(urge:clay (list @t))
225+ ^- (list (list @t))
226+ =/ result (lurk:differ csv dif)
227+ ?> (validate result)
228+ result
229+ ++ join
230+ |= $: ali=(urge:clay (list @t))
231+ bob=(urge:clay (list @t))
232+ ==
233+ ^- (unit (urge:clay (list @t)))
234+ (csv-join ali bob)
235+ ++ mash
236+ |= $: [ship desk (urge:clay (list @t))]
237+ [ship desk (urge:clay (list @t))]
238+ ==
239+ ^- (urge:clay (list @t))
240+ ~|(%csv-mash !!)
241+ --
242+--
243+```
244+
245+In our modified `+grad` arm, we've replaced the `%noun` delegation with a core containing five arms: `+form`, `+diff`, `+pact`, `+join`, and `+mash`. These arms are all required for a valid `+grad` if it's not delegated to another `mark`. We'll now look at each in detail.
246+
247+### `+form`
248+
249+```hoon
250+++ form %csv-diff
251+```
252+
253+`+form` simply specifies the `mark` of the diff file that may be produced by other `+grad` functions. If your diff is the same type as your `mark`, it could just specify itself like `%csv`. In our case our diff is a `(urge:clay (list @t))` rather than a `(list (list @t))`, so we need a separate mark file for the diff itself.
254+
255+Here's another `mark` file which can be saved as `csv-diff.hoon` in `/mar`:
256+
257+```hoon
258+|_ dif=(urge:clay (list @t))
259+++ grab
260+ |%
261+ ++ noun (urge:clay (list @t))
262+ --
263+++ grow
264+ |%
265+ ++ noun dif
266+ --
267+++ grad %noun
268+--
269+```
270+
271+It's very bare-bones, we just need it for our `%csv` `mark` to work. In our `%csv` `mark`, we've specified it as `%csv-diff` in `+form`.
272+
273+### `+diff`
274+
275+```hoon
276+++ diff
277+ |= bob=(list (list @t))
278+ ^- (urge:clay (list @t))
279+ ?> (validate csv)
280+ ?> (validate bob)
281+ (lusk:differ csv bob (loss:differ csv bob))
282+```
283+
284+This arm produces the diff of two `%csv` files. The first `%csv` file will be given as the sample of the parent door, which if you'll recall we gave a face of `csv`. The second `%csv` file will be given as the sample of the gate in `+diff`, which we've named `bob` here. We then just produce the diff of these two files and return it as the type of the mark specified in `+form`, which in our case is `(urge:clay (list @t))` for a `%csv-diff`. Clay will use `+diff` when a file is revised, so it doesn't have to store a whole new copy of the file each time it's modified.
285+
286+### `+pact`
287+
288+```hoon
289+++ pact
290+ |= dif=(urge:clay (list @t))
291+ ^- (list (list @t))
292+ =/ result (lurk:differ csv dif)
293+ ?> (validate result)
294+ result
295+```
296+
297+`+pact` patches a `%csv` file with the given diff. Its gate takes a diff and applies it to the `%csv` given as the sample of the parent door (which we gave a face of `csv`). If the patch succeeds, it will return a new `%csv` file - a valid `(list (list @t))`. When we read a file that's been modified in Clay, Clay will apply all the diffs it has with `+pact` and return the resulting file.
298+
299+### `+join`
300+
301+```hoon
302+++ join
303+ |= $: ali=(urge:clay (list @t))
304+ bob=(urge:clay (list @t))
305+ ==
306+ ^- (unit (urge:clay (list @t)))
307+ (csv-join ali bob)
308+```
309+
310+The `+join` arm merges two different diffs. It takes them both as the sample of its gate (which we've named `ali` and `bob`), and returns a new diff wrapped in a `unit` like `(unit (urge:clay (list @t)))`. The `unit` will be `~` if the merge failed due to a conflict. This is used by Clay in some cases when `desk`s are merged. If diff merges are not possible for your use case, you could just have it always return `~`.
311+
312+### `+mash`
313+
314+```hoon
315+++ mash
316+ |= $: [ship desk (urge:clay (list @t))]
317+ [ship desk (urge:clay (list @t))]
318+ ==
319+ ^- (urge:clay (list @t))
320+ ~|(%csv-mash !!)
321+```
322+
323+This is like `+join` except it forces a diff merge even if there's a conflict. Rather than returning a `unit`, it just returns the diff - a `(urge:clay (list @t))` in our case. Also unlike `+join`, it takes the `ship` and `desk` each diff came from as well as the diff itself.
324+
325+The `+mash` arm is not used by Clay in its file revision operations, so it's safe to just make it a dummy arm that crashes as we've done here. If you were to use it, it would likely just be used manually in an agent, thread or generator.
326+
327+An example of its use would be the `%txt` `mark`, which includes a proper `+mash` function that produces a diff with any conflicts annotated, though how you have `+mash` handle conficts would depend on your use case. If there were no conflicts between the two diffs, it should produce the same diff as the `+join` arm.
328+
329+## Conclusion
330+
331+So there you have it, a fully functional `mark` for CSV files. A `mark` file can be as complex or as simple as you'd like, they're very flexible depending on your use case. Additional conversion methods can always be added as they're needed. For example, with just a few lines of code we could add arms for converting CSV files to `%json` or `%txt` and vice versa.
332+
333+In the next document, we'll look at building and using `mark` cores and `mark` conversion gates in our own code.
content/docs/hoon/reference/_index.md+6−3
@@ -36,15 +36,18 @@ The full story on Hoon's type system.
3636
3737A list of aura types for atoms.
3838
39−### [Runes](/docs/hoon/reference/rune/)
39+## [Runes](/docs/hoon/reference/rune/)
4040
4141Syntax and semantics for Hoon's rune system.
4242
43−### [Limbs and Wings](/docs/hoon/reference/limbs/)
43+## [Limbs and Wings](/docs/hoon/reference/limbs/)
4444
4545How to find data inside Hoon subjects.
4646
47−### [Standard Library](/docs/hoon/reference/stdlib/)
47+## [Standard Library](/docs/hoon/reference/stdlib/)
4848
4949Reference material for the Hoon standard library.
5050
51+## [Zuse](/docs/hoon/reference/zuse/)
52+
53+Reference material for the Zuse library.
content/docs/hoon/reference/rune/ket.md+12−3
@@ -63,9 +63,18 @@ Regular: **1-fixed**.
6363
6464##### Discussion
6565
66−A mold is an idempotent gate that is guaranteed to produce a noun of that type. If an input value isn't of the correct type, the bunt value of that type is returned. (See `^*`.)
67−
68−`^:` is used to produce a gate that is much like a mold, except that instead of producing a bunt value when the input value is of the wrong type, it crashes.
66+A mold is an idempotent gate that is guaranteed to produce a noun of that type.
67+If an input value isn't of the correct type, the bunt value of that type is
68+returned. (See `^*`.)
69+
70+`^:` is used to produce a gate that is much like a mold, except that instead of
71+producing a bunt value when the input value is of the wrong type, it crashes.
72+
73+One may expect that `^:(path /foo)` would result in a syntax error since `^:`
74+only takes one child, but instead it will parse as `=< ^ %:(path /foo)`. Since
75+`:` is the irregular syntax for `=<` this is is parsed as "get `^` (i.e. the
76+mold for cells) from a subject of `(path /foo)`", with `:` being the irregular
77+syntax for `=<`.
6978
7079##### Examples
7180
content/docs/hoon/reference/zuse/2d_1-5.mdnew file+587
@@ -0,0 +1,587 @@
1++++
2+title = "2d(1-5): To JSON, Wains"
3+weight = 40
4+template = "doc.html"
5++++
6+
7+## `++to-wain:format`
8+
9+Cord to line list
10+
11+Convert `txt` to a wain, breaking on newline characters.
12+
13+#### Accepts
14+
15+`txt` is a `@t`.
16+
17+#### Produces
18+
19+A `wain`, which is a `(list @t)`.
20+
21+#### Source
22+
23+```hoon
24+++ to-wain
25+ |= txt=cord
26+ ^- wain
27+ =/ len=@ (met 3 txt)
28+ =/ cut =+(cut -(a 3, c 1, d txt))
29+ =/ sub sub
30+ =| [i=@ out=wain]
31+ |- ^+ out
32+ =+ |- ^- j=@
33+ ?: ?| =(i len)
34+ =(10 (cut(b i)))
35+ ==
36+ i
37+ $(i +(i))
38+ =. out :_ out
39+ (cut(b i, c (sub j i)))
40+ ?: =(j len)
41+ (flop out)
42+ $(i +(j))
43+```
44+
45+#### Examples
46+
47+```
48+> (to-wain:format 'foo\0abar\0abaz')
49+<|foo bar baz|>
50+```
51+
52+---
53+
54+## `++of-wain:format`
55+
56+Line list to cord
57+
58+Convert `tez` to a cord, separating each line with a newline character.
59+
60+#### Accepts
61+
62+`tez` is a `wain`, which is a `(list @t)`.
63+
64+#### Produces
65+
66+A `@t`.
67+
68+#### Source
69+
70+```hoon
71+++ of-wain
72+ |= tez=wain ^- cord
73+ (rap 3 (join '\0a' tez))
74+```
75+
76+#### Examples
77+
78+```
79+> (of-wain:format ~['foo' 'bar' 'baz'])
80+'foo\0abar\0abaz'
81+```
82+
83+---
84+
85+## `++of-wall:format`
86+
87+Line list to tape
88+
89+Convert `a` to a tape, separating each line with a newline character.
90+
91+#### Accepts
92+
93+`a` is a `wall`, which is a `(list tape)`
94+
95+#### Produces
96+
97+A `tape`.
98+
99+#### Source
100+
101+```hoon
102+++ of-wall
103+ |= a=wall ^- tape
104+ ?~(a ~ "{i.a}\0a{$(a t.a)}")
105+```
106+
107+#### Examples
108+
109+```
110+> (of-wall:format ~["foo" "bar" "baz"])
111+"foo\0abar\0abaz\0a"
112+```
113+
114+---
115+
116+## `++json-rn:format`
117+
118+json to rn parser
119+
120+This function is used internally by [+ne](/docs/hoon/reference/zuse/2d_6#nedejsformat) and would not typically be used directly. It is a `rule` that parses a real number string to a `rn` in a unit.
121+
122+#### Accepts
123+
124+A `nail` containing a real number.
125+
126+#### Produces
127+
128+An `edge` containing a `(unit rn)`.
129+
130+#### Source
131+
132+```hoon
133+++ json-rn
134+ %+ knee *rn |.
135+ ;~ plug
136+ (easy %d)
137+ ;~(pose (cold | hep) (easy &))
138+ ;~ plug dim:ag
139+ ;~ pose
140+ ;~ pfix dot
141+ %+ sear
142+ |= a=tape
143+ =/ b (rust a dum:ag)
144+ ?~ b ~
145+ (some [(lent a) u.b])
146+ (plus (shim '0' '9'))
147+ ==
148+ (easy [0 0])
149+ ==
150+ ;~ pose
151+ ;~ pfix
152+ (mask "eE")
153+ ;~ plug
154+ ;~(pose (cold | hep) (cold & lus) (easy &))
155+ ;~ pose
156+ ;~(pfix (plus (just '0')) dim:ag)
157+ dim:ag
158+ ==
159+ ==
160+ ==
161+ (easy [& 0])
162+ ==
163+ ==
164+ ==
165+```
166+
167+#### Examples
168+
169+```
170+> (rush '2.47' json-rn:format)
171+[~ [%d a=%.y b=[c=2 [d=2 e=47] f=%.y i=0]]]
172+```
173+
174+```
175+> (rush '123' json-rn:format)
176+[~ [%d a=%.y b=[c=123 [d=0 e=0] f=%.y i=0]]]
177+```
178+
179+```
180+> (rush 'a' json-rn:format)
181+~
182+```
183+
184+---
185+
186+## `++enjs:format`
187+
188+Container arm for JSON encoders
189+
190+The `core` inside this arm contains a collection of functions for converting various types of data to `json`. The `json` type is defined in `lull.hoon` as:
191+
192+```hoon
193++$ json :: normal json value
194+ $@ ~ :: null
195+ $% [%a p=(list json)] :: array
196+ [%b p=?] :: boolean
197+ [%o p=(map @t json)] :: object
198+ [%n p=@ta] :: number
199+ [%s p=@t] :: string
200+ == ::
201+```
202+
203+This container arm doesn't do anything itself. The different `json` encoding functions are documented individually below.
204+
205+---
206+
207+### `++frond:enjs:format`
208+
209+Object from key-value pair
210+
211+Produces a `json` object containing `q` with a key of `p`.
212+
213+#### Accepts
214+
215+`p` is a `@t` key.
216+
217+`q` is any `json`.
218+
219+#### Produces
220+
221+A `json` object.
222+
223+#### Source
224+
225+```hoon
226+++ frond
227+ |= [p=@t q=json]
228+ ^- json
229+ [%o [[p q] ~ ~]]
230+```
231+
232+#### Examples
233+
234+```
235+> (frond:enjs:format 'foo' s+'bar')
236+[%o p={[p='foo' q=[%s p='bar']]}]
237+```
238+
239+```
240+> (crip (en-json:html (frond:enjs:format 'foo' s+'bar')))
241+'{"foo":"bar"}'
242+```
243+
244+---
245+
246+### `++pairs:enjs:format`
247+
248+Object from key-value pair list
249+
250+Produces a `json` object containing each key-value pair in list `a`.
251+
252+#### Accepts
253+
254+`a` is a `(list [@t json])`.
255+
256+#### Produces
257+
258+A `json` object.
259+
260+#### Source
261+
262+```hoon
263+++ pairs
264+ |= a=(list [p=@t q=json])
265+ ^- json
266+ [%o (~(gas by *(map @t json)) a)]
267+```
268+
269+#### Examples
270+
271+```
272+> =a ~[['foo' n+~.123] ['bar' s+'abc'] ['baz' b+&]]
273+> (pairs:enjs:format a)
274+[%o p={[p='bar' q=[%s p='abc']] [p='baz' q=[%b p=%.y]] [p='foo' q=[%n p=~.123]]}]
275+> (crip (en-json:html (pairs:enjs:format a)))
276+'{"foo":123,"baz":true,"bar":"abc"}'
277+```
278+
279+---
280+
281+### `++tape:enjs:format`
282+
283+String from tape
284+
285+Converts `a` into a `json` string.
286+
287+#### Accepts
288+
289+`a` is a `tape`.
290+
291+#### Produces
292+
293+A `json` string.
294+
295+#### Source
296+
297+```hoon
298+++ tape
299+ |= a=^tape
300+ ^- json
301+ [%s (crip a)]
302+```
303+
304+#### Examples
305+
306+```
307+> (tape:enjs:format "foo")
308+[%s p='foo']
309+```
310+
311+```
312+> (crip (en-json:html (tape:enjs:format "foo")))
313+'"foo"'
314+```
315+
316+---
317+
318+### `++wall:enjs:format`
319+
320+String from wall
321+
322+Converts `a` to a `json` string, separating lines with newline characters.
323+
324+#### Accepts
325+
326+`a` is a `wall`, which is a `(list tape)`.
327+
328+#### Produces
329+
330+A `json` string.
331+
332+#### Source
333+
334+```hoon
335+++ wall
336+ |= a=^wall
337+ ^- json
338+ (tape (of-wall a))
339+```
340+
341+#### Examples
342+
343+```
344+> (wall:enjs:format ~["foo" "bar" "baz"])
345+[%s p='foo\0abar\0abaz\0a']
346+```
347+
348+```
349+> (crip (en-json:html (wall:enjs:format ~["foo" "bar" "baz"])))
350+'"foo\\nbar\\nbaz\\n"'
351+```
352+
353+---
354+
355+### `++ship:enjs:format`
356+
357+~~String~~\* from ship
358+
359+Convert ship `a` to a `json` ~~string~~\*.
360+
361+**Note:** Currently this produces a `json` _number_ rather than string, but with the ship name rendered as text rather than a number. This is for Landscape performance reasons and may be reverted at some point.
362+
363+#### Accepts
364+
365+`a` is a `@p`.
366+
367+#### Produces
368+
369+A `json` ~~string~~ number but with the `@p` rendered as text rather than a number.
370+
371+#### Source
372+
373+```hoon
374+++ ship
375+ |= a=^ship
376+ ^- json
377+ [%n (rap 3 '"' (rsh [3 1] (scot %p a)) '"' ~)]
378+```
379+
380+#### Examples
381+
382+```
383+> (ship:enjs:format our)
384+[%n p=~."zod"]
385+```
386+
387+```
388+> (crip (en-json:html (ship:enjs:format our)))
389+'"zod"'
390+```
391+
392+---
393+
394+### `++numb:enjs:format`
395+
396+Number from unsigned
397+
398+Convert `a` to a `json` number.
399+
400+#### Accepts
401+
402+`a` is a `@u`
403+
404+#### Produces
405+
406+A `json` number.
407+
408+#### Source
409+
410+```hoon
411+++ numb
412+ |= a=@u
413+ ^- json
414+ :- %n
415+ ?: =(0 a) '0'
416+ %- crip
417+ %- flop
418+ |- ^- ^tape
419+ ?:(=(0 a) ~ [(add '0' (mod a 10)) $(a (div a 10))])
420+```
421+
422+#### Examples
423+
424+```
425+> (numb:enjs:format 123)
426+[%n p=~.123]
427+```
428+
429+```
430+> (numb:enjs:format 0xffff)
431+[%n p=~.65535]
432+```
433+
434+```
435+> (crip (en-json:html (numb:enjs:format 123)))
436+'123'
437+```
438+
439+---
440+
441+### `++sect:enjs:format`
442+
443+Seconds timestamp
444+
445+Convert time `a` to a Unix seconds timestamp in a `json` number.
446+
447+#### Accepts
448+
449+`a` is a `@da`.
450+
451+#### Produces
452+
453+A `json` number.
454+
455+#### Source
456+
457+```hoon
458+++ sect
459+ |= a=^time
460+ (numb (unt:chrono:userlib a))
461+```
462+
463+#### Examples
464+
465+```
466+> (sect:enjs:format now)
467+[%n p=~.1630407271]
468+```
469+
470+```
471+> (crip (en-json:html (sect:enjs:format now)))
472+'1630407290'
473+```
474+
475+---
476+
477+### `++time:enjs:format`
478+
479+Millisecond timestamp
480+
481+Convert time `a` to a Unix milliseconds timestamp in a `json` number.
482+
483+#### Accepts
484+
485+`a` is a `@da`.
486+
487+#### Produces
488+
489+A `json` number.
490+
491+#### Source
492+
493+```hoon
494+++ time
495+ |= a=^time
496+ (numb (unm:chrono:userlib a))
497+```
498+
499+#### Examples
500+
501+```
502+> (time:enjs:format now)
503+[%n p=~.1630407451204]
504+```
505+
506+```
507+> (crip (en-json:html (time:enjs:format now)))
508+'1630407462905'
509+```
510+
511+---
512+
513+### `++path:enjs:format`
514+
515+String from path
516+
517+Encode path `a` in a `json` string.
518+
519+#### Accepts
520+
521+`a` is a `path`
522+
523+#### Produces
524+
525+A `json` string.
526+
527+#### Source
528+
529+```hoon
530+++ path
531+ |= a=^path
532+ ^- json
533+ [%s (spat a)]
534+```
535+
536+#### Examples
537+
538+```
539+> (path:enjs:format /foo/bar/baz)
540+[%s p='/foo/bar/baz']
541+```
542+
543+```
544+> (crip (en-json:html (path:enjs:format /foo/bar/baz)))
545+'"/foo/bar/baz"'
546+```
547+
548+---
549+
550+### `++tank:enjs:format`
551+
552+Tank as string array
553+
554+Convert tank `a` into a `json` array of strings. The tank is passed through `+wash` with a maximum width of 80 characters specified, so may be split into multiple strings if it's too wide.
555+
556+#### Accepts
557+
558+`a` is a `tank`
559+
560+#### Produces
561+
562+A `json` array of strings.
563+
564+#### Source
565+
566+```hoon
567+++ tank
568+ |= a=^tank
569+ ^- json
570+ [%a (turn (wash [0 80] a) tape)]
571+```
572+
573+#### Examples
574+
575+```
576+> =tan rose+[[" " "[" "]"] ~[leaf+"foo" leaf+"bar" leaf+"baz"]]
577+> (tank:enjs:format tan)
578+[%a p=~[[%s p='[foo bar baz]']]]
579+> (crip (en-json:html (tank:enjs:format tan)))
580+'["[foo bar baz]"]'
581+```
582+
583+```
584+> =tan rose+[[" " "[" "]"] ~[leaf+"aaaaaaaaaaaaaaaaaaaaa" leaf+"bbbbbbbbbbbbbbbbbbb" leaf+"ccccccccccccccccccc" leaf+"dddddddddddddddddd"]]
585+> (crip (en-json:html (tank:enjs:format tan)))
586+'["[ aaaaaaaaaaaaaaaaaaaaa"," bbbbbbbbbbbbbbbbbbb"," ccccccccccccccccccc"," dddddddddddddddddd","]"]'
587+```
content/docs/hoon/reference/zuse/2d_6.mdnew file+1551
@@ -0,0 +1,1551 @@
1++++
2+title = "2d(6): From JSON"
3+weight = 42
4+template = "doc.html"
5++++
6+
7+## `++dejs:format`
8+
9+Container arm for JSON decoding reparsers
10+
11+The `core` inside this arm contains a large collection of functions for converting `json` data to other kinds of nouns. The `json` type is defined in `lull.hoon` as:
12+
13+```hoon
14++$ json :: normal json value
15+ $@ ~ :: null
16+ $% [%a p=(list json)] :: array
17+ [%b p=?] :: boolean
18+ [%o p=(map @t json)] :: object
19+ [%n p=@ta] :: number
20+ [%s p=@t] :: string
21+ == ::
22+```
23+
24+This container arm doesn't do anything by itself. It just contains the core with the rest of the `+dejs` functions which are documented below, plus it defines a couple of things for those functions:
25+
26+```hoon
27+=> |% ++ grub *
28+ ++ fist $-(json grub)
29+ -- ::
30+```
31+
32+A `fist` is a `gate` which takes `json` and produces a `grub`. Apart from a handful of exceptions, all of the functions below are `fist`s. If the functions below aren't adequate for a particular use case, custom `fist`s can easily be written, as long as they conform to the `$-(json grub)` type definition.
33+
34+A `grub` is just defined as `*`, and is the type of the product of a `fist`. In the case of `+dejs`, it can be absolutely any `noun`.
35+
36+Keep in mind that `+grub:dejs:format` and `+fist:dejs:format` defined here (and subsequently referred to as simply `fist` and `grub`) are different to `+grub:dejs-soft:format` and `+fist:dejs-soft:format` for the [+dejs-soft](/docs/hoon/reference/zuse/2d_7) functions, which return `unit`s.
37+
38+---
39+
40+### `++ar:dejs:format`
41+
42+Array as list
43+
44+Convert array `jon` to a list, decoding each item in `jon` with `wit`.
45+
46+The `+ar` function is a wet gate that takes `wit` and produces a new gate which takes `jon`.
47+
48+#### Accepts
49+
50+`wit` is a `fist` and is the sample of the wet gate.
51+
52+`jon` is a `json` array containing the kind of `json` that `wit` handles. `jon` is the sample of the gate produced by the wet gate.
53+
54+#### Produces
55+
56+A `(list [type])` where `[type]` is the type produced by `wit`.
57+
58+#### Source
59+
60+```hoon
61+++ ar
62+ |* wit=fist
63+ |= jon=json ^- (list _(wit *json))
64+ ?> ?=([%a *] jon)
65+ (turn p.jon wit)
66+```
67+
68+#### Examples
69+
70+```
71+> ((ar so):dejs:format a+[s+'foo' s+'bar' s+'baz' ~])
72+<|foo bar baz|>
73+```
74+
75+---
76+
77+### `++as:dejs:format`
78+
79+Array as set
80+
81+Convert array `jon` to a set, decoding each item in `jon` with `a`.
82+
83+The `+as` function is a wet gate that takes `a` and produces a new gate which takes `jon`.
84+
85+#### Accepts
86+
87+`a` is a `fist`, and is the sample of the wet gate.
88+
89+`jon` is a `json` array containing the kind of `json` that `a` takes. `jon` is the sample of the gate produced by the wet gate.
90+
91+#### Produces
92+
93+A `(set [type])` where `[type]` is the type produced by `a`.
94+
95+#### Source
96+
97+```hoon
98+++ as
99+ |* a=fist
100+ (cu ~(gas in *(set _$:a)) (ar a))
101+```
102+
103+#### Examples
104+
105+```
106+> ((as so):dejs:format a+[s+'foo' s+'bar' s+'baz' ~])
107+[n='baz' l={'bar'} r={'foo'}]
108+```
109+
110+---
111+
112+### `++at:dejs:format`
113+
114+Array as tuple
115+
116+Convert array `jon` to a tuple, decoding each item in the array with the corresponding `fist` in list `wil`.
117+
118+The `+at` function is a wet gate that takes `wil` and produces a new gate which takes `jon`.
119+
120+#### Accepts
121+
122+`wil` is a `(pole fist)`, and is the sample of the wet gate. A `pole` is a faceless list.
123+
124+`jon` is a `json` array whose elements are the same kinds of `json` accepted by the `fist`s in `wil` and in the same order. `jon` is the sample of the gate produced by the wet gate.
125+
126+#### Produces
127+
128+A tuple of the same types and in the same order as those produced by the `fist`s in `wil`.
129+
130+#### Source
131+
132+```hoon
133+++ at
134+ |* wil=(pole fist)
135+ |= jon=json
136+ ?> ?=([%a *] jon)
137+ ((at-raw wil) p.jon)
138+```
139+
140+#### Examples
141+
142+```
143+> ((at ~[so ni bo]):dejs:format a+[s+'foo' n+'123' b+& ~])
144+['foo' 123 %.y]
145+```
146+
147+```
148+> ((at ~[so ni bo]):dejs:format a+[b+& s+'foo' n+'123' ~])
149+dojo: hoon expression failed
150+```
151+
152+---
153+
154+### `++at-raw:dejs:format`
155+
156+Array as tuple, raw
157+
158+This function is used internally by `+at` and would not typically be used directly.
159+
160+`+at-raw` converts list `jol` to a tuple, decoding each item in the list with the corresponding function in list `wil`.
161+
162+The `+at-raw` function is a wet gate that takes `wil` and produces a new gate which takes `jol`.
163+
164+#### Accepts
165+
166+`wil` is a `(pole fist)`, and the sample of the wet gate. A `pole` is a faceless list.
167+
168+`jol` is a `(list json)` whose items are the same kinds of `json` accepted by the `fist`s in `wil` and in the same order. `jol` is the sample of the gate produced by the wet gate.
169+
170+#### Produces
171+
172+A tuple of the types and in the same order as those produced by the `fist`s in `wil`.
173+
174+#### Source
175+
176+```hoon
177+++ at-raw
178+ |* wil=(pole fist)
179+ |= jol=(list json)
180+ ?~ jol !!
181+ ?- wil
182+ :: [wit=* t=*]
183+ [* t=*]
184+ => .(wil [wit *]=wil)
185+ ?~ t.wil ?^(t.jol !! (wit.wil i.jol))
186+ [(wit.wil i.jol) ((at-raw t.wil) t.jol)]
187+ ==
188+```
189+
190+#### Examples
191+
192+```
193+> ((at-raw ~[so ni bo]):dejs:format ~[s+'foo' n+'123' b+&])
194+['foo' 123 %.y]
195+```
196+
197+```
198+> ((at-raw ~[so ni bo]):dejs:format ~[n+'123' s+'foo' b+&])
199+dojo: hoon expression failed
200+```
201+
202+---
203+
204+### `++bo:dejs:format`
205+
206+Boolean
207+
208+Convert boolean `jon` to a `?`.
209+
210+#### Accepts
211+
212+`jon` is a `json` boolean.
213+
214+#### Produces
215+
216+A `?`.
217+
218+#### Source
219+
220+```hoon
221+++ bo
222+ |=(jon=json ?>(?=([%b *] jon) p.jon))
223+```
224+
225+#### Examples
226+
227+```
228+> (bo:dejs:format b+|)
229+%.n
230+```
231+
232+---
233+
234+### `++bu:dejs:format`
235+
236+Boolean NOT
237+
238+Convert the logical NOT of boolean `jon` to a `?`.
239+
240+#### Accepts
241+
242+`jon` is a `json` boolean.
243+
244+#### Produces
245+
246+A `?`.
247+
248+#### Source
249+
250+```hoon
251+++ bu
252+ |=(jon=json ?>(?=([%b *] jon) !p.jon))
253+```
254+
255+#### Examples
256+
257+```
258+> (bu:dejs:format [%b %.y])
259+%.n
260+```
261+
262+---
263+
264+### `++ci:dejs:format`
265+
266+Maybe transform
267+
268+Decode `jon` with `wit`, then transform it with gate `poq` which produces a `unit`. Crash if the `unit` is `~` or else unwrap it and produce its data.
269+
270+The `+ci` function is a wet gate that takes a `poq` and `wit` and produces a new gate that takes `jon`.
271+
272+#### Accepts
273+
274+`poq` is a `gate` that produces a `unit`.
275+
276+`wit` is a `fist`.
277+
278+The wet gate takes `[poq=gate wit=fist]`.
279+
280+`jon` is `json` of the kind accepted by `wit`. `jon` is the sample of the gate produced by the wet gate.
281+
282+#### Produces
283+
284+If gate `poq` produces `(unit [type])`, produce `[type]` or else crash.
285+
286+#### Source
287+
288+```hoon
289+++ ci
290+ |* [poq=gate wit=fist]
291+ |= jon=json
292+ (need (poq (wit jon)))
293+```
294+
295+#### Examples
296+
297+```
298+> ((ci |=(a=? ?:(=(a &) `'foo' ~)) bo):dejs:format b+&)
299+'foo'
300+```
301+
302+```
303+> ((ci |=(a=? ?:(=(a &) `'foo' ~)) bo):dejs:format b+|)
304+dojo: hoon expression failed
305+```
306+
307+---
308+
309+### `++cu:dejs:format`
310+
311+Transform
312+
313+Decode `jon` with `wit`, then transform it with gate `poq`.
314+
315+The `+cu` function is a wet gate that takes `poq` and `wit` and produces a new gate that takes `jon`.
316+
317+#### Accepts
318+
319+`poq` is a `gate`.
320+
321+`wit` is a `fist`.
322+
323+The wet gate takes `[poq=gate wit=fist]`.
324+
325+`jon` is `json` of the kind handled by `wit`. `jon` is the sample of the gate produced by the wet gate.
326+
327+#### Produces
328+
329+The type produced by the gate given in `poq`.
330+
331+#### Source
332+
333+```hoon
334+++ cu
335+ |* [poq=gate wit=fist]
336+ |= jon=json
337+ (poq (wit jon))
338+```
339+
340+#### Examples
341+
342+```
343+> ((cu |=(=@t [t t t]) so):dejs:format s+'foo')
344+['foo' 'foo' 'foo']
345+```
346+
347+---
348+
349+### `++di:dejs:format`
350+
351+Millisecond date
352+
353+Convert number `jon`, containing a Unix milliseconds timestamp, to a date.
354+
355+#### Accepts
356+
357+`jon` is a `json` number.
358+
359+#### Produces
360+
361+A `@da`.
362+
363+#### Source
364+
365+```hoon
366+++ di
367+ (cu from-unix-ms:chrono:userlib ni)
368+```
369+
370+#### Examples
371+
372+```
373+> =time (time:enjs:format now)
374+> time
375+[%n p=~.1630471202176]
376+> (di:dejs:format time)
377+~2021.9.1..04.40.02..2d0e.5604.1893.74bc
378+```
379+
380+---
381+
382+### `++du:dejs:format`
383+
384+Second date
385+
386+Convert number `jon`, containing a Unix seconds timestamp, to a date.
387+
388+#### Accepts
389+
390+`jon` is a `json` number.
391+
392+#### Produces
393+
394+A `@da`.
395+
396+#### Source
397+
398+```hoon
399+++ du
400+ (cu from-unix:chrono:userlib ni)
401+```
402+
403+#### Examples
404+
405+```
406+> =sec (sect:enjs:format now)
407+> sec
408+[%n p=~.1630471524]
409+> (du:dejs:format sec)
410+~2021.9.1..04.45.24
411+```
412+
413+---
414+
415+### `++mu:dejs:format`
416+
417+True unit
418+
419+Decode `jon` with `wit`, then wrap it in a `unit`. Produce `~` if `jon` is `~`.
420+
421+The `+mu` function is a wet gate that takes `wit` and produces a gate which takes `jon`.
422+
423+#### Accepts
424+
425+`wit` is a `fist`.
426+
427+The wet gate takes `wit=fist`.
428+
429+`jon` is `json` of the kind `wit` handles. `jon` is the sample of the gate produced by the wet gate.
430+
431+#### Produces
432+
433+A `(unit [type])`, where `[type]` is the type produced by the `fist` specified in `wit`.
434+
435+#### Source
436+
437+```hoon
438+++ mu
439+ |* wit=fist
440+ |= jon=json
441+ ?~(jon ~ (some (wit jon)))
442+```
443+
444+#### Examples
445+
446+```
447+> ((mu so):dejs:format s+'foo')
448+[~ 'foo']
449+```
450+
451+```
452+> ((mu so):dejs:format ~)
453+~
454+```
455+
456+---
457+
458+### `++ne:dejs:format`
459+
460+Number as real
461+
462+Convert number `jon` to a `@rd`.
463+
464+#### Accepts
465+
466+`jon` is a `json` number.
467+
468+#### Produces
469+
470+A `@rd`.
471+
472+#### Source
473+
474+```hoon
475+++ ne
476+ |= jon=json
477+ ^- @rd
478+ ?> ?=([%n *] jon)
479+ (rash p.jon (cook ryld (cook royl-cell:^so json-rn)))
480+```
481+
482+#### Examples
483+
484+```
485+> (ne:dejs:format n+'123')
486+.~123
487+```
488+
489+```
490+> (ne:dejs:format n+'2.47')
491+.~2.47
492+```
493+
494+---
495+
496+### `++ni:dejs:format`
497+
498+Number as integer
499+
500+Convert number `jon` to a `@ud`. `jon` must be an integer or it will crash.
501+
502+#### Accepts
503+
504+`jon` is a `json` number.
505+
506+#### Produces
507+
508+A `@ud`.
509+
510+#### Source
511+
512+```hoon
513+++ ni
514+ |= jon=json
515+ ?> ?=([%n *] jon)
516+ (rash p.jon dem)
517+```
518+
519+#### Examples
520+
521+```
522+> (ni:dejs:format n+'123')
523+123
524+```
525+
526+```
527+> (ni:dejs:format n+'2.47')
528+{1 2}
529+syntax error
530+```
531+
532+---
533+
534+### `++no:dejs:format`
535+
536+Number as knot
537+
538+Convert number `jon` to a `@ta`.
539+
540+#### Accepts
541+
542+`jon` is a `json` number.
543+
544+#### Produces
545+
546+A `@ta`.
547+
548+#### Source
549+
550+```hoon
551+++ no
552+ |=(jon=json ?>(?=([%n *] jon) p.jon))
553+```
554+
555+#### Examples
556+
557+```
558+> (no:dejs:format n+'2.47')
559+~.2.47
560+```
561+
562+```
563+> (no:dejs:format n+'123')
564+~.123
565+```
566+
567+---
568+
569+### `++nu:dejs:format`
570+
571+Parse string as hex
572+
573+Parse string `jon` as hexadecimal or crash.
574+
575+#### Accepts
576+
577+`jon` is a `json` string.
578+
579+#### Produces
580+
581+A `@`.
582+
583+#### Source
584+
585+```hoon
586+++ nu
587+ |= jon=json
588+ ?> ?=([%s *] jon)
589+ (rash p.jon hex)
590+```
591+
592+#### Examples
593+
594+```
595+> `@ux`(nu:dejs:format s+'DEADBEEF')
596+0xdead.beef
597+```
598+
599+```
600+> `@ux`(nu:dejs:format s+'deadbeef')
601+0xdead.beef
602+```
603+
604+```
605+> `@ux`(nu:dejs:format s+'0xdeadbeef')
606+{1 2}
607+syntax error
608+```
609+
610+---
611+
612+### `++of:dejs:format`
613+
614+Object as frond
615+
616+Convert object `jon`, which contains a single key-value pair, to a key-value tuple using the `fist` in `wer` which matches the key.
617+
618+The `+of` function is a wet gate that takes a list of pairs of keys and `fist`s and produces a new gate that takes `json`.
619+
620+**Note:** While technically the type of an item in the list `wer` is specified as `[cord fist]`, actually using a `cord` may result in incorrect type inferrence. Instead, you'll want to format it as a `@tas` like `%foo`, so the type system correctly interprets it as a tagged union. If the key contains characters that would be invalid in an ordinary `@tas`, you can format it like `%'foo_bar'` - a `%` then single quotes.
621+
622+#### Accepts
623+
624+`wer` is a `(pole [cord fist])`, and is the sample of the wet gate. A `pole` is a faceless `list`.
625+
626+`jon` is a `json` object containing a single key. `jon` is the sample of the gate produced by the wet gate.
627+
628+#### Produces
629+
630+A `[@t [type]]` where `[type]` is the type produced by the matching `fist`.
631+
632+#### Source
633+
634+```hoon
635+++ of
636+ |* wer=(pole [cord fist])
637+ |= jon=json
638+ ?> ?=([%o [@ *] ~ ~] jon)
639+ |-
640+ ?- wer
641+ :: [[key=@t wit=*] t=*]
642+ [[key=@t *] t=*]
643+ => .(wer [[* wit] *]=wer)
644+ ?: =(key.wer p.n.p.jon)
645+ [key.wer ~|(key+key.wer (wit.wer q.n.p.jon))]
646+ ?~ t.wer ~|(bad-key+p.n.p.jon !!)
647+ ((of t.wer) jon)
648+ ==
649+```
650+
651+#### Examples
652+
653+First, let's store some objects containing key-value pairs:
654+
655+```
656+> =obj-1 o+(malt ['foo' s+'hello']~)
657+> (crip (en-json:html obj-1))
658+'{"foo":"hello"}'
659+```
660+
661+```
662+> =obj-2 o+(malt ~[['bar' a+~[n+'123' n+'456']]])
663+> (crip (en-json:html obj-2))
664+'{"bar":[123,456]}'
665+```
666+
667+```
668+> =obj-3 o+(malt ['baz' b+&]~)
669+> (crip (en-json:html obj-3))
670+'{"baz":true}'
671+```
672+
673+Next, let's construct a `+of` function and try it on our objects:
674+
675+```
676+> ((of ~[foo+so bar+(ar ni)]):dejs:format obj-1)
677+[%'foo' 'hello']
678+```
679+
680+```
681+> ((of ~[foo+so bar+(ar ni)]):dejs:format obj-2)
682+[%'bar' ~[123 456]]
683+```
684+
685+```
686+> ((of ~[foo+so bar+(ar ni)]):dejs:format obj-3)
687+[%bad-key 'baz']
688+dojo: hoon expression failed
689+```
690+
691+---
692+
693+### `++ot:dejs:format`
694+
695+Object as tuple.
696+
697+Convert object `jon` to a tuple by decoding each value with the matching `fist` in `wer`. Each key in `wer` must be matched to a key in `jon`. On the other hand, if there are keys in `jon` with no corresponding key in `wer`, they'll simply be ignored.
698+
699+The `+ot` function is a wet gate that takes a list of key-`fist` pairs, and produces a gate which takes `json`.
700+
701+**Note:** While technically the type of an item in the list `wer` is specified as `[cord fist]`, actually using a `cord` may result in incorrect type inferrence. Instead, you'll want to format it as a `@tas` like `%foo`, so the type system correctly interprets it as a tagged union. If the key contains characters that would be invalid in an ordinary `@tas`, you can format it like `%'foo_bar'` - a `%` then single quotes.
702+
703+#### Accepts
704+
705+`wer` is a `(pole [cord fist])`, and is the sample of the wet gate. A `pole` is a faceless list.
706+
707+`jon` is a `json` object, and is the sample of the gate produced by the wet gate.
708+
709+#### Produces
710+
711+A tuple where the type of each item is the product of the corresponding `fist` in `wer`. The order of items in the tuple will match the order of items in `wer`.
712+
713+#### Source
714+
715+```hoon
716+++ ot
717+ |* wer=(pole [cord fist])
718+ |= jon=json
719+ ?> ?=([%o *] jon)
720+ ((ot-raw wer) p.jon)
721+```
722+
723+#### Examples
724+
725+```
726+> %- (ot ~[foo+so bar+ni]):dejs:format
727+ o+(malt (limo ~[['bar' n+'123'] ['foo' s+'hello'] ['baz' b+&]]))
728+['hello' 123]
729+```
730+
731+```
732+> %- (ot ~[foo+so bar+ni]):dejs:format
733+ o+(malt (limo ~[['bar' n+'123'] ['baz' b+&]]))
734+[%key 'foo']
735+dojo: hoon expression failed
736+```
737+
738+---
739+
740+### `++ot-raw:dejs:format`
741+
742+Object as tuple, raw
743+
744+This function is used internally by [+ot](#otdejsformat) and would not typically be used directly.
745+
746+`+ot-raw` converts map `jom` to a tuple by decoding each value with the matching `fist` in `wer`. Each key in `wer` must be matched to a key in the given map. On the other hand, if there are keys in the map with no corresponding key in `wer`, they'll simply be ignored.
747+
748+The `+ot-raw` function is a wet gate that takes a list of key-`fist` pairs, and produces a gate which takes a map of keys to `json`.
749+
750+**Note:** While technically the type of an item in the list `wer` is specified as `[cord fist]`, actually using a `cord` may result in incorrect type inferrence. Instead, you'll want to format it as a `@tas` like `%foo`, so the type system correctly interprets it as a tagged union. If the key contains characters that would be invalid in an ordinary `@tas`, you can format it like `%'foo_bar'` - a `%` then single quotes.
751+
752+#### Accepts
753+
754+`wer` is a `(pole [cord fist])`, and is the sample of the wet gate. A `pole` is a faceless list.
755+
756+`jom` is a `(map @t json)`, and is the sample of the gate produced by the wet gate.
757+
758+#### Produces
759+
760+A tuple where the type of each item is the product of the corresponding `fist` in `wer`. The order of items in the tuple will match the order of items in `wer`.
761+
762+#### Source
763+
764+```hoon
765+++ ot-raw
766+ |* wer=(pole [cord fist])
767+ |= jom=(map @t json)
768+ ?- wer
769+ :: [[key=@t wit=*] t=*]
770+ [[key=@t *] t=*]
771+ => .(wer [[* wit] *]=wer)
772+ =/ ten ~|(key+key.wer (wit.wer (~(got by jom) key.wer)))
773+ ?~(t.wer ten [ten ((ot-raw t.wer) jom)])
774+ ==
775+```
776+
777+#### Examples
778+
779+```
780+> %- (ot-raw ~[foo+so bar+ni]):dejs:format
781+ (malt (limo ~[['bar' n+'123'] ['foo' s+'hello'] ['baz' b+&]]))
782+['hello' 123]
783+```
784+
785+```
786+> %- (ot-raw ~[foo+so bar+ni]):dejs:format
787+ (malt (limo ~[['bar' n+'123'] ['baz' b+&]]))
788+[%key 'foo']
789+dojo: hoon expression failed
790+```
791+
792+---
793+
794+### `++ou:dejs:format`
795+
796+Object of units
797+
798+Convert object `jon` to a tuple by decoding each value with the function in `wer` that matches its key. Keys in `jon` with no matching key in `wer` are ignored. This is the same as [+ot](#otdejsformat) except that:
799+
800+- It wraps each value in `jon` in a `unit` before passing it to the corresponding function in `wer`.
801+- If a key in `wer` has no matching key in `jon`, it passes `~` to that function.
802+
803+Therefore, the functions must take a `(unit json)` rather than just `json`, so they are not `fist`s but rather `$-((unit json) grub)` (despite what the source code says). There are two `+dejs` functions that can be used in `+ou` and take `unit`s: [+uf](#ufdejsformat) and [+un](#undejsformat). Both of them wrap `fist`s like `(uf so)` or `(un so)`. The former, `+uf`, lets you replace a null `unit` with something of your choosing. The latter, `+un`, crashes if the `unit` is null. Using both in a `+ou` allows you to set some values as mandatory and others as optional, replacing any missing optional ones with whatever you want. This is the ultimate purpose of `+ou`.
804+
805+The `+ou` function is a wet gate that takes a list of key-function pairs, and produces a gate which takes `json`.
806+
807+**Note:** While technically the type of an item in the list `wer` is specified as `[cord fist]`, actually using a `cord` may result in incorrect type inferrence. Instead, you'll want to format it as a `@tas` like `%foo`, so the type system correctly interprets it as a tagged union. If the key contains characters that would be invalid in an ordinary `@tas`, you can format it like `%'foo_bar'` - a `%` then single quotes.
808+
809+#### Accepts
810+
811+`wer` is a `(pole [cord $-((unit json) grub)])`, despite saying `(pole [cord fist])` in the source code. `wer` is the sample of the wet gate. A `pole` is a faceless list.
812+
813+`jon` is a `json` object, and is the sample of the gate produced by the wet gate.
814+
815+#### Produces
816+
817+A tuple where the type of each item is the product of the corresponding function in `wer`. The order of items in the tuple will match the order of items in `wer`.
818+
819+#### Source
820+
821+```hoon
822+++ ou
823+ |* wer=(pole [cord fist])
824+ |= jon=json
825+ ?> ?=([%o *] jon)
826+ ((ou-raw wer) p.jon)
827+```
828+
829+#### Examples
830+
831+```
832+> %- (ou ~[foo+(un so) bar+(uf missing+ni)]):dejs:format
833+ o+(malt (limo ~[['foo' s+'hello']]))
834+['hello' %missing]
835+```
836+
837+```
838+> %- (ou ~[foo+(un so) bar+(uf missing+ni)]):dejs:format
839+ o+(malt (limo ~[['bar' n+'123']]))
840+[%key 'foo']
841+dojo: hoon expression failed
842+```
843+
844+```
845+> %- (ou ~[foo+(un so) bar+(uf missing+ni)]):dejs:format
846+ o+(malt (limo ~[['foo' s+'hello'] ['bar' n+'123']]))
847+['hello' 123]
848+```
849+
850+---
851+
852+### `++ou-raw:dejs:format`
853+
854+Object of units, raw
855+
856+This function is used internally by [+ou](#oudejsformat), you would not typically use it directly.
857+
858+Convert map `jom` to a tuple by decoding each value with the function in `wer` that matches its key. Keys in `jom` with no matching key in `wer` are ignored. This is the same as [+ot-raw](#ot-rawdejsformat) except that:
859+
860+- It wraps each value in `jom` in a `unit` before passing it to the corresponding function in `wer`.
861+- If a key in `wer` has no matching key in `jom`, it passes `~` to that function.
862+
863+Therefore, the functions must take a `(unit json)` rather than just `json`, so they are not `fist`s but rather `$-((unit json) grub)` (despite what the source code says). There are two `+dejs` functions that can be used in `+ou-raw` and take `unit`s: [+uf](#ufdejsformat) and [+un](#undejsformat). Both of them wrap `fist`s like `(uf so)` or `(un so)`. The former, `+uf`, lets you replace a null `unit` with something of your choosing. The latter, `+un`, crashes if the `unit` is null. Using both in a `+ou-raw` allows you to set some values as mandatory and others as optional, replacing any missing optional ones with whatever you want.
864+
865+The `+ou-raw` function is a wet gate that takes a list of key-function pairs, and produces a gate which takes a map of `@t` keys to `json`.
866+
867+**Note:** While technically the type of an item in the list `wer` is specified as `[cord fist]`, actually using a `cord` may result in incorrect type inferrence. Instead, you'll want to format it as a `@tas` like `%foo`, so the type system correctly interprets it as a tagged union. If the key contains characters that would be invalid in an ordinary `@tas`, you can format it like `%'foo_bar'` - a `%` then single quotes.
868+
869+#### Accepts
870+
871+`wer` is a `(pole [cord $-((unit json) grub)])`, despite saying `(pole [cord fist])` in the source code. `wer` is the sample of the wet gate. A `pole` is a faceless list.
872+
873+`jon` is a `(map @t json)`, and is the sample of the gate produced by the wet gate.
874+
875+#### Produces
876+
877+A tuple where the type of each item is the product of the corresponding function in `wer`. The order of items in the tuple will match the order of items in `wer`.
878+
879+#### Source
880+
881+```hoon
882+++ ou-raw
883+ |* wer=(pole [cord fist])
884+ |= jom=(map @t json)
885+ ?- wer
886+ :: [[key=@t wit=*] t=*]
887+ [[key=@t *] t=*]
888+ => .(wer [[* wit] *]=wer)
889+ =/ ten ~|(key+key.wer (wit.wer (~(get by jom) key.wer)))
890+ ?~(t.wer ten [ten ((ou-raw t.wer) jom)])
891+ ==
892+```
893+
894+#### Examples
895+
896+```
897+> %- (ou-raw ~[foo+(un so) bar+(uf missing+ni)]):dejs:format
898+ (malt (limo ~[['foo' s+'hello']]))
899+['hello' %missing]
900+```
901+
902+```
903+> %- (ou-raw ~[foo+(un so) bar+(uf missing+ni)]):dejs:format
904+ (malt (limo ~[['bar' n+'123']]))
905+[%key 'foo']
906+dojo: hoon expression failed
907+```
908+
909+```
910+> %- (ou-raw ~[foo+(un so) bar+(uf missing+ni)]):dejs:format
911+ (malt (limo ~[['foo' s+'hello'] ['bar' n+'123']]))
912+['hello' 123]
913+```
914+
915+---
916+
917+### `++oj:dejs:format`
918+
919+Object as jug
920+
921+Convert `jon`, an object of arrays, to a `jug`. Decode each element in each array with `fist`.
922+
923+The `+oj` function is a wet gate that takes `fist` and produces a gate that takes `jon`.
924+
925+#### Accepts
926+
927+`fist` is a `fist`, and is the sample of the wet gate.
928+
929+`jon` is a `json` object of arrays. Each element in each array is of the same `json` kind. `jon` is the sample of the gate produced by the wet gate.
930+
931+#### Produces
932+
933+A `(jug cord [type])`, where `[type]` is the type produced by `fist`.
934+
935+#### Source
936+
937+```hoon
938+++ oj
939+ |* =fist
940+ ^- $-(json (jug cord _(fist *json)))
941+ (om (as fist))
942+```
943+
944+#### Examples
945+
946+```
947+> =jon (need (de-json:html '{"foo":["aaa","bbb","ccc"],"bar":["xxx","yyy","zzz"]}'))
948+> ((oj so):dejs:format jon)
949+{[p='bar' q={'xxx' 'zzz' 'yyy'}] [p='foo' q={'bbb' 'ccc' 'aaa'}]}
950+```
951+
952+---
953+
954+### `++om:dejs:format`
955+
956+Object as map
957+
958+Convert object `jon` to a map, decoding each value with `wit`.
959+
960+The `+om` function is a wet gate that takes `wit` and produces a gate that takes `jon`.
961+
962+#### Accepts
963+
964+`wit` is a `fist`, and is the sample of the wet gate.
965+
966+`jon` is a `json` object whose values are the kind of `json` that `wit` takes. `jon` is the sample of the gate produced by the wet gate.
967+
968+#### Produces
969+
970+A `(map cord [type])`, where `[type]` is the type produced by `wit`.
971+
972+#### Source
973+
974+```hoon
975+++ om
976+ |* wit=fist
977+ |= jon=json
978+ ?> ?=([%o *] jon)
979+ (~(run by p.jon) wit)
980+```
981+
982+#### Examples
983+
984+```
985+> =jon (need (de-json:html '{"foo":"aaa","bar":"bbb"}'))
986+> ((om so):dejs:format jon)
987+{[p='bar' q='bbb'] [p='foo' q='aaa']}
988+```
989+
990+---
991+
992+### `++op:dejs:format`
993+
994+Parse keys of map
995+
996+Convert object `jon` to a map, parsing each key with `fel` and decoding each value with `wit`.
997+
998+The `+op` function is a wet gate that takes `fel` and `wit`, and produces a gate that takes `jon`.
999+
1000+#### Accepts
1001+
1002+The wet gate takes a cell of `[fel wil]`, where `fel` is a parsing `rule` and `wil` is a `fist`.
1003+
1004+`jon` is a `json` object, whose keys are parsable by `fel` and whose values are `json` of the kind `wit` takes. `jon` is the sample of the gate produced by the wet gate.
1005+
1006+#### Produces
1007+
1008+A `(map [a] [b])` where `[a]` is the type produced by `fel` and `[b]` is the type produced by `wit`.
1009+
1010+#### Source
1011+
1012+```hoon
1013+++ op
1014+ |* [fel=rule wit=fist]
1015+ |= jon=json ^- (map _(wonk *fel) _*wit)
1016+ =/ jom ((om wit) jon)
1017+ %- malt
1018+ %+ turn ~(tap by jom)
1019+ |* [a=cord b=*]
1020+ => .(+< [a b]=+<)
1021+ [(rash a fel) b]
1022+```
1023+
1024+#### Examples
1025+
1026+```
1027+> =jon (need (de-json:html '{"123":"aaa","456":"bbb"}'))
1028+> ((op dem so):dejs:format jon)
1029+{[p=456 q='bbb'] [p=123 q='aaa']}
1030+```
1031+
1032+---
1033+
1034+### `++pa:dejs:format`
1035+
1036+String as path
1037+
1038+Convert `jon` and parse to a path.
1039+
1040+#### Accepts
1041+
1042+`jon` is a `json` string encoding a `path`.
1043+
1044+#### Produces
1045+
1046+A `(list @)` which can be cast to a `path`.
1047+
1048+#### Source
1049+
1050+```hoon
1051+++ pa
1052+ (su stap)
1053+```
1054+
1055+#### Examples
1056+
1057+```
1058+> `path`(pa:dejs:format s+'/foo/bar/baz')
1059+/foo/bar/baz
1060+```
1061+
1062+---
1063+
1064+### `++pe:dejs:format`
1065+
1066+Prefix
1067+
1068+Decode `jon` with `wit`, and prefix the result with `pre`.
1069+
1070+The `+pe` function is a wet gate that takes `pre` and `wit`, and produces a gate that takes `jon`.
1071+
1072+#### Accepts
1073+
1074+The wet gate takes a cell of `[pre wit]`, where `pre` is any noun and `wit` is a `fist`.
1075+
1076+`jon` is `json` of the kind accepted by `wit`. `jon` is the sample of the gate produced by the wet gate.
1077+
1078+#### Produces
1079+
1080+A cell of `[[a] [b]]`, where `[a]` is the noun given in `pre` and `[b]` is the type produced by `wit`.
1081+
1082+#### Source
1083+
1084+```hoon
1085+++ pe
1086+ |* [pre=* wit=fist]
1087+ (cu |*(* [pre +<]) wit)
1088+```
1089+
1090+#### Examples
1091+
1092+```
1093+> ((pe %foo so):dejs:format s+'bar')
1094+[%foo 'bar']
1095+```
1096+
1097+---
1098+
1099+### `++sa:dejs:format`
1100+
1101+String as tape
1102+
1103+Convert `jon` to a `tape`.
1104+
1105+#### Accepts
1106+
1107+`jon` is a `json` string.
1108+
1109+#### Produces
1110+
1111+A `tape`.
1112+
1113+#### Source
1114+
1115+```hoon
1116+++ sa
1117+ |=(jon=json ?>(?=([%s *] jon) (trip p.jon)))
1118+```
1119+
1120+#### Examples
1121+
1122+```
1123+> (sa:dejs:format s+'foo')
1124+"foo"
1125+```
1126+
1127+---
1128+
1129+### `++sd:dejs:format`
1130+
1131+String `@ud` as date
1132+
1133+Convert `jon` to a `@da`, parsing it as a date in `@ud` form.
1134+
1135+#### Accepts
1136+
1137+`jon` is a `json` string encoding a date in `@ud` form.
1138+
1139+#### Produces
1140+
1141+A `@da`.
1142+
1143+#### Source
1144+
1145+```hoon
1146+++ sd
1147+ |= jon=json
1148+ ^- @da
1149+ ?> ?=(%s -.jon)
1150+ `@da`(rash p.jon dem:ag)
1151+```
1152+
1153+#### Examples
1154+
1155+```
1156+> (sd:dejs:format s+(scot %ud now))
1157+~2021.9.8..01.02.41..e5db
1158+```
1159+
1160+---
1161+
1162+### `++se:dejs:format`
1163+
1164+String as aura
1165+
1166+Convert and parse `jon` to an atom of the type specified in `aur`.
1167+
1168+The `+se` function is a gate within a gate. The first gate takes `aur` and the second takes `jon`.
1169+
1170+#### Accepts
1171+
1172+`aur` is a `@tas` denoting an aura like `%ud`, `%tas`, `%p`, etc. `aur` is the sample of the first gate
1173+
1174+`jon` is a `json` string encoding an atom of the type specified in `aur`. `jon` is the sample of the second nested gate.
1175+
1176+#### Produces
1177+
1178+A `@` which can then be cast to the type specified in `aur`.
1179+
1180+#### Source
1181+
1182+```hoon
1183+++ se
1184+ |= aur=@tas
1185+ |= jon=json
1186+ ?>(?=([%s *] jon) (slav aur p.jon))
1187+```
1188+
1189+#### Examples
1190+
1191+```
1192+> `@p`((se %p):dejs:format s+(scot %p our))
1193+~zod
1194+```
1195+
1196+```
1197+> `@da`((se %da):dejs:format s+(scot %da now))
1198+~2021.9.8..01.12.28..4f6a
1199+```
1200+
1201+---
1202+
1203+### `++so:dejs:format`
1204+
1205+String as cord
1206+
1207+Convert `jon` to a cord.
1208+
1209+#### Accepts
1210+
1211+`jon` is a `json` string.
1212+
1213+#### Produces
1214+
1215+A `@t`.
1216+
1217+#### Source
1218+
1219+```hoon
1220+++ so
1221+ |=(jon=json ?>(?=([%s *] jon) p.jon))
1222+```
1223+
1224+#### Examples
1225+
1226+```
1227+> (so:dejs:format s+'foo')
1228+'foo'
1229+```
1230+
1231+---
1232+
1233+### `++su:dejs:format`
1234+
1235+Parse string
1236+
1237+Convert and parse `jon` with `sab`.
1238+
1239+The `+su` function is a wet gate that takes `sab`, and produces a gate that takes `jon`.
1240+
1241+#### Accepts
1242+
1243+`sab` is a parsing `rule`, and is the sample of the wet gate.
1244+
1245+`jon` is a `json` string, and is the sample of the gate produced by the wet gate.
1246+
1247+#### Produces
1248+
1249+The type produced by `sab`.
1250+
1251+#### Source
1252+
1253+```hoon
1254+++ su
1255+ |* sab=rule
1256+ |= jon=json ^+ (wonk *sab)
1257+ ?> ?=([%s *] jon)
1258+ (rash p.jon sab)
1259+```
1260+
1261+#### Examples
1262+
1263+```
1264+> ((su dem):dejs:format s+'123456')
1265+123.456
1266+```
1267+
1268+```
1269+> `@ub`((su bin):dejs:format s+'00001011101110001101')
1270+0b1011.1011.1000.1101
1271+```
1272+
1273+---
1274+
1275+### `++uf:dejs:format`
1276+
1277+Unit fall
1278+
1279+Convert the `json` data in unit `jon` with `wit` unless `jon` is `~`, in which case return `def`. Note this deals with `(unit json)` rather than the usual `json`. This would typically be used inside a [+ou](#oudejsformat) function to replace missing values with the given values.
1280+
1281+The `+uf` function is a wet gate that takes `def` and `wit`, and produces a gate that takes `jon`.
1282+
1283+#### Accepts
1284+
1285+The wet gate takes a cell of `[def wit]`, where `def` is any `noun` and `wit` is a `fist`.
1286+
1287+`jon` is a `(unit json)`, and is the sample of the gate produced by the wet gate.
1288+
1289+#### Produces
1290+
1291+Either the type produced by `wit`, or else the `noun` given in `def` if `jon` is null.
1292+
1293+#### Source
1294+
1295+```hoon
1296+++ uf
1297+ |* [def=* wit=fist]
1298+ |= jon=(unit json)
1299+ ?~(jon def (wit u.jon))
1300+```
1301+
1302+#### Examples
1303+
1304+```
1305+> ((uf %missing so):dejs:format `s+'foo')
1306+'foo'
1307+```
1308+
1309+```
1310+> ((uf %missing so):dejs:format ~)
1311+%missing
1312+```
1313+
1314+---
1315+
1316+### `++un:dejs:format`
1317+
1318+Unit need
1319+
1320+Convert the `json` data in unit `jon` with `wit` unless `jon` is `~`, in which case crash. Note this deals with `(unit json)` rather than the usual `json`. This would typically be used inside a [+ou](#oudejsformat) function and in conjunction with [+uf](#ufdejsformat) to specify mandatory values.
1321+
1322+The `+un` function is a wet gate that takes `wit` and produces a gate that takes `jon`.
1323+
1324+#### Accepts
1325+
1326+`wit` is a `fist`, and is the sample of the wet gate.
1327+
1328+`jon` is a `(unit json)`, and is the sample of the gate returned by the wet gate.
1329+
1330+#### Produces
1331+
1332+The type produced by `wit` or crash if `jon` is null.
1333+
1334+#### Source
1335+
1336+```hoon
1337+++ un
1338+ |* wit=fist
1339+ |= jon=(unit json)
1340+ (wit (need jon))
1341+```
1342+
1343+#### Examples
1344+
1345+```
1346+> ((un so):dejs:format `s+'foo')
1347+'foo'
1348+```
1349+
1350+```
1351+> ((un so):dejs:format ~)
1352+dojo: hoon expression failed
1353+```
1354+
1355+---
1356+
1357+### `++ul:dejs:format`
1358+
1359+Null
1360+
1361+Return `~` if `jon` is null or else crash.
1362+
1363+#### Accepts
1364+
1365+`jon` is null `json`.
1366+
1367+#### Produces
1368+
1369+`~` if `jon` is null, otherwise crashes.
1370+
1371+#### Source
1372+
1373+```hoon
1374+++ ul
1375+ |=(jon=json ?~(jon ~ !!))
1376+```
1377+
1378+#### Examples
1379+
1380+```
1381+> (ul:dejs:format ~)
1382+~
1383+```
1384+
1385+```
1386+> (ul:dejs:format b+&)
1387+dojo: hoon expression failed
1388+```
1389+
1390+---
1391+
1392+### `++za:dejs:format`
1393+
1394+Full unit pole
1395+
1396+Check whether all units in list `pod` are non-null. This is used internally by some functions and would not typically be used directly.
1397+
1398+#### Accepts
1399+
1400+`pod` is a `(pole (unit))`. A `pole` is a faceless list.
1401+
1402+#### Produces
1403+
1404+A `?`, which is `%.n` if any of the `unit`s in `pod` are `~`, and `%.y` otherwise.
1405+
1406+#### Source
1407+
1408+```hoon
1409+++ za
1410+ |* pod=(pole (unit))
1411+ ?~ pod &
1412+ ?~ -.pod |
1413+ (za +.pod)
1414+```
1415+
1416+#### Examples
1417+
1418+```
1419+> (za:dejs:format ~[`1 `2 `3 `4])
1420+%.y
1421+```
1422+
1423+```
1424+> (za:dejs:format ~)
1425+%.y
1426+```
1427+
1428+```
1429+> (za:dejs:format ~[`1 `2 ~ `4])
1430+%.n
1431+```
1432+
1433+---
1434+
1435+### `++zl:dejs:format`
1436+
1437+Collapse unit list
1438+
1439+Convert `lut`, a list of units, to a `(unit (list))` by stripping the unit from each item. The resulting unit is null if any of the units in the list are null. This is used internally by some functions, you would not typically use it directly.
1440+
1441+#### Accepts
1442+
1443+A `(list (unit))`.
1444+
1445+#### Produces
1446+
1447+A `(unit (list))` which is null if any of the units in `lut` were null.
1448+
1449+#### Source
1450+
1451+```hoon
1452+++ zl
1453+ |* lut=(list (unit))
1454+ ?. |- ^- ?
1455+ ?~(lut & ?~(i.lut | $(lut t.lut)))
1456+ ~
1457+ %- some
1458+ |-
1459+ ?~ lut ~
1460+ [i=u:+.i.lut t=$(lut t.lut)]
1461+```
1462+
1463+#### Examples
1464+
1465+```
1466+> (zl:dejs:format (limo ~[`1 `2 `3 `4 `5 `6]))
1467+[~ [i=1 t=~[2 3 4 5 6]]]
1468+```
1469+
1470+```
1471+> (zl:dejs:format (limo ~[`1 `2 ~ `4 `5 `6]))
1472+~
1473+```
1474+
1475+---
1476+
1477+### `++zp:dejs:format`
1478+
1479+Unit tuple
1480+
1481+Convert `but`, a list of units, to a tuple by stripping the unit from each item. Crashes if any of the units are null. This is used internally by some functions, you would not typically use it directly.
1482+
1483+#### Accepts
1484+
1485+`but` is a `(pole (unit))`. A `pole` is a faceless list.
1486+
1487+#### Produces
1488+
1489+A tuple containing each unwrapped element from the original list, or crashes if any of the units were null.
1490+
1491+#### Source
1492+
1493+```hoon
1494+++ zp
1495+ |* but=(pole (unit))
1496+ ?~ but !!
1497+ ?~ +.but
1498+ u:->.but
1499+ [u:->.but (zp +.but)]
1500+```
1501+
1502+#### Examples
1503+
1504+```
1505+> (zp:dejs:format ~[`1 `2 `3 `4 `5 `6])
1506+[1 2 3 4 5 6]
1507+```
1508+
1509+```
1510+> (zp:dejs:format ~[`1 `2 ~ `4 `5 `6])
1511+mull-none
1512+dojo: hoon expression failed
1513+```
1514+
1515+---
1516+
1517+### `++zm:dejs:format`
1518+
1519+Collapse unit map
1520+
1521+Strip units from values in `lum`, a map of units. Returns null if any of the units are null. This is used internally by some functions, you would not typically use it directly.
1522+
1523+#### Accepts
1524+
1525+`lum` is a `(map term (unit))`
1526+
1527+#### Produces
1528+
1529+A `(unit (map term [type]))`, where `[type]` is the type the units in `lum` contained. Produces `~` if any of the units were null.
1530+
1531+#### Source
1532+
1533+```hoon
1534+++ zm
1535+ |* lum=(map term (unit))
1536+ ?: (~(rep by lum) |=([[@ a=(unit)] b=_|] |(b ?=(~ a))))
1537+ ~
1538+ (some (~(run by lum) need))
1539+```
1540+
1541+#### Examples
1542+
1543+```
1544+> (zm:dejs:format (malt ~[['foo' `1] ['bar' `2]]))
1545+[~ {[p='bar' q=2] [p='foo' q=1]}]
1546+```
1547+
1548+```
1549+> (zm:dejs:format (malt (limo ~[['foo' `1] ['bar' ~]])))
1550+~
1551+```
content/docs/hoon/reference/zuse/2d_7.mdnew file+1307
@@ -0,0 +1,1307 @@
1++++
2+title = "2d(7): From JSON (unit)"
3+weight = 44
4+template = "doc.html"
5++++
6+
7+## `++dejs-soft:format`
8+
9+Container arm for unitized JSON decoding reparsers
10+
11+The `core` inside this arm contains a large collection of functions for converting `json` data to `unit`s of various kinds. The `json` type is defined in `lull.hoon` as:
12+
13+```hoon
14++$ json :: normal json value
15+ $@ ~ :: null
16+ $% [%a p=(list json)] :: array
17+ [%b p=?] :: boolean
18+ [%o p=(map @t json)] :: object
19+ [%n p=@ta] :: number
20+ [%s p=@t] :: string
21+ == ::
22+```
23+
24+This container arm doesn't do anything by itself. It just contains the core with the rest of the `+dejs-soft` functions which are documented below, plus it defines a couple of things for those functions:
25+
26+```hoon
27+=> |% ++ grub (unit *)
28+ ++ fist $-(json grub)
29+ --
30+```
31+
32+A `fist` is a `gate` which takes `json` and produces a `grub`. Apart from a handful of exceptions, all of the functions below are `fist`s. If the functions below aren't adequate for a particular use case, custom `fist`s can easily be written, as long as they conform to the `$-(json grub)` type definition.
33+
34+A `grub` is just defined as `(unit *)`, and is the type of the product of a `fist`. In the case of `+dejs-soft`, it can be any noun in a `unit`.
35+
36+Keep in mind that `+grub:dejs-soft:format` and `+fist:dejs-soft:format` defined here (and subsequently referred to as simply `fist` and `grub`) are different to `+grub:dejs:format` and `+fist:dejs:format` for the [+dejs](/docs/hoon/reference/zuse/2d_6) functions, which simply return `noun`s rather than `unit`s.
37+
38+---
39+
40+### `++ar:dejs-soft:format`
41+
42+Array as list (in unit)
43+
44+Convert array `jon` to a list, decoding each item in `jon` with `wit`. The result is wrapped in a unit which is null if the decoding failed.
45+
46+The `+ar` function is a wet gate that takes `wit` and produces a new gate which takes `jon`.
47+
48+#### Accepts
49+
50+`wit` is a `fist` and is the sample of the wet gate.
51+
52+`jon` is a `json` array containing the kind of `json` that `wit` handles. `jon` is the sample of the gate produced by the wet gate.
53+
54+#### Produces
55+
56+A `(unit (list [type]))` where `[type]` is the type produced by `wit`. The `unit` is null if decoding fails.
57+
58+#### Source
59+
60+```hoon
61+++ ar
62+ |* wit=fist
63+ |= jon=json
64+ ?. ?=([%a *] jon) ~
65+ %- zl
66+ |-
67+ ?~ p.jon ~
68+ [i=(wit i.p.jon) t=$(p.jon t.p.jon)]
69+```
70+
71+#### Examples
72+
73+```
74+> ((ar so):dejs-soft:format a+~[s+'foo' s+'bar' s+'baz'])
75+[~ [i='foo' t=<|bar baz|>]]
76+```
77+
78+```
79+> ((ar so):dejs-soft:format a+~[n+'123' s+'bar' s+'baz'])
80+~
81+```
82+
83+---
84+
85+### `++at:dejs-soft:format`
86+
87+Array as tuple (in unit)
88+
89+Convert array `jon` to a tuple, decoding each item in the array with the corresponding `fist` in list `wil`. The result is wrapped in a unit which is null if the decoding failed.
90+
91+The `+at` function is a wet gate that takes `wil` and produces a new gate which takes `jon`.
92+
93+#### Accepts
94+
95+`wil` is a `(pole fist)`, and is the sample of the wet gate. A `pole` is a faceless list.
96+
97+`jon` is a `json` array whose elements are the same kinds of `json` accepted by the `fist`s in `wil` and in the same order. `jon` is the sample of the gate produced by the wet gate.
98+
99+#### Produces
100+
101+A `(unit [n])` where `[n]` is a tuple containing items of the same type and in the same order as those produced by the `fist`s in `wil`. The `unit` is null if decoding failed.
102+
103+#### Source
104+
105+```hoon
106+++ at
107+ |* wil=(pole fist)
108+ |= jon=json
109+ ?. ?=([%a *] jon) ~
110+ ?. =((lent wil) (lent p.jon)) ~
111+ =+ raw=((at-raw wil) p.jon)
112+ ?.((za raw) ~ (some (zp raw)))
113+```
114+
115+#### Examples
116+
117+```
118+> ((at ~[so ni bo]):dejs-soft:format a+~[s+'foo' n+'123' b+&])
119+[~ ['foo' 123 %.y]]
120+```
121+
122+```
123+> ((at ~[so ni bo]):dejs-soft:format a+~[n+'123' s+'foo' b+&])
124+~
125+```
126+
127+---
128+
129+### `++at-raw:dejs-soft:format`
130+
131+Array as tuple, raw (unitized)
132+
133+This function is used internally by [+at](#atdejs-softformat) and would not typically be used directly.
134+
135+`+at-raw` converts list `jol` to a new list, decoding each item in the list with the corresponding function in list `wil`. Each item in the list gets wrapped in a unit, and any item whose decoding fails is null.
136+
137+The `+at-raw` function is a wet gate that takes `wil` and produces a new gate which takes `jol`.
138+
139+#### Accepts
140+
141+`wil` is a `(pole fist)`, and the sample of the wet gate. A `pole` is a faceless list.
142+
143+`jol` is a `(list json)` whose items are the same kinds of `json` accepted by the `fist`s in `wil` and in the same order. `jol` is the sample of the gate produced by the wet gate.
144+
145+#### Produces
146+
147+A list of the types and in the same order as those produced by the `fist`s in `wil`. Each item is wrapped in a unit and any item whose decoding fails is null.
148+
149+#### Source
150+
151+```hoon
152+++ at-raw
153+ |* wil=(pole fist)
154+ |= jol=(list json)
155+ ?~ wil ~
156+ :- ?~(jol ~ (-.wil i.jol))
157+ ((at-raw +.wil) ?~(jol ~ t.jol))
158+```
159+
160+#### Examples
161+
162+```
163+> ((at-raw ~[so ni bo]):dejs-soft:format ~[s+'foo' n+'123' b+&])
164+[[~ 'foo'] [~ 123] [~ %.y] ~]
165+```
166+
167+```
168+> ((at-raw ~[so ni bo]):dejs-soft:format ~[s+'foo' b+| b+&])
169+[[~ 'foo'] ~ [~ %.y] ~]
170+```
171+
172+---
173+
174+### `++bo:dejs-soft:format`
175+
176+Boolean (in unit)
177+
178+Convert boolean `jon` to a `?` and wrap the result in a unit. If decoding fails the unit is null.
179+
180+#### Accepts
181+
182+`jon` is a `json` boolean.
183+
184+#### Produces
185+
186+A `?` wrapped in a `unit`. The unit is null if the decoding failed.
187+
188+#### Source
189+
190+```hoon
191+++ bo
192+ |=(jon=json ?.(?=([%b *] jon) ~ [~ u=p.jon]))
193+```
194+
195+#### Examples
196+
197+```
198+> (bo:dejs-soft:format b+|)
199+[~ %.n]
200+```
201+
202+```
203+> (bo:dejs-soft:format n+'123')
204+~
205+```
206+
207+---
208+
209+### `++bu:dejs-soft:format`
210+
211+Boolean NOT (in unit)
212+
213+Convert the logical NOT of boolean `jon` to a `?`. The result is wrapped in a unit, if the decoding fails the unit is null.
214+
215+#### Accepts
216+
217+`jon` is a `json` boolean.
218+
219+#### Produces
220+
221+A `(unit ?)`. The `unit` is `~` if the decoding failed.
222+
223+#### Source
224+
225+```hoon
226+++ bu
227+ |=(jon=json ?.(?=([%b *] jon) ~ [~ u=!p.jon]))
228+```
229+
230+#### Examples
231+
232+```
233+> (bu:dejs-soft:format b+&)
234+[~ %.n]
235+```
236+
237+```
238+> (bu:dejs-soft:format n+'123')
239+~
240+```
241+
242+---
243+
244+### `++ci:dejs-soft:format`
245+
246+Maybe transform (in unit)
247+
248+Decode `jon` with `wit`, then transform it with gate `poq` which produces a unit. If the unit is null or the decoding fails it produces `~`, otherwise it produces the unit.
249+
250+The `+ci` function is a wet gate that takes a `poq` and `wit` and produces a new gate that takes `jon`.
251+
252+#### Accepts
253+
254+The wet gate takes `[poq wit]`, where `poq` is a `gate` that produces a `unit` and `wit` is a `fist`.
255+
256+`jon` is `json` of the kind accepted by `wit`. `jon` is the sample of the gate produced by the wet gate.
257+
258+#### Produces
259+
260+Produces `(unit [type])`, where `[type]` is the type of the data in the `unit` produced by `poq`. The `unit` is `~` if the decoding failed or if the `unit` produced by `poq` is `~`.
261+
262+#### Source
263+
264+```hoon
265+++ ci
266+ |* [poq=gate wit=fist]
267+ |= jon=json
268+ (biff (wit jon) poq)
269+```
270+
271+#### Examples
272+
273+```
274+> ((ci |=(a=? ?:(=(a &) `'foo' ~)) bo):dejs-soft:format b+&)
275+[~ 'foo']
276+```
277+
278+```
279+> ((ci |=(a=? ?:(=(a &) `'foo' ~)) bo):dejs-soft:format b+|)
280+~
281+```
282+
283+```
284+> ((ci |=(a=? ?:(=(a &) `'foo' ~)) bo):dejs-soft:format n+'123')
285+~
286+```
287+
288+---
289+
290+### `++cu:dejs-soft:format`
291+
292+Transform (in unit)
293+
294+Decode `jon` with `wit`, then transform it with gate `poq`. The result is wrapped in a unit, which is null if the decoding failed.
295+
296+The `+cu` function is a wet gate that takes `poq` and `wit` and produces a new gate that takes `jon`.
297+
298+#### Accepts
299+
300+The wet gate takes `[poq wit]`, where `poq` is a `gate` and `wit` is a `fist`.
301+
302+`jon` is `json` of the kind handled by `wit`. `jon` is the sample of the gate produced by the wet gate.
303+
304+#### Produces
305+
306+`(unit [type])`, where `[type]` is the type produced by the gate given in `poq`. The `unit` is `~` if the decoding failed.
307+
308+#### Source
309+
310+```hoon
311+++ cu
312+ |* [poq=gate wit=fist]
313+ |= jon=json
314+ (bind (wit jon) poq)
315+```
316+
317+#### Examples
318+
319+```
320+> ((cu |=(a=? ?:(=(a &) 'foo' ~)) bo):dejs-soft:format b+&)
321+[~ 'foo']
322+```
323+
324+```
325+> ((cu |=(a=? ?:(=(a &) 'foo' ~)) bo):dejs-soft:format b+|)
326+[~ ~]
327+```
328+
329+```
330+> ((cu |=(a=? ?:(=(a &) 'foo' ~)) bo):dejs-soft:format n+'123')
331+~
332+```
333+
334+---
335+
336+### `++da:dejs-soft:format`
337+
338+UTC date (in unit)
339+
340+Convert string `jon` to a `@da`, parsing it as a UTC date & time string, e.g.`'Thu, 09 Sep 2021 05:58:52'`. Note the inclusion of a timezone offset like `+1200` will pass the parser but will be ignored. The result is wrapped in a unit, which is null if decoding or parsing failed.
341+
342+#### Accepts
343+
344+`jon` is a `json` string encoding a UTC date & time string.
345+
346+#### Produces
347+
348+A `@da`.
349+
350+#### Examples
351+
352+```
353+> (da:dejs-soft:format s+'Thu, 09 Sep 2021 05:58:52')
354+[~ ~2021.9.9..05.58.52]
355+```
356+
357+```
358+> (da:dejs-soft:format s+'09 Sep 2021 05:58:52')
359+[~ ~2021.9.9..05.58.52]
360+```
361+
362+```
363+> (da:dejs-soft:format s+'Thu, 09 Sep 2021 05:58:52 +1200')
364+[~ ~2021.9.9..05.58.52]
365+```
366+
367+```
368+> (da:dejs-soft:format s+'gkjeagkja')
369+~
370+```
371+
372+```
373+> (da:dejs-soft:format b+&)
374+~
375+```
376+
377+---
378+
379+### `++dank:dejs-soft:format`
380+
381+Tank (in unit)
382+
383+Convert `jon`, a `json`-encoded `tank`, to a `tank`. The result is wrapped in a unit and is null if decoding failed.
384+
385+#### Accepts
386+
387+`jon` is `json`.
388+
389+#### Produces
390+
391+A `(unit tank)`. The `unit` is `~` if decoding failed.
392+
393+#### Source
394+
395+```hoon
396+++ dank
397+ ^- $-(json (unit tank))
398+ %+ re *tank |. ~+
399+ %- of :~
400+ leaf+sa
401+ palm+(ot style+(ot mid+sa cap+sa open+sa close+sa ~) lines+(ar dank) ~)
402+ rose+(ot style+(ot mid+sa open+sa close+sa ~) lines+(ar dank) ~)
403+ ==
404+```
405+
406+#### Examples
407+
408+```
409+> =js-txt '{"rose":{"lines":[{"leaf":"foo"},{"leaf":"bar"},{"leaf":"baz"}],"style":{"mid":" ","close":"]","open":"["}}}'
410+> (dank:dejs-soft:format (need (de-json:html js-txt)))
411+[~ [%rose p=[p=" " q="[" r="]"] q=~[[%leaf p="foo"] [%leaf p="bar"] [%leaf p="baz"]]]]
412+> ~(ram re (need (dank:dejs-soft:format (need (de-json:html js-txt)))))
413+"[foo bar baz]"
414+```
415+
416+```
417+> (dank:dejs-soft:format (need (de-json:html '{"leaf":"foo"}')))
418+[~ [%leaf p="foo"]]
419+> ~(ram re (need (dank:dejs-soft:format (need (de-json:html '{"leaf":"foo"}')))))
420+"foo"
421+```
422+
423+```
424+> (dank:dejs-soft:format n+'123')
425+~
426+```
427+
428+---
429+
430+### `++di:dejs-soft:format`
431+
432+Millisecond date (in unit)
433+
434+Convert number `jon` containing milliseconds to a date. The result is wrapped in a unit which is null if decoding failed.
435+
436+#### Accepts
437+
438+`jon` is a `json` number.
439+
440+#### Produces
441+
442+A `(unit @da)`. The `unit` is `~` if decoding failed.
443+
444+#### Source
445+
446+```hoon
447+++ di
448+ (cu from-unix-ms:chrono:userlib ni)
449+```
450+
451+#### Examples
452+
453+```
454+> =time (time:enjs:format now)
455+> time
456+[%n p=~.1631177855330]
457+> (di:dejs-soft:format time)
458+[~ ~2021.9.9..08.57.35..547a.e147.ae14.7ae1]
459+```
460+
461+```
462+> (di:dejs-soft:format b+&)
463+~
464+```
465+
466+---
467+
468+### `++mu:dejs-soft:format`
469+
470+True unit (in unit)
471+
472+Decode `jon` with `wit`, then wrap it in two units. The inner unit is null if `jon` was null, the outer unit is null if decoding failed.
473+
474+The `+mu` function is a wet gate that takes `wit` and produces a gate which takes `jon`.
475+
476+#### Accepts
477+
478+`wit` is a `fist`, and is the sample of the wet gate.
479+
480+`jon` is `json` of the kind `wit` handles. `jon` is the sample of the gate produced by the wet gate.
481+
482+#### Produces
483+
484+A `(unit (unit [type]))`, where `[type]` is the type produced by `wit`. The inner `unit` is `~` if `jon` was null, the outer `unit` is `~` if decoding failed.
485+
486+#### Source
487+
488+```hoon
489+++ mu
490+ |* wit=fist
491+ |= jon=json
492+ ?~(jon (some ~) (bind (wit jon) some))
493+```
494+
495+#### Examples
496+
497+```
498+> ((mu so):dejs-soft:format s+'foo')
499+[~ [~ u='foo']]
500+```
501+
502+```
503+> ((mu so):dejs-soft:format ~)
504+[~ u=~]
505+```
506+
507+```
508+> ((mu so):dejs-soft:format b+&)
509+~
510+```
511+
512+---
513+
514+### `++ne:dejs-soft:format`
515+
516+Number as real (in unit)
517+
518+Convert number `jon` to a `@rd` and wrap the result in a unit. The unit is null if decoding failed.
519+
520+#### Accepts
521+
522+`jon` is a `json` number.
523+
524+#### Produces
525+
526+A `(unit @rd)`. The `unit` is `~` if decoding failed.
527+
528+#### Source
529+
530+```hoon
531+++ ne
532+ |= jon=json
533+ ^- (unit @rd)
534+ ?. ?=([%n *] jon) ~
535+ (rush p.jon (cook ryld (cook royl-cell:^so json-rn)))
536+```
537+
538+#### Examples
539+
540+```
541+> (ne:dejs-soft:format n+'123')
542+[~ .~123]
543+```
544+
545+```
546+> (ne:dejs-soft:format n+'2.47')
547+[~ .~2.47]
548+```
549+
550+```
551+> (ne:dejs-soft:format b+&)
552+~
553+```
554+
555+---
556+
557+### `++ni:dejs-soft:format`
558+
559+Number as integer (in unit)
560+
561+Convert number `jon` to a `@ud` and wrap it in a unit. If `jon` is not an integer or if decoding otherwise failed, the unit is null.
562+
563+#### Accepts
564+
565+`jon` is a `json` number.
566+
567+#### Produces
568+
569+A `(unit @ud)`. The `unit` is `~` if `jon` was not an integer or if decoding otherwise failed.
570+
571+#### Source
572+
573+```hoon
574+++ ni
575+ |= jon=json
576+ ?. ?=([%n *] jon) ~
577+ (rush p.jon dem)
578+```
579+
580+#### Examples
581+
582+```
583+> (ni:dejs-soft:format n+'123')
584+[~ 123]
585+```
586+
587+```
588+> (ni:dejs-soft:format n+'2.47')
589+~
590+```
591+
592+```
593+> (ni:dejs-soft:format b+&)
594+~
595+```
596+
597+---
598+
599+### `++no:dejs-soft:format`
600+
601+Number as knot (in unit)
602+
603+Convert number `jon` to a `@ta` and wrap it in a unit. The result is null if decoding failed.
604+
605+#### Accepts
606+
607+`jon` is a `json` number.
608+
609+#### Produces
610+
611+A `(unit @ta)`. The `unit` is `~` if decoding failed.
612+
613+#### Source
614+
615+```hoon
616+++ no
617+ |= jon=json
618+ ?. ?=([%n *] jon) ~
619+ (some p.jon)
620+```
621+
622+#### Examples
623+
624+```
625+> (no:dejs-soft:format n+'2.47')
626+[~ ~.2.47]
627+```
628+
629+```
630+> (no:dejs-soft:format n+'123')
631+[~ ~.123]
632+```
633+
634+```
635+> (no:dejs-soft:format b+&)
636+~
637+```
638+
639+---
640+
641+### `++of:dejs-soft:format`
642+
643+Object as frond (in unit)
644+
645+Convert object `jon`, which contains a single key-value pair, to a key-value tuple using the `fist` in `wer` which matches the key. The result is wrapped in a unit which is null if the key couldn't be found in `wer` or if the decoding failed.
646+
647+The `+of` function is a wet gate that takes a list of pairs of keys and `fist`s and produces a new gate that takes `json`.
648+
649+**Note:** While technically the type of an item in the list `wer` is specified as `[cord fist]`, actually using a `cord` may result in incorrect type inferrence. Instead, you'll want to format it as a `@tas` like `%foo`, so the type system correctly interprets it as a tagged union. If the key contains characters that would be invalid in an ordinary `@tas`, you can format it like `%'foo_bar'` - a `%` then single quotes.
650+
651+#### Accepts
652+
653+`wer` is a `(pole [cord fist])`, and is the sample of the wet gate. A `pole` is a faceless `list`.
654+
655+`jon` is a `json` object containing a single key. `jon` is the sample of the gate produced by the wet gate.
656+
657+#### Produces
658+
659+A `(unit [@t [type]])` where `[type]` is the type produced by the matching `fist`. The `unit` is `~` if decoding failed or the key could not be found.
660+
661+#### Source
662+
663+```hoon
664+++ of
665+ |* wer=(pole [cord fist])
666+ |= jon=json
667+ ?. ?=([%o [@ *] ~ ~] jon) ~
668+ |-
669+ ?~ wer ~
670+ ?: =(-.-.wer p.n.p.jon)
671+ ((pe -.-.wer +.-.wer) q.n.p.jon)
672+ ((of +.wer) jon)
673+```
674+
675+#### Examples
676+
677+First, let's store some objects containing key-value pairs:
678+
679+```
680+> =obj-1 o+(malt ['foo' s+'hello']~)
681+> (crip (en-json:html obj-1))
682+'{"foo":"hello"}'
683+```
684+
685+```
686+> =obj-2 o+(malt ~[['bar' a+~[n+'123' n+'456']]])
687+> (crip (en-json:html obj-2))
688+'{"bar":[123,456]}'
689+```
690+
691+```
692+> =obj-3 o+(malt ['baz' b+&]~)
693+> (crip (en-json:html obj-3))
694+'{"baz":true}'
695+```
696+
697+Next, let's construct a `+of` function and try it on our objects:
698+
699+```
700+> ((of ~[foo+so bar+(ar ni)]):dejs-soft:format obj-1)
701+[~ [%foo 'hello']]
702+```
703+
704+```
705+> ((of ~[foo+so bar+(ar ni)]):dejs-soft:format obj-2)
706+[~ [%bar [i=123 t=~[456]]]]
707+```
708+
709+```
710+> ((of ~[foo+so bar+(ar ni)]):dejs-soft:format obj-3)
711+~
712+```
713+
714+```
715+> ((of ~[foo+so bar+(ar ni)]):dejs-soft:format b+&)
716+~
717+```
718+
719+---
720+
721+### `++ot:dejs-soft:format`
722+
723+Object as tuple (in unit)
724+
725+Convert object `jon` to a tuple by decoding each value with the matching `fist` in `wer`. Each key in `wer` must be matched to a key in `jon`. On the other hand, if there are keys in `jon` with no corresponding key in `wer`, they'll simply be ignored. The result is wrapped in a unit which is null if decoding failed.
726+
727+The `+ot` function is a wet gate that takes a list of key-`fist` pairs, and produces a gate which takes `json`.
728+
729+**Note:** While technically the type of an item in the list `wer` is specified as `[cord fist]`, actually using a `cord` may result in incorrect type inferrence. Instead, you'll want to format it as a `@tas` like `%foo`, so the type system correctly interprets it as a tagged union. If the key contains characters that would be invalid in an ordinary `@tas`, you can format it like `%'foo_bar'` - a `%` then single quotes.
730+
731+#### Accepts
732+
733+`wer` is a `(pole [cord fist])`, and is the sample of the wet gate. A `pole` is a faceless list.
734+
735+`jon` is a `json` object, and is the sample of the gate produced by the wet gate.
736+
737+#### Produces
738+
739+A `(unit [tuple])` where the type of each item in `[tuple]` is the product of the corresponding `fist` in `wer`. The order of items in the tuple will match the order of items in `wer`. The `unit` is `~` if decoding failed.
740+
741+#### Source
742+
743+```hoon
744+++ ot
745+ |* wer=(pole [cord fist])
746+ |= jon=json
747+ ?. ?=([%o *] jon) ~
748+ =+ raw=((ot-raw wer) p.jon)
749+ ?.((za raw) ~ (some (zp raw)))
750+```
751+
752+#### Examples
753+
754+```
755+> %- (ot ~[foo+so bar+ni]):dejs-soft:format
756+ o+(malt (limo ~[['bar' n+'123'] ['foo' s+'hello'] ['baz' b+&]]))
757+[~ ['hello' 123]]
758+```
759+
760+```
761+> %- (ot ~[foo+so bar+ni]):dejs-soft:format
762+ o+(malt (limo ~[['bar' n+'123'] ['baz' b+&]]))
763+~
764+```
765+
766+---
767+
768+### `++ot-raw:dejs-soft:format`
769+
770+Object as list of units, raw
771+
772+This function is used internally by [+ot](#otdejs-softformat) and would not typically be used directly.
773+
774+`+ot-raw` converts map `jom` to a list of units by decoding each value with the matching `fist` in `wer`, then wrapping them in a unit. Any key in `wer` which cannot be matched to a key in `jon` is null in the resulting list. If there are keys in `jom` with no corresponding key in `wer`, they'll simply be ignored.
775+
776+The `+ot-raw` function is a wet gate that takes a list of key-`fist` pairs, and produces a gate which takes a map of keys to `json`.
777+
778+**Note:** While technically the type of an item in the list `wer` is specified as `[cord fist]`, actually using a `cord` may result in incorrect type inferrence. Instead, you'll want to format it as a `@tas` like `%foo`, so the type system correctly interprets it as a tagged union. If the key contains characters that would be invalid in an ordinary `@tas`, you can format it like `%'foo_bar'` - a `%` then single quotes.
779+
780+#### Accepts
781+
782+`wer` is a `(pole [cord fist])`, and is the sample of the wet gate. A `pole` is a faceless list.
783+
784+`jom` is a `(map @t json)`, and is the sample of the gate produced by the wet gate.
785+
786+#### Produces
787+
788+A `(list (unit))`, where the type of the data in each `unit` is the product of the corresponding `fist` in `wer`. The order of items in the list will match the order of items in `wer`. Any keys in `wer` which couldn't be matched will be `~` in the resulting list.
789+
790+#### Source
791+
792+```hoon
793+++ ot-raw
794+ |* wer=(pole [cord fist])
795+ |= jom=(map @t json)
796+ ?~ wer ~
797+ =+ ten=(~(get by jom) -.-.wer)
798+ [?~(ten ~ (+.-.wer u.ten)) ((ot-raw +.wer) jom)]
799+```
800+
801+#### Examples
802+
803+```
804+> %- (ot-raw ~[foo+so bar+ni]):dejs-soft:format
805+ (malt (limo ~[['bar' n+'123'] ['foo' s+'hello'] ['baz' b+&]]))
806+[[~ 'hello'] [~ 123] ~]
807+```
808+
809+```
810+> %- (ot-raw ~[foo+so bar+ni]):dejs-soft:format
811+ (malt (limo ~[['bar' n+'123'] ['baz' b+&]]))
812+[~ [~ 123] ~]
813+```
814+
815+---
816+
817+### `++om:dejs-soft:format`
818+
819+Object as map (in unit)
820+
821+Convert object `jon` to a map, decoding each value with `wit`. The result is wrapped in a unit which is null if decoding failed.
822+
823+The `+om` function is a wet gate that takes `wit` and produces a gate that takes `jon`.
824+
825+#### Accepts
826+
827+`wit` is a `fist`, and is the sample of the wet gate.
828+
829+`jon` is a `json` object whose values are the kind of `json` that `wit` takes. `jon` is the sample of the gate produced by the wet gate.
830+
831+#### Produces
832+
833+A `(unit (map @t [type]))`, where `[type]` is the type produced by `wit`. The `unit` is `~` if decoding failed.
834+
835+#### Source
836+
837+```hoon
838+++ om
839+ |* wit=fist
840+ |= jon=json
841+ ?. ?=([%o *] jon) ~
842+ (zm (~(run by p.jon) wit))
843+```
844+
845+#### Examples
846+
847+```
848+> =jon (need (de-json:html '{"foo":"aaa","bar":"bbb"}'))
849+> ((om so):dejs-soft:format jon)
850+[~ {[p='bar' q='bbb'] [p='foo' q='aaa']}]
851+```
852+
853+```
854+> ((om so):dejs-soft:format b+&)
855+~
856+```
857+
858+---
859+
860+### `++op:dejs-soft:format`
861+
862+Parse keys of map (in unit)
863+
864+Convert object `jon` to a map, parsing each key with `fel` and decoding each value with `wit`. The result is wrapped in a unit which is null if decoding or parsing failed.
865+
866+The `+op` function is a wet gate that takes `fel` and `wit`, and produces a gate that takes `jon`.
867+
868+#### Accepts
869+
870+The wet gate takes a cell of `[fel wil]`, where `fel` is a parsing `rule` and `wil` is a `fist`.
871+
872+`jon` is a `json` object, whose keys are parsable by `fel` and whose values are `json` of the kind `wit` takes. `jon` is the sample of the gate produced by the wet gate.
873+
874+#### Produces
875+
876+A `(unit (map [a] [b]))` where `[a]` is the type produced by `fel` and `[b]` is the type produced by `wit`. The `unit` is `~` if decoding or parsing failed.
877+
878+#### Source
879+
880+```hoon
881+++ op
882+ |* [fel=rule wit=fist]
883+ |= jon=json ^- (map _(wonk *fel) _*wit)
884+ =/ jom ((om wit) jon)
885+ %- malt
886+ %+ turn ~(tap by jom)
887+ |* [a=cord b=*]
888+ => .(+< [a b]=+<)
889+ [(rash a fel) b]
890+```
891+
892+#### Examples
893+
894+```
895+> =jon (need (de-json:html '{"123":"aaa","456":"bbb"}'))
896+> ((op dem so):dejs-soft:format jon)
897+[~ u={[p=456 q='bbb'] [p=123 q='aaa']}]
898+```
899+
900+---
901+
902+### `++pe:dejs-soft:format`
903+
904+Prefix (in unit)
905+
906+Decode `jon` with `wit`, prefix it with `pre`, then wrap the result in a unit which is null if decoding failed.
907+
908+The `+pe` function is a wet gate that takes `pre` and `wit`, and produces a gate that takes `jon`.
909+
910+#### Accepts
911+
912+The wet gate takes a cell of `[pre wit]`, where `pre` is any noun and `wit` is a `fist`.
913+
914+`jon` is `json` of the kind accepted by `wit`. `jon` is the sample of the gate produced by the wet gate.
915+
916+#### Produces
917+
918+A `(unit [[a] [b]])`, where `[a]` is the noun given in `pre` and `[b]` is the type produced by `wit`. The `unit` is `~` if decoding failed.
919+
920+#### Source
921+
922+```hoon
923+++ pe
924+ |* [pre=* wit=fist]
925+ (cu |*(* [pre +<]) wit)
926+```
927+
928+#### Examples
929+
930+```
931+> ((pe %foo so):dejs-soft:format s+'abc')
932+[~ [%foo 'abc']]
933+```
934+
935+```
936+> ((pe %foo so):dejs-soft:format b+&)
937+~
938+```
939+
940+---
941+
942+### `++re:dejs-soft:format`
943+
944+Recursive reparser
945+
946+This function facilitates recursion in other `fist`s. It is used internally by some functions and would not typically be used directly. `jon` is decoded by the `fist` in the trap `sef` and cast to the type of the noun given in `gar`. The result is wrapped in a unit which is null if decoding failed.
947+
948+`+re` is a wet gate that takes a cell of `gar` and `sef`, and produces a gate which takes `jon`.
949+
950+#### Accepts
951+
952+`gar` is any `noun`, its type determines the return type.
953+
954+`sef` is a `|.(fist)`.
955+
956+The wet gate takes `[gar sef]`.
957+
958+`jon` is `json` of the kind handled by the `fist` in `sef`, and is the sample of the gate produced by the wet gate.
959+
960+#### Produces
961+
962+A `(unit [type])` where `[type]` is the type of `gar`.
963+
964+#### Source
965+
966+```hoon
967+++ re
968+ |* [gar=* sef=_|.(fist)]
969+ |= jon=json
970+ ^- (unit _gar)
971+ ((sef) jon)
972+```
973+
974+#### Examples
975+
976+The basic format looks like so:
977+
978+```
979+> ((re *@t |.(so)):dejs-soft:format s+'abc')
980+[~ 'abc']
981+```
982+
983+```
984+> ((re *@t |.(so)):dejs-soft:format b+&)
985+~
986+```
987+
988+For a recursive example, see its usage in the source of [+dank](#dankdejs-softformat).
989+
990+---
991+
992+### `++sa:dejs-soft:format`
993+
994+String as tape (in unit)
995+
996+Convert `jon` to a `tape` and wrap the result in a unit, which is null if the decoding failed.
997+
998+#### Accepts
999+
1000+`jon` is a `json` string.
1001+
1002+#### Produces
1003+
1004+A `(unit tape)`. The `unit` is `~` if decoding failed.
1005+
1006+#### Source
1007+
1008+```hoon
1009+++ sa
1010+ |= jon=json
1011+ ?.(?=([%s *] jon) ~ (some (trip p.jon)))
1012+```
1013+
1014+#### Examples
1015+
1016+```
1017+> (sa:dejs-soft:format s+'foo')
1018+[~ "foo"]
1019+```
1020+
1021+```
1022+> (sa:dejs-soft:format b+&)
1023+~
1024+```
1025+
1026+---
1027+
1028+### `++so:dejs-soft:format`
1029+
1030+String as cord (in unit)
1031+
1032+Convert `jon` to a cord and wrap it in a unit. The unit is null if decoding failed.
1033+
1034+#### Accepts
1035+
1036+`jon` is a `json` string.
1037+
1038+#### Produces
1039+
1040+A `(unit @t)`. The `unit` is `~` if decoding failed.
1041+
1042+#### Source
1043+
1044+```hoon
1045+++ so
1046+ |= jon=json
1047+ ?.(?=([%s *] jon) ~ (some p.jon))
1048+```
1049+
1050+#### Examples
1051+
1052+```
1053+> (so:dejs-soft:format s+'foo')
1054+[~ 'foo']
1055+```
1056+
1057+```
1058+> (so:dejs-soft:format b+&)
1059+~
1060+```
1061+
1062+---
1063+
1064+### `++su:dejs-soft:format`
1065+
1066+Parse string (in unit)
1067+
1068+Convert and parse `jon` with `sab`, then wrap the result in a unit. The unit is null if parsing or decoding failed.
1069+
1070+The `+su` function is a wet gate that takes `sab`, and produces a gate that takes `jon`.
1071+
1072+#### Accepts
1073+
1074+`sab` is a parsing `rule`, and is the sample of the wet gate.
1075+
1076+`jon` is a `json` string, and is the sample of the gate produced by the wet gate.
1077+
1078+#### Produces
1079+
1080+A `(unit [type])`, where `[type]` is the type produced by `sab`.
1081+
1082+#### Source
1083+
1084+```hoon
1085+++ su
1086+ |* sab=rule
1087+ |= jon=json
1088+ ?. ?=([%s *] jon) ~
1089+ (rush p.jon sab)
1090+```
1091+
1092+#### Examples
1093+
1094+```
1095+> ((su dem):dejs-soft:format s+'123456')
1096+[~ 123.456]
1097+```
1098+
1099+```
1100+> `(unit @ub)`((su bin):dejs-soft:format s+'00001011101110001101')
1101+[~ 0b1011.1011.1000.1101]
1102+```
1103+
1104+```
1105+> ((su dem):dejs-soft:format s+'abc')
1106+~
1107+```
1108+
1109+```
1110+> ((su dem):dejs-soft:format b+&)
1111+~
1112+```
1113+
1114+---
1115+
1116+### `++ul:dejs-soft:format`
1117+
1118+Null (in unit)
1119+
1120+Return `[~ ~]` if `jon` is null or else return `~`.
1121+
1122+#### Accepts
1123+
1124+`jon` is null `json`.
1125+
1126+#### Produces
1127+
1128+A `(unit ~)`. The `unit` is `~` if `jon` is not `~`.
1129+
1130+#### Source
1131+
1132+```hoon
1133+++ ul |=(jon=json ?~(jon (some ~) ~))
1134+```
1135+
1136+#### Examples
1137+
1138+```
1139+> (ul:dejs-soft:format ~)
1140+[~ ~]
1141+```
1142+
1143+```
1144+> (ul:dejs-soft:format b+&)
1145+~
1146+```
1147+
1148+### `++za:dejs-soft:format`
1149+
1150+Full unit pole
1151+
1152+Check whether all units in list `pod` are non-null. This is used internally by some functions and would not typically be used directly.
1153+
1154+#### Accepts
1155+
1156+`pod` is a `(pole (unit))`. A `pole` is a faceless list.
1157+
1158+#### Produces
1159+
1160+A `?`, which is `%.n` if any of the `unit`s in `pod` are `~`, and `%.y` otherwise.
1161+
1162+#### Source
1163+
1164+```hoon
1165+++ za
1166+ |* pod=(pole (unit))
1167+ ?~ pod &
1168+ ?~ -.pod |
1169+ (za +.pod)
1170+```
1171+
1172+#### Examples
1173+
1174+```
1175+> (za:dejs-soft:format ~[`1 `2 `3 `4])
1176+%.y
1177+```
1178+
1179+```
1180+> (za:dejs-soft:format ~)
1181+%.y
1182+```
1183+
1184+```
1185+> (za:dejs-soft:format ~[`1 `2 ~ `4])
1186+%.n
1187+```
1188+
1189+---
1190+
1191+### `++zl:dejs-soft:format`
1192+
1193+Collapse unit list
1194+
1195+Convert `lut`, a list of units, to a `(unit (list))` by stripping the unit from each item. The resulting unit is null if any of the units in the list are null. This is used internally by some functions, you would not typically use it directly.
1196+
1197+#### Accepts
1198+
1199+A `(list (unit))`.
1200+
1201+#### Produces
1202+
1203+A `(unit (list))` which is null if any of the units in `lut` were null.
1204+
1205+#### Source
1206+
1207+```hoon
1208+++ zl
1209+ |* lut=(list (unit))
1210+ ?. |- ^- ?
1211+ ?~(lut & ?~(i.lut | $(lut t.lut)))
1212+ ~
1213+ %- some
1214+ |-
1215+ ?~ lut ~
1216+ [i=u:+.i.lut t=$(lut t.lut)]
1217+```
1218+
1219+#### Examples
1220+
1221+```
1222+> (zl:dejs-soft:format (limo ~[`1 `2 `3 `4 `5 `6]))
1223+[~ [i=1 t=~[2 3 4 5 6]]]
1224+```
1225+
1226+```
1227+> (zl:dejs-soft:format (limo ~[`1 `2 ~ `4 `5 `6]))
1228+~
1229+```
1230+
1231+---
1232+
1233+### `++zp:dejs-soft:format`
1234+
1235+Unit tuple
1236+
1237+Convert `but`, a list of units, to a tuple by stripping the unit from each item. Crashes if any of the units are null. This is used internally by some functions, you would not typically use it directly.
1238+
1239+#### Accepts
1240+
1241+`but` is a `(pole (unit))`. A `pole` is a faceless list.
1242+
1243+#### Produces
1244+
1245+A tuple containing each unwrapped element from the original list, or crashes if any of the units were null.
1246+
1247+#### Source
1248+
1249+```hoon
1250+++ zp
1251+ |* but=(pole (unit))
1252+ ?~ but !!
1253+ ?~ +.but
1254+ u:->.but
1255+ [u:->.but (zp +.but)]
1256+```
1257+
1258+#### Examples
1259+
1260+```
1261+> (zp:dejs-soft:format ~[`1 `2 `3 `4 `5 `6])
1262+[1 2 3 4 5 6]
1263+```
1264+
1265+```
1266+> (zp:dejs-soft:format ~[`1 `2 ~ `4 `5 `6])
1267+mull-none
1268+dojo: hoon expression failed
1269+```
1270+
1271+---
1272+
1273+### `++zm:dejs-soft:format`
1274+
1275+Collapse unit map
1276+
1277+Strip units from values in `lum`, a map of units. Returns null if any of the units are null. This is used internally by some functions, you would not typically use it directly.
1278+
1279+#### Accepts
1280+
1281+`lum` is a `(map term (unit))`
1282+
1283+#### Produces
1284+
1285+A `(unit (map term [type]))`, where `[type]` is the type the units in `lum` contained. Produces `~` if any of the units were null.
1286+
1287+#### Source
1288+
1289+```hoon
1290+++ zm
1291+ |* lum=(map term (unit))
1292+ ?: (~(rep by lum) |=([[@ a=(unit)] b=_|] |(b ?=(~ a))))
1293+ ~
1294+ (some (~(run by lum) need))
1295+```
1296+
1297+#### Examples
1298+
1299+```
1300+> (zm:dejs-soft:format (malt ~[['foo' `1] ['bar' `2]]))
1301+[~ {[p='bar' q=2] [p='foo' q=1]}]
1302+```
1303+
1304+```
1305+> (zm:dejs-soft:format (malt (limo ~[['foo' `1] ['bar' ~]])))
1306+~
1307+```
content/docs/hoon/reference/zuse/2e_2-3.mdnew file+67
@@ -0,0 +1,67 @@
1++++
2+title = "2e(2-3): Print & Parse JSON"
3+weight = 50
4+template = "doc.html"
5++++
6+
7+## `++en-json:html`
8+
9+Print json
10+
11+Encode `val`, a `json` structure, in a `tape`.
12+
13+#### Accepts
14+
15+`val` is any `json`.
16+
17+#### Produces
18+
19+A `tape`.
20+
21+#### Source
22+
23+This is a very large function, refer to `zuse.hoon` for the source code.
24+
25+#### Examples
26+
27+```
28+> (en-json:html s+'foo')
29+"\"foo\""
30+```
31+
32+```
33+> (en-json:html o+(malt (limo ~[['foo' s+'xxx'] ['bar' n+'123'] ['baz' b+&]])))
34+"\{\"foo\":\"xxx\",\"baz\":true,\"bar\":123}"
35+```
36+
37+---
38+
39+## `++de-json:html`
40+
41+Parse json
42+
43+Parse cord `a` to a `json` structure. The result is wrapped in a unit which is null if parsing failed.
44+
45+#### Accepts
46+
47+`a` is a `cord` in which JSON is encoded.
48+
49+#### Produces
50+
51+A `(unit json)`. The `unit` is `~` if parsing failed.
52+
53+#### Source
54+
55+This is a very large function, refer to `zuse.hoon` for the source code.
56+
57+#### Examples
58+
59+```
60+> (de-json:html '{"foo":"xxx","baz":true,"bar":123}')
61+[~ [%o p={[p='bar' q=[%n p=~.123]] [p='baz' q=[%b p=%.y]] [p='foo' q=[%s p='xxx']]}]]
62+```
63+
64+```
65+> (de-json:html '"foo"')
66+[~ [%s p='foo']]
67+```
content/docs/hoon/reference/zuse/_index.mdnew file+31
@@ -0,0 +1,31 @@
1++++
2+title = "Zuse"
3+weight = 50
4+sort_by = "weight"
5+template = "sections/docs/chapters.html"
6+insert_anchor_links = "right"
7++++
8+
9+Documentation for the `zuse.hoon` library.
10+
11+[Table of Contents](/docs/hoon/reference/zuse/table-of-contents)
12+
13+### 2d: Formatting functions
14+
15+[2d(1-5): To JSON, Wains](/docs/hoon/reference/zuse/2d_1-5)
16+
17+Functions for encoding/decoding line-lists and various JSON encoding functions.
18+
19+[2d(6): From JSON](/docs/hoon/reference/zuse/2d_6)
20+
21+Functions for decoding `json`.
22+
23+[2d(7): From JSON (unit)](/docs/hoon/reference/zuse/2d_7)
24+
25+Functions for decoding `json` to `unit`s.
26+
27+### 2e: Web Text Functions
28+
29+[2e(2-3): Print & Parse JSON](/docs/hoon/reference/zuse/2e_2-3)
30+
31+Print `json` and parse JSON.
content/docs/hoon/reference/zuse/table-of-contents.mdnew file+247
@@ -0,0 +1,247 @@
1++++
2+title = "Table of Contents"
3+weight = 0
4+sort_by = "weight"
5+template = "doc.html"
6++++
7+
8+Documentation for the Zuse library.
9+
10+Can be navigated [alphabetically](#alphabetical) or [by section](#by-section).
11+
12+## Alphabetical
13+
14+### a
15+
16+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#ardejs-softformat' title="Decode json (unit): Array as list"><code>++ar:dejs-soft:format</code></a>
17+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ardejsformat' title="Decode json: Array as list"><code>++ar:dejs:format</code></a>
18+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#asdejsformat' title="Decode json: Array as set"><code>++as:dejs:format</code></a>
19+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#at-rawdejs-softformat' title="Decode json (unit): Array as tuple, raw"><code>++at-raw:dejs-soft:format</code></a>
20+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#at-rawdejsformat' title="Decode json: Array as tuple, raw"><code>++at-raw:dejs:format</code></a>
21+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#atdejs-softformat' title="Decode json (unit): Array as tuple"><code>++at:dejs-soft:format</code></a>
22+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#atdejsformat' title="Decode json: Array as tuple"><code>++at:dejs:format</code></a>
23+
24+### b
25+
26+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#bodejs-softformat' title="Decode json (unit): Boolean"><code>++bo:dejs-soft:format</code></a>
27+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#bodejsformat' title="Decode json: Boolean"><code>++bo:dejs:format</code></a>
28+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#budejs-softformat' title="Decode json (unit): Boolean NOT"><code>++bu:dejs-soft:format</code></a>
29+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#budejsformat' title="Decode json: Boolean NOT"><code>++bu:dejs:format</code></a>
30+
31+### c
32+
33+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#cidejs-softformat' title="Decode json (unit): Maybe transform"><code>++ci:dejs-soft:format</code></a>
34+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#cidejsformat' title="Decode json: Maybe transform"><code>++ci:dejs:format</code></a>
35+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#cudejs-softformat' title="Decode json (unit): Transform"><code>++cu:dejs-soft:format</code></a>
36+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#cudejsformat' title="Decode json: Transform"><code>++cu:dejs:format</code></a>
37+
38+### d
39+
40+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#dadejs-softformat' title="Decode json (unit): UTC date"><code>++da:dejs-soft:format</code></a>
41+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#dankdejs-softformat' title="Decode json (unit): Tank"><code>++dank:dejs-soft:format</code></a>
42+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#dejs-softformat' title="Container arm for unitized JSON decoding reparsers"><code>++dejs-soft:format</code></a>
43+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#dejsformat' title="Container arm for JSON decoding reparsers"><code>++dejs:format</code></a>
44+<a class="tooltip" href='/docs/hoon/reference/zuse/2e_2-3/#de-jsonhtml' title="Parse JSON"><code>++de-json:html</code></a>
45+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#didejs-softformat' title="Decode json (unit): Millisecond date"><code>++di:dejs-soft:format</code></a>
46+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#didejsformat' title="Decode json: Millisecond date"><code>++di:dejs:format</code></a>
47+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#dudejsformat' title="Decode json: Second date"><code>++du:dejs:format</code></a>
48+
49+### e
50+
51+<a class="tooltip" href='/docs/hoon/reference/zuse/2e_2-3/#en-jsonhtml' title="Parse JSON"><code>++en-json:html</code></a>
52+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#enjsformat' title="Container arm for JSON encoders"><code>++enjs:format</code></a>
53+
54+### f
55+
56+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#frondenjsformat' title="Encode json: Object from key-value pair"><code>++frond:enjs:format</code></a>
57+
58+### j
59+
60+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#json-rnformat' title="Json to rn parser"><code>++json-rn:format</code></a>
61+
62+### m
63+
64+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#mudejs-softformat' title="Decode json (unit): True unit"><code>++mu:dejs-soft:format</code></a>
65+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#mudejsformat' title="Decode json: True unit"><code>++mu:dejs:format</code></a>
66+
67+### n
68+
69+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#nedejs-softformat' title="Decode json (unit): Number as real"><code>++ne:dejs-soft:format</code></a>
70+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#nedejsformat' title="Decode json: Number as real"><code>++ne:dejs:format</code></a>
71+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#nidejs-softformat' title="Decode json (unit): Number as integer"><code>++ni:dejs-soft:format</code></a>
72+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#nidejsformat' title="Decode json: Number as integer"><code>++ni:dejs:format</code></a>
73+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#nodejs-softformat' title="Decode json (unit): Number as knot"><code>++no:dejs-soft:format</code></a>
74+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#nodejsformat' title="Decode json: Number as knot"><code>++no:dejs:format</code></a>
75+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#nudejsformat' title="Decode json: Parse string as hex"><code>++nu:dejs:format</code></a>
76+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#numbenjsformat' title="Encode json: Number from unsigned"><code>++numb:enjs:format</code></a>
77+
78+### o
79+
80+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#of-wainformat' title="Line list to cord"><code>++of-wain:format</code></a>
81+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#of-wallformat' title="Line list to tape"><code>++of-wall:format</code></a>
82+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#ofdejs-softformat' title="Decode json (unit): Object as frond"><code>++of:dejs-soft:format</code></a>
83+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ofdejsformat' title="Decode json: Object as frond"><code>++of:dejs:format</code></a>
84+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ojdejsformat' title="Decode json: Object as jug"><code>++oj:dejs:format</code></a>
85+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#omdejs-softformat' title="Decode json (unit): Object as map"><code>++om:dejs-soft:format</code></a>
86+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#omdejsformat' title="Decode json: Object as map"><code>++om:dejs:format</code></a>
87+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#opdejs-softformat' title="Decode json (unit): Parse keys of map"><code>++op:dejs-soft:format</code></a>
88+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#opdejsformat' title="Decode json: Parse keys of map"><code>++op:dejs:format</code></a>
89+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#ot-rawdejs-softformat' title="Decode json (unit): Object as list of units, raw"><code>++ot-raw:dejs-soft:format</code></a>
90+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ot-rawdejsformat' title="Decode json: Object as tuple, raw"><code>++ot-raw:dejs:format</code></a>
91+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#otdejs-softformat' title="Decode json (unit): Object as tuple"><code>++ot:dejs-soft:format</code></a>
92+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#otdejsformat' title="Decode json: Object as tuple"><code>++ot:dejs:format</code></a>
93+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ou-rawdejsformat' title="Decode json: Object of units, raw"><code>++ou-raw:dejs:format</code></a>
94+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#oudejsformat' title="Decode json: Object of units"><code>++ou:dejs:format</code></a>
95+
96+### p
97+
98+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#padejsformat' title="Decode json: String as path"><code>++pa:dejs:format</code></a>
99+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#pairsenjsformat' title="Encode json: Object from key-value pair list"><code>++pairs:enjs:format</code></a>
100+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#pathenjsformat' title="Encode json: String from path"><code>++path:enjs:format</code></a>
101+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#pedejs-softformat' title="Decode json (unit): Prefix"><code>++pe:dejs-soft:format</code></a>
102+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#pedejsformat' title="Decode json: Prefix"><code>++pe:dejs:format</code></a>
103+
104+### r
105+
106+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#redejs-softformat' title="Decode json (unit): Recursive reparser"><code>++re:dejs-soft:format</code></a>
107+
108+### s
109+
110+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#sadejs-softformat' title="Decode json (unit): String as tape"><code>++sa:dejs-soft:format</code></a>
111+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#sedejsformat' title="Decode json: String as tape"><code>++sa:dejs:format</code></a>
112+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#sddejsformat' title="Decode json: String @ud as date"><code>++sd:dejs:format</code></a>
113+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#sedejsformat' title="Decode json: String as aura"><code>++se:dejs:format</code></a>
114+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#sectenjsformat' title="Encode json: Seconds timestamp"><code>++sect:enjs:format</code></a>
115+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#shipenjsformat' title="Encode json: String from ship"><code>++ship:enjs:format</code></a>
116+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#sodejs-softformat' title="Decode json (unit): String as cord"><code>++so:dejs-soft:format</code></a>
117+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#sodejsformat' title="Decode json: String as cord"><code>++so:dejs:format</code></a>
118+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#sudejs-softformat' title="Decode json (unit): Parse string"><code>++su:dejs-soft:format</code></a>
119+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#sudejsformat' title="Decode json: Parse string"><code>++su:dejs:format</code></a>
120+
121+### t
122+
123+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#tankenjsformat' title="Encode json: Tank as string array"><code>++tank:enjs:format</code></a>
124+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#tapeenjsformat' title="Encode json: String from tape"><code>++tape:enjs:format</code></a>
125+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#timeenjsformat' title="Encode json: Millisecond timestamp"><code>++time:enjs:format</code></a>
126+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#to-wainformat' title="Cord to line list"><code>++to-wain:format</code></a>
127+
128+### u
129+
130+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ufdejsformat' title="Decode json: Unit fall"><code>++uf:dejs:format</code></a>
131+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#uldejs-softformat' title="Decode json (unit): Null"><code>++ul:dejs-soft:format</code></a>
132+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#uldejsformat' title="Decode json: Null"><code>++ul:dejs:format</code></a>
133+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#undejsformat' title="Decode json: Unit need"><code>++un:dejs:format</code></a>
134+
135+### w
136+
137+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#wallenjsformat' title="Encode json: String from wall"><code>++wall:enjs:format</code></a>
138+
139+### z
140+
141+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#zadejs-softformat' title="Decode json (unit): Full unit pole"><code>++za:dejs-soft:format</code></a>
142+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#zadejsformat' title="Decode json: Full unit pole"><code>++za:dejs:format</code></a>
143+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#zldejs-softformat' title="Decode json (unit): Collapse unit list"><code>++zl:dejs-soft:format</code></a>
144+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#zldejsformat' title="Decode json: Collapse unit list"><code>++zl:dejs:format</code></a>
145+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#zmdejs-softformat' title="Decode json (unit): Collapse unit map"><code>++zm:dejs-soft:format</code></a>
146+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#zmdejsformat' title="Decode json: Collapse unit map"><code>++zm:dejs:format</code></a>
147+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#zpdejs-softformat' title="Decode json (unit): Unit tuple"><code>++zp:dejs-soft:format</code></a>
148+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#zpdejsformat' title="Decode json: Unit tuple"><code>++zp:dejs:format</code></a>
149+
150+## By Section
151+
152+### 2d (1-5): Formatting functions: Line lists and JSON encoding
153+
154+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#to-wainformat' title="Cord to line list"><code>++to-wain:format</code></a>
155+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#of-wainformat' title="Line list to cord"><code>++of-wain:format</code></a>
156+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#of-wallformat' title="Line list to tape"><code>++of-wall:format</code></a>
157+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#json-rnformat' title="Json to rn parser"><code>++json-rn:format</code></a>
158+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#enjsformat' title="Container arm for JSON encoders"><code>++enjs:format</code></a>
159+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#frondenjsformat' title="Encode json: Object from key-value pair"><code>++frond:enjs:format</code></a>
160+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#pairsenjsformat' title="Encode json: Object from key-value pair list"><code>++pairs:enjs:format</code></a>
161+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#tapeenjsformat' title="Encode json: String from tape"><code>++tape:enjs:format</code></a>
162+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#wallenjsformat' title="Encode json: String from wall"><code>++wall:enjs:format</code></a>
163+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#shipenjsformat' title="Encode json: String from ship"><code>++ship:enjs:format</code></a>
164+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#numbenjsformat' title="Encode json: Number from unsigned"><code>++numb:enjs:format</code></a>
165+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#sectenjsformat' title="Encode json: Seconds timestamp"><code>++sect:enjs:format</code></a>
166+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#timeenjsformat' title="Encode json: Millisecond timestamp"><code>++time:enjs:format</code></a>
167+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#pathenjsformat' title="Encode json: String from path"><code>++path:enjs:format</code></a>
168+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_1-5/#tankenjsformat' title="Encode json: Tank as string array"><code>++tank:enjs:format</code></a>
169+
170+### 2d (6): Formatting functions: JSON decoding
171+
172+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#dejsformat' title="Container arm for JSON decoding reparsers"><code>++dejs:format</code></a>
173+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ardejsformat' title="Decode json: Array as list"><code>++ar:dejs:format</code></a>
174+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#asdejsformat' title="Decode json: Array as set"><code>++as:dejs:format</code></a>
175+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#atdejsformat' title="Decode json: Array as tuple"><code>++at:dejs:format</code></a>
176+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#at-rawdejsformat' title="Decode json: Array as tuple, raw"><code>++at-raw:dejs:format</code></a>
177+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#bodejsformat' title="Decode json: Boolean"><code>++bo:dejs:format</code></a>
178+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#budejsformat' title="Decode json: Boolean NOT"><code>++bu:dejs:format</code></a>
179+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#cidejsformat' title="Decode json: Maybe transform"><code>++ci:dejs:format</code></a>
180+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#cudejsformat' title="Decode json: Transform"><code>++cu:dejs:format</code></a>
181+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#didejsformat' title="Decode json: Millisecond date"><code>++di:dejs:format</code></a>
182+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#dudejsformat' title="Decode json: Second date"><code>++du:dejs:format</code></a>
183+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#mudejsformat' title="Decode json: True unit"><code>++mu:dejs:format</code></a>
184+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#nedejsformat' title="Decode json: Number as real"><code>++ne:dejs:format</code></a>
185+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#nidejsformat' title="Decode json: Number as integer"><code>++ni:dejs:format</code></a>
186+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#nodejsformat' title="Decode json: Number as knot"><code>++no:dejs:format</code></a>
187+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#nudejsformat' title="Decode json: Parse string as hex"><code>++nu:dejs:format</code></a>
188+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ofdejsformat' title="Decode json: Object as frond"><code>++of:dejs:format</code></a>
189+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#otdejsformat' title="Decode json: Object as tuple"><code>++ot:dejs:format</code></a>
190+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ot-rawdejsformat' title="Decode json: Object as tuple, raw"><code>++ot-raw:dejs:format</code></a>
191+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#oudejsformat' title="Decode json: Object of units"><code>++ou:dejs:format</code></a>
192+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ou-rawdejsformat' title="Decode json: Object of units, raw"><code>++ou-raw:dejs:format</code></a>
193+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ojdejsformat' title="Decode json: Object as jug"><code>++oj:dejs:format</code></a>
194+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#omdejsformat' title="Decode json: Object as map"><code>++om:dejs:format</code></a>
195+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#opdejsformat' title="Decode json: Parse keys of map"><code>++op:dejs:format</code></a>
196+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#padejsformat' title="Decode json: String as path"><code>++pa:dejs:format</code></a>
197+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#pedejsformat' title="Decode json: Prefix"><code>++pe:dejs:format</code></a>
198+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#sedejsformat' title="Decode json: String as tape"><code>++sa:dejs:format</code></a>
199+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#sddejsformat' title="Decode json: String @ud as date"><code>++sd:dejs:format</code></a>
200+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#sedejsformat' title="Decode json: String as aura"><code>++se:dejs:format</code></a>
201+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#sodejsformat' title="Decode json: String as cord"><code>++so:dejs:format</code></a>
202+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#sudejsformat' title="Decode json: Parse string"><code>++su:dejs:format</code></a>
203+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#ufdejsformat' title="Decode json: Unit fall"><code>++uf:dejs:format</code></a>
204+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#undejsformat' title="Decode json: Unit need"><code>++un:dejs:format</code></a>
205+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#uldejsformat' title="Decode json: Null"><code>++ul:dejs:format</code></a>
206+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#zadejsformat' title="Decode json: Full unit pole"><code>++za:dejs:format</code></a>
207+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#zldejsformat' title="Decode json: Collapse unit list"><code>++zl:dejs:format</code></a>
208+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#zpdejsformat' title="Decode json: Unit tuple"><code>++zp:dejs:format</code></a>
209+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_6/#zmdejsformat' title="Decode json: Collapse unit map"><code>++zm:dejs:format</code></a>
210+
211+### 2d (7): Formatting functions: JSON decoding (unit)
212+
213+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#dejs-softformat' title="Container arm for unitized JSON decoding reparsers"><code>++dejs-soft:format</code></a>
214+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#ardejs-softformat' title="Decode json (unit): Array as list"><code>++ar:dejs-soft:format</code></a>
215+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#atdejs-softformat' title="Decode json (unit): Array as tuple"><code>++at:dejs-soft:format</code></a>
216+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#at-rawdejs-softformat' title="Decode json (unit): Array as tuple, raw"><code>++at-raw:dejs-soft:format</code></a>
217+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#bodejs-softformat' title="Decode json (unit): Boolean"><code>++bo:dejs-soft:format</code></a>
218+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#budejs-softformat' title="Decode json (unit): Boolean NOT"><code>++bu:dejs-soft:format</code></a>
219+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#cidejs-softformat' title="Decode json (unit): Maybe transform"><code>++ci:dejs-soft:format</code></a>
220+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#cudejs-softformat' title="Decode json (unit): Transform"><code>++cu:dejs-soft:format</code></a>
221+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#dadejs-softformat' title="Decode json (unit): UTC date"><code>++da:dejs-soft:format</code></a>
222+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#dankdejs-softformat' title="Decode json (unit): Tank"><code>++dank:dejs-soft:format</code></a>
223+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#didejs-softformat' title="Decode json (unit): Millisecond date"><code>++di:dejs-soft:format</code></a>
224+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#mudejs-softformat' title="Decode json (unit): True unit"><code>++mu:dejs-soft:format</code></a>
225+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#nedejs-softformat' title="Decode json (unit): Number as real"><code>++ne:dejs-soft:format</code></a>
226+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#nidejs-softformat' title="Decode json (unit): Number as integer"><code>++ni:dejs-soft:format</code></a>
227+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#nodejs-softformat' title="Decode json (unit): Number as knot"><code>++no:dejs-soft:format</code></a>
228+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#ofdejs-softformat' title="Decode json (unit): Object as frond"><code>++of:dejs-soft:format</code></a>
229+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#otdejs-softformat' title="Decode json (unit): Object as tuple"><code>++ot:dejs-soft:format</code></a>
230+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#ot-rawdejs-softformat' title="Decode json (unit): Object as list of units, raw"><code>++ot-raw:dejs-soft:format</code></a>
231+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#omdejs-softformat' title="Decode json (unit): Object as map"><code>++om:dejs-soft:format</code></a>
232+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#opdejs-softformat' title="Decode json (unit): Parse keys of map"><code>++op:dejs-soft:format</code></a>
233+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#pedejs-softformat' title="Decode json (unit): Prefix"><code>++pe:dejs-soft:format</code></a>
234+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#redejs-softformat' title="Decode json (unit): Recursive reparser"><code>++re:dejs-soft:format</code></a>
235+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#sadejs-softformat' title="Decode json (unit): String as tape"><code>++sa:dejs-soft:format</code></a>
236+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#sodejs-softformat' title="Decode json (unit): String as cord"><code>++so:dejs-soft:format</code></a>
237+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#sudejs-softformat' title="Decode json (unit): Parse string"><code>++su:dejs-soft:format</code></a>
238+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#uldejs-softformat' title="Decode json (unit): Null"><code>++ul:dejs-soft:format</code></a>
239+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#zadejs-softformat' title="Decode json (unit): Full unit pole"><code>++za:dejs-soft:format</code></a>
240+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#zldejs-softformat' title="Decode json (unit): Collapse unit list"><code>++zl:dejs-soft:format</code></a>
241+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#zpdejs-softformat' title="Decode json (unit): Unit tuple"><code>++zp:dejs-soft:format</code></a>
242+<a class="tooltip" href='/docs/hoon/reference/zuse/2d_7/#zmdejs-softformat' title="Decode json (unit): Collapse unit map"><code>++zm:dejs-soft:format</code></a>
243+
244+### 2e (2-3): Web text: JSON printing and parsing
245+
246+<a class="tooltip" href='/docs/hoon/reference/zuse/2e_2-3/#en-jsonhtml' title="Parse JSON"><code>++en-json:html</code></a>
247+<a class="tooltip" href='/docs/hoon/reference/zuse/2e_2-3/#de-jsonhtml' title="Parse JSON"><code>++de-json:html</code></a>
content/docs/userspace/_index.md+3
@@ -28,3 +28,6 @@ Resources on threads - monadic functions useful for complex IO.
2828
2929Resources on Graph Store, a non-relational database specialized for social media applications.
3030
31+## [Distribution](/docs/userspace/dist/dist)
32+
33+Resources on distribution and management of desks/apps.
content/docs/userspace/dist/_index.mdnew file+29
@@ -0,0 +1,29 @@
1++++
2+title = "Distribution"
3+weight = 900
4+sort_by = "weight"
5+template = "sections/docs/chapters.html"
6+insert_anchor_links = "right"
7++++
8+
9+Developer documentation for desk/app distribution and management.
10+
11+## [Overview](/docs/userspace/dist/dist)
12+
13+An overview of desk/app distribution and management.
14+
15+## [Docket Files](/docs/userspace/dist/docket)
16+
17+Documentation of `desk.docket` files.
18+
19+## [Glob](/docs/userspace/dist/glob)
20+
21+Documentation of `glob`s (client bundles).
22+
23+## [Guide](/docs/userspace/dist/guide)
24+
25+A walkthrough of creating, installing and publishing a new desk with a tile and front-end.
26+
27+## [Dojo Tools](/docs/userspace/dist/tools)
28+
29+Documentation of useful generators for managing and distributing desks.
content/docs/userspace/dist/dist.mdnew file+105
@@ -0,0 +1,105 @@
1++++
2+title = "Overview"
3+weight = 1
4+template = "doc.html"
5++++
6+
7+Urbit allows peer-to-peer distribution and installation of applications. A user can click on a link to an app hosted by another ship to install that app. The homescreen interface lets users manage their installed apps and launch their interfaces in new tabs.
8+
9+This document describes the architecture of Urbit's app distribution system. For a walk-through of creating and distributing an app, see the [`Guide`](/docs/userspace/dist/guide) document.
10+
11+## Architecture
12+
13+The unit of software distribution is the desk. A desk is a lot like a git branch, but full of typed files, and designed to work with the Arvo kernel. In addition to files full of source code, a desk specifies the Kelvin version of the kernel that it's expecting to interact with, and it includes a manifest file describing which of the Gall agents it defines should be run by default.
14+
15+Every desk is self-contained: the result of validating its files and building its agents is a pure function of its contents and the code in the specified Kelvin version of the kernel. A desk on one ship will build into the same files and programs, noun for noun, as on any other ship.
16+
17+This symmetry is broken during agent installation, which can emit effects that might trigger other actions that cause the Arvo event to fail and be rolled back. An agent can ask the kernel to kill the Arvo event by using the new `%pyre` effect. Best practice, though, is for no desk to have a hard dependency on another desk.
18+
19+If you're publishing an app that expects another app to be installed in order to function, the best practice is to check in `+on-init` for the presence of that other app's desk. If it's not installed, your app should display a message to the user and a link to the app that they should install in order to support your app. App-install links are well-supported in Tlon's Landscape, a suite of user-facing applications developed by Tlon.
20+
21+For the moment, every live desk must have the same Kelvin version as the kernel. Future kernels that know how to maintain backward compatibility with older kernels will also allow older desks, but no commitment has yet been made to maintain backward compatibility across kernel versions, so for the time being, app developers should expect to update their apps accordingly.
22+
23+Each desk defines its own filetypes (called `mark`s), in its `/mar` folder. There are no longer shared system marks that all userspace code knows, nor common libraries in `/lib` or `/sur` — each desk is completely self-contained.
24+
25+It's common for a desk to want to use files that were originally defined in another desk, so that it can interact with agents on that desk. The convention is that if I'm publishing an app that I expect other devs to build client apps for (on other desks), I split out a "dev desk" containing just the external interface to my desk. Typically, both my app desk and clients' app desks will sync from this dev desk.
26+
27+Tlon has done this internally. Most desks will want to sync the `%base-dev` desk so they can easily interact with the kernel and system apps in the `%base` desk. The `%base` desk includes agents such as `%dojo` and `%hood` (with Kiln as an informal sub-agent of `%hood` that manages desk installations).
28+
29+A "landscape app", i.e. a desk that defines a tile that the user can launch from the home screen, should also sync from the `%garden-dev` desk. This desk includes the versioned `%docket-0` mark, which the app needs in order to include a `/desk/docket-0` file.
30+
31+The `%docket` agent reads the `/desk/docket-0` file to display an app tile on the home screen and hook up other front-end functionality, such as downloading the app's client bundle ([glob](/docs/userspace/dist/glob)). Docket is a new agent, in the `%garden` desk, that manages app installations. Docket serves the home screen, downloads client bundles, and communicates with Kiln to configure the apps on your system.
32+
33+For those of you familiar with the old `%glob` and `%file-server` agents, they have now been replaced by Docket.
34+
35+### Anatomy of a Desk
36+
37+Desks still contain helper files in `/lib` and `/sur`, generators in `/gen`, marks in `/mar`, threads in `/ted`, tests in `/tests`, and agents in `/app`. In addition, desks now also contain these files:
38+
39+```
40+/sys/kelvin :: Kernel kelvin, e.g. [%zuse 420]
41+/desk/bill :: (optional, read by Kiln) list of agents to run
42+/desk/docket-0 :: (optional, read by Docket) app metadata
43+/desk/ship :: (optional, read by Docket) ship of original desk publisher, e.g. ~zod
44+```
45+
46+Only the `%base` desk contains a `/sys` directory with the standard library, zuse, Arvo code and vanes. All other desks simply specify the kernel version with which they're compatible in the `/sys/kelvin` file.
47+
48+### Updates
49+
50+The main idea is that an app should only ever be run by a kernel that knows how to run it. For now, since there are not yet kernels that know how to run apps designed for an older kernel, this constraint boils down to ensuring that all live desks have the same kernel Kelvin version as the running kernel itself.
51+
52+To upgrade your kernel to a new version, you need to make a commit to the `%base` desk. Clay will then check if any files in `/sys` changed in this commit. If so, Clay sends the new commit to Arvo, which decides if it needs to upgrade (or upgrade parts of itself, such as a vane). After Arvo upgrades (or decides not to), it wakes up Clay, which finalizes the commit to the `%base` desk and notify the rest of the system.
53+
54+That's the basic flow for upgrading the kernel. However, some kernel updates also change the Kelvin version. If the user has also installed apps, those apps are designed to work with the old Kelvin, so they won't work with the new Kelvin — at least, not at the commit that's currently running.
55+
56+Kiln, part of the system app `%hood` in the `%base` desk, manages desk installations, including the `%base` desk. It can install an app in two ways: a local install, sourced from a desk on the user's machine, or a remote install, which downloads a desk from another ship. Both are performed using the same generator, `|install`.
57+
58+A remote install syncs an upstream desk into a local desk by performing a merge into the local desk whenever the upstream desk changes.
59+
60+The Kelvin update problem is especially thorny for remote installs, which are the most common. By default, a planet has its `%base` desk synced from its sponsor's `%kids` desk, and it will typically have app desks synced from their publishers' ships.
61+
62+Kiln listens (through Clay, which knows how to query remote Clays) for new commits on a remote-installed app's upstream ship and desk. When Clay hears about a new commit, it downloads the files and stores them as a "foreign desk", without validating or building them. It also tells Kiln.
63+
64+When Kiln learns of these new foreign files, it reads the new `/sys/kelvin`. If it's the same as the live kernel's, Kiln asks Clay to merge the new files into the local desk where the app is installed. If the new foreign Kelvin is further ahead (closer to zero) than the kernel's, Kiln does not merge it into the local desk yet. Instead, it enqueues it.
65+
66+Later, when Kiln hears of a new kernel Kelvin version on the upstream `%base` desk, it checks whether all the other live desks have a commit enqueued at that Kelvin. If so, it updates `%base` and then all the other desks, in one big Arvo event. This brings the system from fully at the old Kelvin, to fully at the new Kelvin, atomically — if any part of that fails, the Arvo event will abort and be rolled back, leaving the system back fully at the old Kelvin.
67+
68+If not all live desks have an enqueued commit at the new kernel Kelvin, then Kiln notifies its clients that a kernel update is blocked on a set of desks. Docket, listening to Kiln, presents the user with a choice: either dismiss the notification and keep the old kernel, or suspend the blocking desks and apply the kernel update.
69+
70+Suspending a desk turns off all its agents, saving their states in Gall. If there are no agents running from a desk, that desk doesn't force the kernel to be at the same Kelvin version. It's just inert data. If a later upstream update allows this desk to be run with a newer kernel, the user can revive the desk, and the system will migrate the old state into the new agent.
71+
72+### Managing Apps and Desks in Kiln
73+
74+Turning agents on and off is managed declaratively, rather than imperatively. Kiln maintains state for each desk about which agents should be forced on and which should be forced off. The set of running agents is now a function of the desk's `/desk/bill` manifest file and that user configuration state in Kiln. This means starting or stopping an agent is idempotent, both in Kiln and Gall.
75+
76+For details of the generators for managing desks and agents in Kiln, see the [`Dojo Tools`](/docs/userspace/dist/tools) document.
77+
78+### Landscape apps
79+
80+It's possible to create and distribute desks without a front-end, but typically you'll want to distribute an app with a user interface. Such an app has two primary components:
81+
82+- Gall agents and associated backend code which reside in the desk.
83+- A client bundle called a [`glob`](/docs/userspace/dist/glob), which contains the front-end files like HTML, CSS, JS, images, and so forth.
84+
85+When a desk is installed, Kiln will start up the Gall agents in the `desk.bill` manifest, and the `%docket` agent will read the `desk.docket-0` file. This file will specify the name of the app, various metadata, the appearance of the app's tile in the homescreen, and the source of the `glob` so it can serve the interface. For more details of the docket file, see the [Docket File](/docs/userspace/dist/docket) document.
86+
87+### Globs
88+
89+The reason to separate a glob from Clay is that Clay is a revision-controlled system. Like in most revision control systems, deleting data from it is nontrivial due to newer commits referencing old commits. If Clay grows the ability to delete data, perhaps glob data could be moved into it. Until then, since client bundles tend to be updated frequently, it's best practice not to put your glob in your app host ship's Clay at all to make sure it doesn't fill up your ship's "loom" memory arena.
90+
91+If the glob is to be served over Ames, there is an HTTP-based glob uploader that allows you to use a web form to upload a folder into your ship, which will convert the folder to a glob and link to it in your app desk's docket manifest file.
92+
93+Note that serving a glob over Ames might increase the install time for your app, since Ames is currently pretty slow compared to HTTP — but being able to serve a glob from your ship allows you to serve your whole app, both server-side and client-side, without setting up a CDN or any other external web tooling. Your ship can do it all on its own.
94+
95+For further details of globs, see the [Glob](/docs/userspace/dist/glob) document.
96+
97+## Sections
98+
99+- [Glob](/docs/userspace/dist/glob) - Documentation of `glob`s (client bundles).
100+
101+- [Docket Files](/docs/userspace/dist/docket) - Documentation of docket files.
102+
103+- [Guide](/docs/userspace/dist/guide) - A walkthrough of creating, installing and publishing a new desk with a tile and front-end.
104+
105+- [Dojo Tools](/docs/userspace/dist/tools) - Documentation of useful generators for managing and distributing desks.
content/docs/userspace/dist/docket.mdnew file+296
@@ -0,0 +1,296 @@
1++++
2+title = "Docket File"
3+weight = 2
4+template = "doc.html"
5++++
6+
7+The docket file sets various options for desks with a tile and (usually) a browser-based front-end of some kind. Mainly it configures the appearance of an app's tile, the source of its [glob](/docs/userspace/dist/glob), and some additional metadata.
8+
9+The docket file is read by the `%docket` agent when a desk is `|install`ed. The `%docket` agent will fetch the glob if applicable and create the tile as specified on the homescreen. If the desk is published with `:treaty|publish`, the information specified in the docket file will also be displayed for others who are browsing apps to install on your ship.
10+
11+The docket file is _optional_ in the general case. If it is omitted, however, the app cannot have a tile in the homescreen, nor can it be published with the `%treaty` agent, so others will not be able to browse for it from their homescreens.
12+
13+The docket file must be named `desk.docket-0`. The `%docket` `mark` is versioned to facilitate changes down the line, so the `-0` suffix may be incremented in the future.
14+
15+The file must contain a `hoon` list with a series of clauses. The clauses are defined in `/sur/docket.hoon` as:
16+
17+```hoon
18++$ clause
19+ $% [%title title=@t]
20+ [%info info=@t]
21+ [%color color=@ux]
22+ [%glob-http url=cord hash=@uvH]
23+ [%glob-ames =ship hash=@uvH]
24+ [%image =url]
25+ [%site =path]
26+ [%base base=term]
27+ [%version =version]
28+ [%website website=url]
29+ [%license license=cord]
30+ ==
31+```
32+
33+The `%image` clause is optional. It is mandatory to have exactly one of either `%site`, `%glob-http` or `%glob-ames`. All other clauses are mandatory.
34+
35+Here's what a typical docket file might look like:
36+
37+```hoon
38+:~
39+ title+'Foo'
40+ info+'An app that does a thing.'
41+ color+0xf9.8e40
42+ glob-ames+[~zod 0v0]
43+ image+'https://example.com/tile.svg'
44+ base+'foo'
45+ version+[0 0 1]
46+ license+'MIT'
47+ website+'https://example.com'
48+==
49+```
50+
51+Details of each clause and their purpose are described below.
52+
53+---
54+
55+## `%title`
56+
57+_required_
58+
59+The `%title` field specifies the name of the app. The title will be the name shown on the app's tile, as well as the name of the app when others search for it.
60+
61+#### Type
62+
63+```hoon
64+[%title title=@t]
65+```
66+
67+#### Example
68+
69+```hoon
70+title+'Bitcoin'
71+```
72+
73+---
74+
75+## `%info`
76+
77+_required_
78+
79+The `%info` field is a brief summary of what the app does. It will be shown as the subtitle in _App Info_.
80+
81+#### Type
82+
83+```hoon
84+[%info info=@t]
85+```
86+
87+#### Example
88+
89+```hoon
90+info+'A Bitcoin Wallet that lets you send and receive Bitcoin directly to and from other Urbit users'
91+```
92+
93+---
94+
95+## `%color`
96+
97+_required_
98+
99+The `%color` field specifies the color of the app tile as an `@ux`-formatted hex value.
100+
101+#### Type
102+
103+```hoon
104+[%color color=@ux]
105+```
106+
107+#### Example
108+
109+```hoon
110+color+0xf9.8e40
111+```
112+
113+---
114+
115+## `%glob-http`
116+
117+_exactly one of either this, [glob-ames](#glob-ames) or [site](#site) is required_
118+
119+The `%glob-http` field specifies the URL and hash of the app's [glob](/docs/userspace/distribution/glob) if it is distributed via HTTP.
120+
121+#### Type
122+
123+```hoon
124+[%glob-http url=cord hash=@uvH]
125+```
126+
127+#### Example
128+
129+```hoon
130+glob-http+['https://example.com/glob-0v1.s0me.h4sh.glob' 0v1.s0me.h4sh]
131+```
132+
133+---
134+
135+## `%glob-ames`
136+
137+_exactly one of either this, [glob-http](#glob-http) or [site](#site) is required_
138+
139+The `%glob-ames` field specifies the ship and hash of the app's [glob](/docs/userspace/distribution/glob) if it is distributed from a ship over Ames. If the glob will be distributed from our ship, the hash can initially be `0v0` as it will be overwritten with the hash produced by the [Globulator](/docs/userspace/distribution/glob#globulator).
140+
141+#### Type
142+
143+```hoon
144+[%glob-ames =ship hash=@uvH]
145+```
146+
147+#### Example
148+
149+```hoon
150+glob-ames+[~zod 0v0]
151+```
152+
153+---
154+
155+## `%site`
156+
157+_exactly one of either this, [glob-ames](#glob-ames) or [glob-http](#glob-http) is required_
158+
159+It's possible for an app to handle HTTP requests from the client directly rather than with a separate [glob](/docs/userspace/distribution/glob). In that case, the `%site` field specifies the `path` of the Eyre endpoint the app will bind. If `%site` is used, clicking the app's tile will simply open a new tab with a GET request to the specified Eyre endpoint.
160+
161+For more information on direct HTTP handling with a Gall agent or generator, see the [Eyre Internal API Reference](/docs/arvo/eyre/tasks) documentation.
162+
163+#### Type
164+
165+```hoon
166+[%site =path]
167+```
168+
169+#### Example
170+
171+```hoon
172+site+/foo/bar
173+```
174+
175+---
176+
177+## `%image`
178+
179+_optional_
180+
181+The `%image` field specifies the URL of an image to be displayed on the app's tile. This field is optional and may be omitted entirely.
182+
183+The given image will be displayed on top of the [color](#color)ed tile. The app [title](#title) (and hamburger menu upon hover) will be displayed on top of the given image, in small rounded boxes with the same background color as the main tile. The given image will be displayed at 100% of the width of the tile. The image's corners will be hidden by the rounded corners of the tile, so the image itself needn't have rounded corners. The tile is a perfect square, so if the image should occupy the whole tile, it should also be a perfect square. If the image should be a smaller icon in the center of the tile (like the bitcoin tile), it should just have a square of transparent negative space around it.
184+
185+It may be tempting to set the image URL as a root-relative path like `/apps/myapp/img/tile.svg` and bundle it in the glob. While this would work locally, it means the image would fail to load for those browsing apps to install. Therefore, the image should be hosted somewhere globally available.
186+
187+#### Type
188+
189+```hoon
190+[%image =url]
191+```
192+
193+The `url` type is a simple `cord`:
194+
195+```hoon
196++$ url cord
197+```
198+
199+#### Example
200+
201+```hoon
202+image+'http://example.com/icon.svg'
203+```
204+
205+---
206+
207+## `%base`
208+
209+_required_
210+
211+The `%base` field specifies the base of the URL path of the glob resources. In the browser, the path will begin with `/apps`, then the specified base, then the rest of the path to the particular glob resource like `http://localhost:8080/apps/my-base/index.html`. Note the `path`s of the glob contents themselves should not include this base element.
212+
213+#### Type
214+
215+```hoon
216+[%base base=term]
217+```
218+
219+#### Example
220+
221+```hoon
222+base+'bitcoin'
223+```
224+
225+---
226+
227+## `%version`
228+
229+_required_
230+
231+The `%version` field specifies the current version of the app. It's a triple of three `@ud` numbers representing the major version, minor version and patch version. In the client, `[1 2 3]` will be rendered as `1.2.3`. You would typically increase the appropriate number each time you published a change to the app.
232+
233+#### Type
234+
235+```hoon
236+[%version =version]
237+```
238+
239+The `version` type is just a triple of three numbers:
240+
241+```hoon
242++$ version
243+ [major=@ud minor=@ud patch=@ud]
244+```
245+
246+#### Example
247+
248+```hoon
249+version+[0 0 1]
250+```
251+
252+---
253+
254+## `%website`
255+
256+_required_
257+
258+The `%website` field is for a link to a relevant website. This might be a link to the app's github repo, company website, or whatever is appropriate. This field will be displayed when people are browsing apps to install.
259+
260+#### Type
261+
262+```hoon
263+[%website website=url]
264+```
265+
266+The `url` type is a simple `cord`:
267+
268+```hoon
269++$ url cord
270+```
271+
272+#### Example
273+
274+```hoon
275+website+'https://example.com'
276+```
277+
278+---
279+
280+## `%license`
281+
282+_required_
283+
284+The `%license` field specifies the license for the app in question. It would typically be a short name like `MIT`, `GPLv2`, or what have you. The field just takes a `cord` so any license can be specified.
285+
286+#### Type
287+
288+```hoon
289+[%license license=cord]
290+```
291+
292+#### Example
293+
294+```hoon
295+license+'MIT'
296+```
content/docs/userspace/dist/glob.mdnew file+102
@@ -0,0 +1,102 @@
1++++
2+title = "Glob"
3+weight = 3
4+template = "doc.html"
5++++
6+
7+A `glob` contains the client bundle—client-side resources like HTML, JS, and CSS files—for a landscape app distributed in a desk. Globs are managed separately from other files in desks because they often contain large files that frequently change, and would therefore bloat a ship's state if they were subject to Clay's revision control mechanisms.
8+
9+The hash and source of an app's glob is defined in a desk's [docket file](/docs/userspace/dist/docket). The `%docket` agent reads the docket file, obtains the glob from the specified source, and makes its contents available to the browser client. On a desk publisher's ship, if the glob is to be distributed over Ames, the glob is also made available to desk subscribers.
10+
11+## The `glob` type
12+
13+The `%docket`agent defines the type of a `glob` as:
14+
15+```hoon
16++$ glob (map path mime)
17+```
18+
19+Given the following file heirarchy:
20+
21+```
22+foo
23+├── css
24+│ └── style.css
25+├── img
26+│ ├── favicon.png
27+│ ├── foo.svg
28+│ └── bar.svg
29+├── index.html
30+└── js
31+ └── baz.js
32+```
33+
34+...its `$glob` form would look like:
35+
36+```hoon
37+{ [p=/img/foo/svg q=[p=/image/svg+xml q=[p=0 q=0]]]
38+ [p=/css/style/css q=[p=/text/css q=[p=0 q=0]]]
39+ [p=/img/favicon/png q=[p=/image/png q=[p=0 q=0]]]
40+ [p=/js/baz/js q=[p=/application/javascript q=[p=0 q=0]]]
41+ [p=/img/bar/svg q=[p=/image/svg+xml q=[p=0 q=0]]]
42+ [p=/index/html q=[p=/text/html q=[p=0 q=0]]]
43+}
44+```
45+
46+<sup>Note: The mime byte-length and data are 0 in this example because it was made with empty dummy files.</sup>
47+
48+A glob may contain any number of files and folders in any kind of heirarchy. The one important thing is that an `index.html` file is present in its root. The `index.html` file is automatically served when the app is opened in the browser and will fail if it is missing.
49+
50+In addition to the `$glob` type, a glob can also be output to Unix with a `.glob` file extension for distribution over HTTP. This file simply contains a [`jam`](/docs/hoon/reference/stdlib/2p#jam)med `$glob` structure.
51+
52+## Docket file clause
53+
54+The `desk.docket-0` file must include exactly one of the following clauses:
55+
56+#### `site+/some/path`
57+
58+If an app binds an Eyre endpoint and handles HTTP directly, for example with a [`%connect` task:eyre](/docs/arvo/eyre/tasks#connect), the `%site` clause is used, specifying the Eyre binding. In this case a glob is omitted entirely.
59+
60+#### `glob-ames+[~zod 0vs0me.h4sh]`
61+
62+If the glob is to be distributed over Ames, the `%glob-ames` clause is used, with a cell of the `ship` which has the glob and the `@uv` hash of the glob. If it's our ship, the hash can just be `0v0` and the glob can instead be created with the [Globulator](#globulator).
63+
64+#### `glob-http+['https://example.com/some.glob' 0vs0me.h4sh]`
65+
66+If the glob is to be distributed over HTTP, for example from an s3 instance, the `%glob-http` clause is used. It takes a cell of a `cord` with the URL serving the glob and the `@uv` hash of the glob.
67+
68+## Making a glob
69+
70+There are a couple of different methods depending on whether the glob will be distributed over HTTP or Ames.
71+
72+### Globulator
73+
74+For globs distributed over Ames from our ship, the client bundle can be uploaded directly with `%docket`'s Globulator tool, which is available in the browser at `http[s]://[host]/docket/upload`. It looks like this:
75+
76+![Globulator](https://media.urbit.org/docs/userspace/dist/globulator.png)
77+
78+Simply select the target desk, select the folder to be globulated, and hit `glob!`.
79+
80+Note the target desk must have been `|install`ed before uploading its glob. When installed, `%docket` will print `docket: awaiting manual glob for %desk-name desk` in the terminal and wait for the upload. The hash in the `%ames-glob` clause of the docket file will be overwritten by the hash of the new glob. As a result, there's no need to specify the actual glob hash in `desk.docket` - you can just use any `@uv` like `0v0`. Once uploaded, the desk can then be published with `:treaty|publish %desk-name` and the glob will become available for download by subscribers.
81+
82+### `-make-glob`
83+
84+There's a different process for globs to be distributed over HTTP from a webserver rather than over Ames from a ship. For this purpose, the `%garden` desk includes a `%make-glob` thread. The thread takes a folder in a desk and produces a glob of the files it contains, which it then saves to Unix in a [`jam`](/docs/hoon/reference/stdlib/2p#jam)file with a `.glob` extension.
85+
86+To begin, you'll need to spin up a ship (typically a fake ship) and `|mount` a desk for which to add the files. In order for Clay to add the files, the desk must contain `mark` files in its `/mar` directory for all file extensions your folder contains. The `%garden` desk is a good bet because it includes `mark` files for `.js`, `.html`, `.png`, `.svg`, `.woff2` and a couple of others. If there's no desk with a mark for a particular file type you want included in your glob, you may need to add a new mark file. A very rudimentary mark file like the `png.hoon` mark will suffice.
87+
88+With the desk mounted, add the folder to be globbed to the root of the desk in Unix. It's imporant it's in the root because the `%make-glob` thread will only strip the first level of the folder heirarchy.
89+
90+Next, `|commit` the files to the desk and change directory in the dojo to the `%garden` desk with `=dir /=garden=`. Then, run `-make-glob %the-desk /folder-name`, where `%the-desk` is the desk containing the folder to be globbed and `/folder-name` is its name.
91+
92+On Unix, if you look in `/path/to/pier/.urb/put`, you'll now see a file which looks like:
93+
94+```
95+glob-0v1.7vpqa.r8pn5.6t0s1.rhc7r.5e9vo.glob
96+```
97+
98+This file can be uploaded to your webserver and the `desk.docket-0` file of the desk you're publishing can be updated with:
99+
100+```hoon
101+glob-http+['https://s3.example.com/glob-0v1.7vpqa.r8pn5.6t0s1.rhc7r.5e9vo.glob' 0v1.7vpqa.r8pn5.6t0s1.rhc7r.5e9vo]
102+```
content/docs/userspace/dist/guide.mdnew file+286
@@ -0,0 +1,286 @@
1++++
2+title = "Guide"
3+weight = 4
4+template = "doc.html"
5++++
6+
7+In this document we'll walk through an example of creating and publishing a desk that others can install. We'll create a simple "Hello World!" front-end with a "Hello" tile to launch it. For simplicity, the desk won't include an actual Gall agent, but we'll note everything necessary if there were one.
8+
9+## Create desk
10+
11+To begin, we'll need to clone the [urbit git repo](https://github.com/urbit/urbit) from the Unix terminal:
12+
13+```
14+[user@host ~]$ git clone https://github.com/urbit/urbit urbit-git
15+```
16+
17+Once that's done, we can navigate to the `pkg` directory in our cloned repo:
18+
19+```
20+[user@host ~]$ cd urbit-git/pkg
21+[user@host pkg]$ ls .
22+arvo btc-wallet garden grid interface npm webterm
23+base-dev docker-image garden-dev herb landscape symbolic-merge.sh
24+bitcoin ent ge-additions hs libaes_siv urbit
25+```
26+
27+Each desk defines its own `mark`s, in its `/mar` folder. There are no longer shared system marks that all userspace code knows, nor common libraries in `/lib` or `/sur`. Each desk is completely self-contained. This means any new desk will need a number of base files.
28+
29+To make the creation of a new desk easier, `base-dev` and `garden-dev` contain symlinks to all `/sur`, `/lib` and `/mar` files necessary for interacting with the `%base` and `%garden` desks respectively. These dev desks can be copied and merged with the `symbolic-merge.sh` included.
30+
31+Let's create a new `hello` desk:
32+
33+```
34+[user@host pkg]$ mkdir hello
35+[user@host pkg]$ ./symbolic-merge.sh base-dev hello
36+[user@host pkg]$ ./symbolic-merge.sh garden-dev hello
37+[user@host pkg]$ cd hello
38+[user@host hello]$ ls
39+lib mar sur
40+```
41+
42+### `sys.kelvin`
43+
44+Our desk must include a `sys.kelvin` file which specifies the kernel version it's compatible with. Let's create that:
45+
46+```
47+[user@host hello]$ echo "[%zuse 420]" > sys.kelvin
48+[user@host hello]$ cat sys.kelvin
49+[%zuse 420]
50+```
51+
52+### `desk.ship`
53+
54+We can also add a `desk.ship` file to specify the original publisher of this desk. We'll try this on a fakezod so let's just add `~zod` as the publisher:
55+
56+```
57+[user@host hello]$ echo "~zod" > desk.ship
58+[user@host hello]$ cat desk.ship
59+~zod
60+```
61+
62+### `desk.bill`
63+
64+If we had Gall agents in this desk which should be automatically started when the desk is installed, we'd add them to a `hoon` list in the `desk.bill` file. It would look something like this:
65+
66+```hoon
67+:~ %some-app
68+ %another
69+==
70+```
71+
72+In this example we're not adding any agents, so we'll simply omit the `desk.bill` file.
73+
74+### `desk.docket-0`
75+
76+The final file we need is `desk.docket-0`. This one's more complicated, so we'll open it in our preferred text editor:
77+
78+```
79+[user@host hello]$ nano desk.docket-0
80+```
81+
82+In the text editor, we'll add the following:
83+
84+```hoon
85+:~ title+'Hello'
86+ info+'A simple hello world app.'
87+ color+0x81.88c9
88+ image+'https://media.urbit.org/docs/userspace/dist/wut.svg'
89+ base+'hello'
90+ glob-ames+[~zod 0v0]
91+ version+[0 0 1]
92+ website+'https://urbit.org/docs/userspace/dist/guide'
93+ license+'MIT'
94+==
95+```
96+
97+You can refer to the [Docket File](/docs/userspace/dist/docket) documentation for more details of what is required. In brief, the `desk.docket-0` file contains a `hoon` list of [clauses](/docs/userspace/dist/docket) which configure the appearance of the app tile, the source of the [glob](/docs/userspace/dist/glob), and some other metadata.
98+
99+We've given the app a [`%title`](/docs/userspace/dist/docket#title) of "Hello", which will be displayed on the app tile and will be the name of the app when others browse to install it. We've given the app tile a [`%color`](/docs/userspace/dist/docket#color) of `#8188C9`, and also specified the URL of an [`%image`](/docs/userspace/dist/docket#image) to display on the tile.
100+
101+The [`%base`](/docs/userspace/dist/docket#base) clause specifies the base URL path for the app. We've specified "hello" so it'll be `http://localhost:8080/apps/hello/...` in the browser. For the [glob](/docs/userspace/dist/glob), we've used a clause of [`%glob-ames`](/docs/userspace/dist/docket#glob-ames), which means the glob will be served from a ship over Ames, as opposed to being served over HTTP with a [`%glob-http`](/docs/userspace/dist/docket#glob-http) clause or having an Eyre binding with a [`%site`](/docs/userspace/dist/docket#site) clause. You can refer to the [glob](/docs/userspace/dist/glob) documentation for more details of the glob options. In our case we've specified `[~zod 0v0]`. Since `~zod` is the fakeship we'll install it on, the `%docket` agent will await a separate upload of the `glob`, so we can just specify `0v0` here as it'll get overwritten later.
102+
103+The [`%version`](/docs/userspace/dist/docket#version) clause specifies the version as a triple of major version, minor version and patch version. The rest is just some additional informative metadata which will be displayed in _App Info_.
104+
105+So let's save that to the `desk.docket-0` file and have a look at our desk:
106+
107+```
108+[user@host hello]$ ls
109+desk.docket-0 desk.ship lib mar sur sys.kelvin
110+```
111+
112+That's everything we need for now.
113+
114+## Install
115+
116+Let's spin up a fakezod in which we can install our desk:
117+
118+```
119+[user@host hello]$ cd ~/piers/fake
120+[user@host fake]$ urbit -F zod
121+```
122+
123+Once our fakezod is booted, we'll need to create a new `%hello` desk for our app and mount it. We can do this in the dojo like so:
124+
125+```
126+> |merge %hello our %base
127+>=
128+> |mount %hello
129+>=
130+```
131+
132+Now, back in the Unix terminal, we should see the new desk mounted:
133+
134+```
135+[user@host fake]$ cd zod
136+[user@host zod]$ ls
137+hello
138+```
139+
140+Currently it's just a clone of the `%base` desk, so let's delete its contents:
141+
142+```
143+[user@host zod]$ rm -r hello/*
144+```
145+
146+Next, we'll copy in the contents of the `hello` desk we created earlier. We must use `cp -LR` to resolve all the symlinks:
147+
148+```
149+[user@host zod]$ cp -LR ~/urbit-git/pkg/hello/* hello/
150+```
151+
152+Back in the dojo we can commit the changes and install the desk:
153+
154+```
155+> |commit %hello
156+> |install our %hello
157+kiln: installing %hello locally
158+docket: awaiting manual glob for %hello desk
159+```
160+
161+The `docket: awaiting manual glob for %hello desk` message is because our `desk.docket-0` file includes a [`%glob-ames`](/docs/userspace/dist/docket#glob-ames) clause which specifies our ship as the source, so it's waiting for us to upload the glob.
162+
163+If we open a browser now, navigate to `http://localhost:8080` and login with the default fakezod code `lidlut-tabwed-pillex-ridrup`, we'll see our tile's appeared but it says "installing" with a spinner due to the missing glob:
164+
165+![Installing Tile](https://media.urbit.org/docs/userspace/dist/local-install-1.png)
166+
167+## Create files for glob
168+
169+We'll now create the files for the glob. We'll use a very simple static HTML page that just displayes "Hello World!" and an image. Typically we'd have a more complex JS web app that talked to apps on our ship through Eyre's channel system, but for the sake of simplicity we'll forgo that. Let's hop back in the Unix terminal:
170+
171+```
172+[user@host zod]$ cd ~
173+[user@host ~]$ mkdir hello-glob
174+[user@host ~]$ cd hello-glob
175+[user@host hello-glob]$ mkdir img
176+[user@host hello-glob]$ wget -P img https://media.urbit.org/docs/userspace/dist/pot.svg
177+[user@host hello-glob]$ tree
178+.
179+└── img
180+ └── pot.svg
181+
182+1 directory, 1 file
183+```
184+
185+We've grabbed an image to use in our "Hello world!" page. The next thing we need to add is an `index.html` file in the root of the folder. The `index.html` file is mandatory; it's what will be loaded when the app's tile is clicked. Let's open our preferred editor and create it:
186+
187+```
188+[user@host hello-glob]$ nano index.html
189+```
190+
191+In the editor, paste in the following HTML and save it:
192+
193+```html
194+<!DOCTYPE html>
195+<html>
196+ <head>
197+ <style>
198+ div {
199+ text-align: center;
200+ }
201+ </style>
202+ </head>
203+ <title>Hello World</title>
204+ <body>
205+ <div>
206+ <h1>Hello World!</h1>
207+ <img src="img/pot.svg" alt="pot" width="219" height="196" />
208+ </div>
209+ </body>
210+</html>
211+```
212+
213+Our `hello-glob` folder should now look like this:
214+
215+```
216+[user@host hello-glob]$ tree
217+.
218+├── img
219+│ └── pot.svg
220+└── index.html
221+
222+1 directory, 2 files
223+```
224+
225+## Upload to glob
226+
227+We can now create a glob from the directory. To do so, navigate to `http://localhost:8080/docket/upload` in the browser. This will bring up the `%docket` app's [Globulator](/docs/userspace/dist/glob#globulator) tool:
228+
229+![Globulator](https://media.urbit.org/docs/userspace/dist/globulator.png)
230+
231+Simply select the `hello` desk from the drop-down, click `Choose file` and select the `hello-glob` folder in the the file browser, then hit `glob!`.
232+
233+Now if we return to our ship's homescreen, we should see the tile looks as we specified in the docket file:
234+
235+![Installed Tile](https://media.urbit.org/docs/userspace/dist/local-install-2.png)
236+
237+And if we click on the tile, it'll load the `index.html` in our glob:
238+
239+![Hello World!](https://media.urbit.org/docs/userspace/dist/local-install-3.png)
240+
241+Our app is working!
242+
243+## Publish
244+
245+The final step is publishing our desk with the `%treaty` agent so others can install it. To do this, there's a simple command in the dojo:
246+
247+```
248+> :treaty|publish %hello
249+>=
250+```
251+
252+Note: For desks without a docket file (and therefore without a tile and glob), treaty can't be used. Instead you can make the desk public with `|public %desk-name`.
253+
254+## Remote install
255+
256+Let's spin up another fake ship so we can try install it:
257+
258+```
259+[user@host hello-glob]$ cd ~/piers/fake
260+[user@host fake]$ urbit -F bus
261+```
262+
263+At the time of writing, we must manually request the published apps on a given ship from the dojo. This will likely change in the future but for now we must run the following on `~bus` before we can search for apps on `~zod` from the homescreen:
264+
265+```
266+> :treaty|ally ~zod
267+>=
268+```
269+
270+Note: For desks without a docket files (and therefore without a tile and glob), treaty can't be used. Instead remote users can install it from the dojo with `|install ~our-ship %desk-name`.
271+
272+Now in the browser, navigate to `http://localhost:8081` and login with `~bus`'s code `riddec-bicrym-ridlev-pocsef`. Next, type `~zod/` in the search bar, and it should pop up a list of `~zod`'s published apps, which in this case is our `Hello` app:
273+
274+![Remote install search](https://media.urbit.org/docs/userspace/dist/remote-install-1.png)
275+
276+When we click on the app, it'll show some of the information from the clauses in the docket file:
277+
278+![Remote app info](https://media.urbit.org/docs/userspace/dist/remote-install-2.png)
279+
280+Click `Get App` and it'll ask as if we want to install it:
281+
282+![Remote app install](https://media.urbit.org/docs/userspace/dist/remote-install-3.png)
283+
284+Finally, click `Get "Hello"` and it'll be installed as a tile on `~bus` which can then be opened:
285+
286+![Remote app finished](https://media.urbit.org/docs/userspace/dist/remote-install-4.png)
content/docs/userspace/dist/tools.mdnew file+342
@@ -0,0 +1,342 @@
1++++
2+title = "Dojo Tools"
3+weight = 5
4+template = "doc.html"
5++++
6+
7+A number of generators are included for managing and viewing the status of desks and their agents. Each of these are documented below.
8+
9+Note that some old generators have been replaced:
10+
11+- `|start` - Replaced with [`|rein`](#rein).
12+- `|ota` - Replaced with [`|install`](#install), [`|uninstall`](#uninstall), [`|pause`](#pause) and [`|resume`](#resume).
13+- `|fade` - Replaced with [`|nuke`](#nuke).
14+- `|doze` - Replaced with [`|rein`](#rein) or [`|suspend`](#suspend).
15+- `|wake` - Replaced with [`|rein`](#rein) or [`|revive`](#revive).
16+- `+trouble` - This still exists but is deprecated, and is now an alias for [`+vats`](#vats).
17+
18+---
19+
20+## `+vats`
21+
22+Print out the status of each installed desk.
23+
24+Desks in Clay which aren't installed will be omitted.
25+
26+Fields:
27+
28+- `/sys/kelvin` - The version of `%zuse` the desk is compatible with.
29+- `base hash` - The merge base (common ancestor) between the desk and its upstream source.
30+- `%cz hash` - The hash of the desk.
31+- `app status` - May be `suspended` or `running`.
32+- `force on` - The set of agents on the desk which have been manually started despite not being on the `desk.bill` manifest.
33+- `force off` - The set of agents on the desk which have been manually stopped despite being on the `desk.bill` manifest.
34+- `publishing ship` - The original publisher if the source ship is republishing the desk.
35+- `updates` - May be `local`, `tracking` or `paused`. Local means it will receive updates via commits on the local ship. Tracking means it will receive updates from the `source ship`. Paused means it will not receive updates.
36+- `source desk` - The desk on the `source ship`.
37+- `source aeon` - The revision number of the desk on the `source ship`.
38+- `pending updates` - Updates waiting to be applied due to incompatibility.
39+
40+#### Arguments
41+
42+None.
43+
44+#### Examples
45+
46+```
47+> +vats
48+%base
49+ /sys/kelvin: [%zuse 420]
50+ base hash: ~
51+ %cz hash: 0v6.2nqmu.oqm24.ighl6.n0gp9.s8res.feql1.dl8ap.isli3.jk0hu.acrd2
52+ app status: running
53+ force on: ~
54+ force off: ~
55+ publishing ship: ~
56+ updates: tracking
57+ source ship: ~zod
58+ source desk: %base
59+ source aeon: 3
60+ pending updates: ~
61+::
62+%garden
63+ /sys/kelvin: [%zuse 420]
64+ base hash: ~
65+ %cz hash: 0v1e.2h7hs.elq3g.1sdt7.qfga6.ganga.7p95j.aog44.8p5fe.kpr6v.7ai82
66+ app status: running
67+ force on: ~
68+ force off: ~
69+ publishing ship: ~
70+ updates: tracking
71+ source ship: ~zod
72+ source desk: %garden
73+ source aeon: 3
74+ pending updates: ~
75+```
76+
77+---
78+
79+## `+agents`
80+
81+Print out the status of Gall agents on a desk.
82+
83+Agents may either be `archived` or `running`. Nuked or unstarted agents which are not on the manifest are omitted.
84+
85+#### Arguments
86+
87+```
88+desk
89+```
90+
91+#### Example
92+
93+```
94+> +agents %garden
95+status: running %hark-system-hook
96+status: running %treaty
97+status: running %docket
98+status: running %settings-store
99+status: running %hark-store
100+```
101+
102+---
103+
104+## `|suspend`
105+
106+Shut down all agents on a desk, archiving their states.
107+
108+The tile in the homescreen (if it has one) will turn gray and say "Suspended" in the top-left corner. This generator does the same thing as selecting "Suspend" from an app tile's hamburger menu.
109+
110+#### Arguments
111+
112+```
113+desk
114+```
115+
116+#### Examples
117+
118+```
119+|suspend %bitcoin
120+```
121+
122+---
123+
124+## `|revive`
125+
126+Revive all agents on a desk, migrating archived states.
127+
128+All agents specified in `desk.bill` which are suspended will be restarted. If updates to the agents have occurred since their states were archived, they'll be migrated with the state transition functions in the agent. This generator does the same thing as selecting "Resume App" from the app tile's hamburger menu.
129+
130+#### Arguments
131+
132+```
133+desk
134+```
135+
136+#### Examples
137+
138+```
139+|revive %bitcoin
140+```
141+
142+---
143+
144+## `|install`
145+
146+Install a desk, starting its agents and listening for updates.
147+
148+If it's a remote desk we don't already have, it will be fetched. The agents started will be those specified in the `desk.bill` manifest. If it has a docket file, its tile will be added to the homescreen and its glob fetched. If we already have the desk, the source for updates will be switched to the ship specified.
149+
150+It takes a `ship` and `desk` as its mandatory arguments. The desk may be installed with a different name specified in the optional `local` argument.
151+
152+#### Arguments
153+
154+```
155+ship desk, =local desk
156+```
157+
158+#### Examples
159+
160+```
161+|install ~zod %bitcoin
162+```
163+
164+```
165+|install our %webterm
166+```
167+
168+```
169+|install ~zod %bitcoin, =local %foo
170+```
171+
172+---
173+
174+## `|uninstall`
175+
176+Uninstall a desk, suspending its agents and ignoring updates.
177+
178+The specified desk will be retained in Clay, but its agents will all be stopped and have their states archived like [`|suspend`](#suspend). This is the reverse of [`|install`](#install).
179+
180+Note that this will not remove the tile or glob from the homescreen, so if the desk has a tile it should be uninstalled with the "Remove App" button in the tile's hamburger menu.
181+
182+#### Arguments
183+
184+```
185+desk
186+```
187+
188+#### Examples
189+
190+```
191+|uninstall %bitcoin
192+```
193+
194+---
195+
196+## `|pause`
197+
198+Pause updates on a desk.
199+
200+The specified desk will stop tracking updates from its upstream source.
201+
202+#### Arguments
203+
204+```
205+desk
206+```
207+
208+#### Examples
209+
210+```
211+|pause %bitcoin
212+```
213+
214+---
215+
216+## `|resume`
217+
218+Resume updates on a desk.
219+
220+Start tracking previously [`|pause`](#pause)d updates from a desk's upstream source.
221+
222+#### Arguments
223+
224+```
225+desk
226+```
227+
228+#### Examples
229+
230+```
231+|resume %bitcoin
232+```
233+
234+---
235+
236+## `|nuke`
237+
238+Shut down an agent and permanently delete its state.
239+
240+The default behaviour is to shut down the specified Gall agent and discard its state, similar to the now-deprecated `|fade` generator. **Note this irreversibly wipes the app's state**. Additionally, if the optional `desk` argument is `%.y`, it takes a desk rather than an agent name and nukes every agent on the specified desk.
241+
242+#### Arguments
243+
244+```
245+@tas, =desk ?
246+```
247+
248+#### Examples
249+
250+Nuke a single agent:
251+
252+```
253+|nuke %btc-wallet
254+```
255+
256+Nuke every agent on a desk:
257+
258+```
259+|nuke %bitcoin, =desk &
260+```
261+
262+---
263+
264+## `|bump`
265+
266+Try to apply a kernel update.
267+
268+If `%zuse`'s kelvin version has decreased, try to apply the update. If any desks are incompatible with the new `%zuse` version, the update will fail. The update can be forced with the optional `force` argument, in which case incompatible desks will be `|suspend`ed. The `set` of desks to omit (and therefore suspend) can also be explicitly specified with the optional `except` argument.
269+
270+#### Arguments
271+
272+All optional:
273+
274+```
275+, =force ?, =except (set desk)
276+```
277+
278+#### Examples
279+
280+Try to apply update, failing if blocked by any desks:
281+
282+```
283+|bump
284+```
285+
286+Force the update, suspending incompatible desks:
287+
288+```
289+|bump, =force &
290+```
291+
292+Apply kernel update, omitting and suspending the specified desks:
293+
294+```
295+|bump, =except (silt ~[%bitcoin %webterm])
296+```
297+
298+---
299+
300+## `|rein`
301+
302+Adjust the state of a desk.
303+
304+This allows you to stop and start agents on a desk, regardless of whether they're on the manifest. Stopped agents have their states archived. It can also suspend and revive the whole desk with the optional `liv` argument.
305+
306+#### Arguments
307+
308+```
309+desk (list [? dude:gall]), =liv ?
310+```
311+
312+#### Examples
313+
314+Start an agent:
315+
316+```
317+|rein %bitcoin [& %btc-provider]
318+```
319+
320+Stop an agent, archiving its state:
321+
322+```
323+|rein %bitcoin [| %btc-wallet]
324+```
325+
326+Stop one agent, start another:
327+
328+```
329+|rein %bitcoin [| %btc-wallet] [& %btc-provider]
330+```
331+
332+Suspend a desk:
333+
334+```
335+|rein %bitcoin, =liv |
336+```
337+
338+Revive a desk:
339+
340+```
341+|rein %bitcoin
342+```
content/getting-started/_index.md+9
@@ -77,3 +77,12 @@ Or to install `snap` for your distribution, snapcraft provides [installation ins
7777</style>
7878
7979If you'd like to have more direct control over the Urbit virtual machine, or are setting up Urbit on a cloud droplet, try [installation using the command line](/getting-started/cli).
80+
81+### Next steps
82+
83+If you haven't already done so, we recommend spending 10 minutes or so reading
84+[Understanding Urbit](/understanding-urbit) to get acquainted with the project.
85+Then once you've been become acquainted with your ship and explored the network
86+for awhile, consider checking out the [User's Manual](/using) which provides
87+guidance and reference material for operating your ship, as well as explanations
88+for Urbit concepts everyone should eventually learn.
content/getting-started/planet.md+1−1
@@ -11,7 +11,7 @@ A planet is a permanent Urbit identity. Like all Urbit identities, they can neve
1111There are a few ways to get your own planet:
1212
1313- Getting an invitation from a friend (or stranger).
14−- Purchasing a planet, including hosting, from a [hosting provider](#hosting-providers) such as [geturbitid.com](https://www.geturbitid.com/).
14+- Purchasing a planet, including hosting, from a [hosting provider](#hosting-providers).
1515- Manually setting up and hosting a planet purchased from a third party such as [urbit.live](https://urbit.live), [OpenSea](https://opensea.io), [planet.market](https://planet.market/), [urbit.me](https://urbit.me), [urth systems](https://urth.systems/), or [Urbit Marketplace](https://urbitmarketplace.com/).
1616
1717Note that when you buy a planet, you should ensure with the provider that your parent star is operating. If you need to escape a non-operational star, see [Escaping A Sponsor](/using/id/using-bridge#escaping-your-sponsor).
content/grants/network-explorer-data-pipeline-http-api.md+2−2
@@ -10,10 +10,10 @@ grant_category = [ "App Dev" ]
1010image = ""
1111description = "Build a public, open HTTP API for exploring metrics about the Urbit network."
1212reward = 5
13−assignee = "Christopher King"
13+assignee = "~dinleb-rambep"
1414id = "1101665172"
1515completed = false
16−canceled = true
16+canceled = false
1717link = ""
1818+++
1919
content/grants/overhaul-the-urbitorg-website.md+2−2
@@ -9,10 +9,10 @@ grant_category = [ "Design" ]
99[extra]
1010image = ""
1111description = "Rework urbit.org to encourage participation with the project."
12−reward = 6
12+reward = 2
1313assignee = "~radbur-sivmus"
1414id = "246698762"
15−completed = false
15+completed = true
1616canceled = false
1717link = ""
1818+++
content/grants/urbian-a-customized-linux-distribution-for-urbit-appliances.md+1−1
@@ -13,7 +13,7 @@ reward = 2
1313assignee = "~botter-nidnul"
1414id = "337545546"
1515completed = false
16−canceled = false
16+canceled = true
1717link = ""
1818+++
1919
content/grants/urbit-event-series.md+1−1
@@ -12,7 +12,7 @@ description = "A series of community-focused events to create a new knowledge ba
1212reward = 6
1313assignee = "~naplet-hildec"
1414id = "1751024973"
15−completed = false
15+completed = true
1616canceled = false
1717link = ""
1818+++
content/using/_index.md+3−3
@@ -1,17 +1,17 @@
11+++
2−title = "Usage Docs"
2+title = "User's Manual"
33sort_by = "weight"
44template = "sections/docs/chapters.html"
55+++
66
7−Welcome to the usage documentation for the Urbit project. This documentation is
7+Welcome to the User's Manual for the Urbit project. This documentation is
88maintained by [Tlon](https://tlon.io) and the Urbit community in a public
99[Github repository](https://github.com/urbit/urbit.org). Issues and
1010contributions are welcome.
1111
1212This documentation provides a series of guides and reference material for
1313assisting you in the usage and operations of your ship. If you're looking for
14−documentation on how to *develop* on Urbit, see our [development docs](/docs/).
14+documentation on how to _develop_ on Urbit, see our [development docs](/docs/).
1515
1616### [Urbit OS](/using/os/)
1717
content/using/os/_index.md+1−1
@@ -10,7 +10,7 @@ This section describes how to interact with your running Urbit ship: this
1010includes working with the filesystem, command line (`dojo`), resolving common
1111issues, and more.
1212
13−### [Getting Started](/using/os/getting-started)
13+### [Basics](/using/os/basics)
1414
1515An overview of common commands and useful general knowledge for operating your
1616ship.
content/using/os/getting-started.md → content/using/os/basics.mdrenamed+1−1
@@ -1,5 +1,5 @@
11+++
2−title = "Getting Started"
2+title = "Basics"
33description = "How to operate your ship, including using your ship's filesystem and messaging applications, starting a moon, or requesting a DNS entry."
44template = "doc.html"
55weight = 1
lib/glossary.js+596
@@ -6526,4 +6526,600 @@ export const glossary = [
65266526 slug: "https://urbit.org/docs/reference/library/3f/#zyrtun",
65276527 desc: "Used in the Hoon standard library.",
65286528 },
6529+ // zuse
6530+ {
6531+ name: "Decode json (unit): Array as list",
6532+ symbol: "ar:dejs-soft:format",
6533+ usage: "zuse",
6534+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#ardejs-softformat",
6535+ desc: "Used in the Zuse library.",
6536+ },
6537+ {
6538+ name: "Decode json: Array as list",
6539+ symbol: "ar:dejs:format",
6540+ usage: "zuse",
6541+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#ardejsformat",
6542+ desc: "Used in the Zuse library.",
6543+ },
6544+ {
6545+ name: "Decode json: Array as set",
6546+ symbol: "as:dejs:format",
6547+ usage: "zuse",
6548+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#asdejsformat",
6549+ desc: "Used in the Zuse library.",
6550+ },
6551+ {
6552+ name: "Decode json (unit): Array as tuple, raw",
6553+ symbol: "at-raw:dejs-soft:format",
6554+ usage: "zuse",
6555+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#at-rawdejs-softformat",
6556+ desc: "Used in the Zuse library.",
6557+ },
6558+ {
6559+ name: "Decode json: Array as tuple, raw",
6560+ symbol: "at-raw:dejs:format",
6561+ usage: "zuse",
6562+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#at-rawdejsformat",
6563+ desc: "Used in the Zuse library.",
6564+ },
6565+ {
6566+ name: "Decode json (unit): Array as tuple",
6567+ symbol: "at:dejs-soft:format",
6568+ usage: "zuse",
6569+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#atdejs-softformat",
6570+ desc: "Used in the Zuse library.",
6571+ },
6572+ {
6573+ name: "Decode json: Array as tuple",
6574+ symbol: "at:dejs:format",
6575+ usage: "zuse",
6576+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#atdejsformat",
6577+ desc: "Used in the Zuse library.",
6578+ },
6579+ {
6580+ name: "Decode json (unit): Boolean",
6581+ symbol: "bo:dejs-soft:format",
6582+ usage: "zuse",
6583+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#bodejs-softformat",
6584+ desc: "Used in the Zuse library.",
6585+ },
6586+ {
6587+ name: "Decode json: Boolean",
6588+ symbol: "bo:dejs:format",
6589+ usage: "zuse",
6590+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#bodejsformat",
6591+ desc: "Used in the Zuse library.",
6592+ },
6593+ {
6594+ name: "Decode json (unit): Boolean NOT",
6595+ symbol: "bu:dejs-soft:format",
6596+ usage: "zuse",
6597+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#budejs-softformat",
6598+ desc: "Used in the Zuse library.",
6599+ },
6600+ {
6601+ name: "Decode json: Boolean NOT",
6602+ symbol: "bu:dejs:format",
6603+ usage: "zuse",
6604+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#budejsformat",
6605+ desc: "Used in the Zuse library.",
6606+ },
6607+ {
6608+ name: "Decode json (unit): Maybe transform",
6609+ symbol: "ci:dejs-soft:format",
6610+ usage: "zuse",
6611+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#cidejs-softformat",
6612+ desc: "Used in the Zuse library.",
6613+ },
6614+ {
6615+ name: "Decode json: Maybe transform",
6616+ symbol: "ci:dejs:format",
6617+ usage: "zuse",
6618+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#cidejsformat",
6619+ desc: "Used in the Zuse library.",
6620+ },
6621+ {
6622+ name: "Decode json (unit): Transform",
6623+ symbol: "cu:dejs-soft:format",
6624+ usage: "zuse",
6625+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#cudejs-softformat",
6626+ desc: "Used in the Zuse library.",
6627+ },
6628+ {
6629+ name: "Decode json: Transform",
6630+ symbol: "cu:dejs:format",
6631+ usage: "zuse",
6632+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#cudejsformat",
6633+ desc: "Used in the Zuse library.",
6634+ },
6635+ {
6636+ name: "Decode json (unit): UTC date",
6637+ symbol: "da:dejs-soft:format",
6638+ usage: "zuse",
6639+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#dadejs-softformat",
6640+ desc: "Used in the Zuse library.",
6641+ },
6642+ {
6643+ name: "Decode json (unit): Tank",
6644+ symbol: "dank:dejs-soft:format",
6645+ usage: "zuse",
6646+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#dankdejs-softformat",
6647+ desc: "Used in the Zuse library.",
6648+ },
6649+ {
6650+ name: "Container arm for unitized JSON decoding reparsers",
6651+ symbol: "dejs-soft:format",
6652+ usage: "zuse",
6653+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#dejs-softformat",
6654+ desc: "Used in the Zuse library.",
6655+ },
6656+ {
6657+ name: "Container arm for JSON decoding reparsers",
6658+ symbol: "dejs:format",
6659+ usage: "zuse",
6660+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#dejsformat",
6661+ desc: "Used in the Zuse library.",
6662+ },
6663+ {
6664+ name: "Parse JSON",
6665+ symbol: "de-json:html",
6666+ usage: "zuse",
6667+ slug: "https://urbit.org/docs/hoon/reference/zuse/2e_2-3/#de-jsonhtml",
6668+ desc: "Used in the Zuse library.",
6669+ },
6670+ {
6671+ name: "Decode json (unit): Millisecond date",
6672+ symbol: "di:dejs-soft:format",
6673+ usage: "zuse",
6674+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#didejs-softformat",
6675+ desc: "Used in the Zuse library.",
6676+ },
6677+ {
6678+ name: "Decode json: Millisecond date",
6679+ symbol: "di:dejs:format",
6680+ usage: "zuse",
6681+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#didejsformat",
6682+ desc: "Used in the Zuse library.",
6683+ },
6684+ {
6685+ name: "Decode json: Second date",
6686+ symbol: "du:dejs:format",
6687+ usage: "zuse",
6688+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#dudejsformat",
6689+ desc: "Used in the Zuse library.",
6690+ },
6691+ {
6692+ name: "Parse JSON",
6693+ symbol: "en-json:html",
6694+ usage: "zuse",
6695+ slug: "https://urbit.org/docs/hoon/reference/zuse/2e_2-3/#en-jsonhtml",
6696+ desc: "Used in the Zuse library.",
6697+ },
6698+ {
6699+ name: "Container arm for JSON encoders",
6700+ symbol: "enjs:format",
6701+ usage: "zuse",
6702+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#enjsformat",
6703+ desc: "Used in the Zuse library.",
6704+ },
6705+ {
6706+ name: "Encode json: Object from key-value pair",
6707+ symbol: "frond:enjs:format",
6708+ usage: "zuse",
6709+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#frondenjsformat",
6710+ desc: "Used in the Zuse library.",
6711+ },
6712+ {
6713+ name: "Json to rn parser",
6714+ symbol: "json-rn:format",
6715+ usage: "zuse",
6716+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#json-rnformat",
6717+ desc: "Used in the Zuse library.",
6718+ },
6719+ {
6720+ name: "Decode json (unit): True unit",
6721+ symbol: "mu:dejs-soft:format",
6722+ usage: "zuse",
6723+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#mudejs-softformat",
6724+ desc: "Used in the Zuse library.",
6725+ },
6726+ {
6727+ name: "Decode json: True unit",
6728+ symbol: "mu:dejs:format",
6729+ usage: "zuse",
6730+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#mudejsformat",
6731+ desc: "Used in the Zuse library.",
6732+ },
6733+ {
6734+ name: "Decode json (unit): Number as real",
6735+ symbol: "ne:dejs-soft:format",
6736+ usage: "zuse",
6737+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#nedejs-softformat",
6738+ desc: "Used in the Zuse library.",
6739+ },
6740+ {
6741+ name: "Decode json: Number as real",
6742+ symbol: "ne:dejs:format",
6743+ usage: "zuse",
6744+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#nedejsformat",
6745+ desc: "Used in the Zuse library.",
6746+ },
6747+ {
6748+ name: "Decode json (unit): Number as integer",
6749+ symbol: "ni:dejs-soft:format",
6750+ usage: "zuse",
6751+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#nidejs-softformat",
6752+ desc: "Used in the Zuse library.",
6753+ },
6754+ {
6755+ name: "Decode json: Number as integer",
6756+ symbol: "ni:dejs:format",
6757+ usage: "zuse",
6758+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#nidejsformat",
6759+ desc: "Used in the Zuse library.",
6760+ },
6761+ {
6762+ name: "Decode json (unit): Number as knot",
6763+ symbol: "no:dejs-soft:format",
6764+ usage: "zuse",
6765+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#nodejs-softformat",
6766+ desc: "Used in the Zuse library.",
6767+ },
6768+ {
6769+ name: "Decode json: Number as knot",
6770+ symbol: "no:dejs:format",
6771+ usage: "zuse",
6772+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#nodejsformat",
6773+ desc: "Used in the Zuse library.",
6774+ },
6775+ {
6776+ name: "Decode json: Parse string as hex",
6777+ symbol: "nu:dejs:format",
6778+ usage: "zuse",
6779+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#nudejsformat",
6780+ desc: "Used in the Zuse library.",
6781+ },
6782+ {
6783+ name: "Encode json: Number from unsigned",
6784+ symbol: "numb:enjs:format",
6785+ usage: "zuse",
6786+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#numbenjsformat",
6787+ desc: "Used in the Zuse library.",
6788+ },
6789+ {
6790+ name: "Line list to cord",
6791+ symbol: "of-wain:format",
6792+ usage: "zuse",
6793+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#of-wainformat",
6794+ desc: "Used in the Zuse library.",
6795+ },
6796+ {
6797+ name: "Line list to tape",
6798+ symbol: "of-wall:format",
6799+ usage: "zuse",
6800+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#of-wallformat",
6801+ desc: "Used in the Zuse library.",
6802+ },
6803+ {
6804+ name: "Decode json (unit): Object as frond",
6805+ symbol: "of:dejs-soft:format",
6806+ usage: "zuse",
6807+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#ofdejs-softformat",
6808+ desc: "Used in the Zuse library.",
6809+ },
6810+ {
6811+ name: "Decode json: Object as frond",
6812+ symbol: "of:dejs:format",
6813+ usage: "zuse",
6814+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#ofdejsformat",
6815+ desc: "Used in the Zuse library.",
6816+ },
6817+ {
6818+ name: "Decode json: Object as jug",
6819+ symbol: "oj:dejs:format",
6820+ usage: "zuse",
6821+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#ojdejsformat",
6822+ desc: "Used in the Zuse library.",
6823+ },
6824+ {
6825+ name: "Decode json (unit): Object as map",
6826+ symbol: "om:dejs-soft:format",
6827+ usage: "zuse",
6828+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#omdejs-softformat",
6829+ desc: "Used in the Zuse library.",
6830+ },
6831+ {
6832+ name: "Decode json: Object as map",
6833+ symbol: "om:dejs:format",
6834+ usage: "zuse",
6835+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#omdejsformat",
6836+ desc: "Used in the Zuse library.",
6837+ },
6838+ {
6839+ name: "Decode json (unit): Parse keys of map",
6840+ symbol: "op:dejs-soft:format",
6841+ usage: "zuse",
6842+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#opdejs-softformat",
6843+ desc: "Used in the Zuse library.",
6844+ },
6845+ {
6846+ name: "Decode json: Parse keys of map",
6847+ symbol: "op:dejs:format",
6848+ usage: "zuse",
6849+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#opdejsformat",
6850+ desc: "Used in the Zuse library.",
6851+ },
6852+ {
6853+ name: "Decode json (unit): Object as list of units, raw",
6854+ symbol: "ot-raw:dejs-soft:format",
6855+ usage: "zuse",
6856+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#ot-rawdejs-softformat",
6857+ desc: "Used in the Zuse library.",
6858+ },
6859+ {
6860+ name: "Decode json: Object as tuple, raw",
6861+ symbol: "ot-raw:dejs:format",
6862+ usage: "zuse",
6863+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#ot-rawdejsformat",
6864+ desc: "Used in the Zuse library.",
6865+ },
6866+ {
6867+ name: "Decode json (unit): Object as tuple",
6868+ symbol: "ot:dejs-soft:format",
6869+ usage: "zuse",
6870+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#otdejs-softformat",
6871+ desc: "Used in the Zuse library.",
6872+ },
6873+ {
6874+ name: "Decode json: Object as tuple",
6875+ symbol: "ot:dejs:format",
6876+ usage: "zuse",
6877+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#otdejsformat",
6878+ desc: "Used in the Zuse library.",
6879+ },
6880+ {
6881+ name: "Decode json: Object of units, raw",
6882+ symbol: "ou-raw:dejs:format",
6883+ usage: "zuse",
6884+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#ou-rawdejsformat",
6885+ desc: "Used in the Zuse library.",
6886+ },
6887+ {
6888+ name: "Decode json: Object of units",
6889+ symbol: "ou:dejs:format",
6890+ usage: "zuse",
6891+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#oudejsformat",
6892+ desc: "Used in the Zuse library.",
6893+ },
6894+ {
6895+ name: "Decode json: String as path",
6896+ symbol: "pa:dejs:format",
6897+ usage: "zuse",
6898+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#padejsformat",
6899+ desc: "Used in the Zuse library.",
6900+ },
6901+ {
6902+ name: "Encode json: Object from key-value pair list",
6903+ symbol: "pairs:enjs:format",
6904+ usage: "zuse",
6905+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#pairsenjsformat",
6906+ desc: "Used in the Zuse library.",
6907+ },
6908+ {
6909+ name: "Encode json: String from path",
6910+ symbol: "path:enjs:format",
6911+ usage: "zuse",
6912+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#pathenjsformat",
6913+ desc: "Used in the Zuse library.",
6914+ },
6915+ {
6916+ name: "Decode json (unit): Prefix",
6917+ symbol: "pe:dejs-soft:format",
6918+ usage: "zuse",
6919+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#pedejs-softformat",
6920+ desc: "Used in the Zuse library.",
6921+ },
6922+ {
6923+ name: "Decode json: Prefix",
6924+ symbol: "pe:dejs:format",
6925+ usage: "zuse",
6926+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#pedejsformat",
6927+ desc: "Used in the Zuse library.",
6928+ },
6929+ {
6930+ name: "Decode json (unit): Recursive reparser",
6931+ symbol: "re:dejs-soft:format",
6932+ usage: "zuse",
6933+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#redejs-softformat",
6934+ desc: "Used in the Zuse library.",
6935+ },
6936+ {
6937+ name: "Decode json (unit): String as tape",
6938+ symbol: "sa:dejs-soft:format",
6939+ usage: "zuse",
6940+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#sadejs-softformat",
6941+ desc: "Used in the Zuse library.",
6942+ },
6943+ {
6944+ name: "Decode json: String as tape",
6945+ symbol: "sa:dejs:format",
6946+ usage: "zuse",
6947+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#sedejsformat",
6948+ desc: "Used in the Zuse library.",
6949+ },
6950+ {
6951+ name: "Decode json: String @ud as date",
6952+ symbol: "sd:dejs:format",
6953+ usage: "zuse",
6954+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#sddejsformat",
6955+ desc: "Used in the Zuse library.",
6956+ },
6957+ {
6958+ name: "Decode json: String as aura",
6959+ symbol: "se:dejs:format",
6960+ usage: "zuse",
6961+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#sedejsformat",
6962+ desc: "Used in the Zuse library.",
6963+ },
6964+ {
6965+ name: "Encode json: Seconds timestamp",
6966+ symbol: "sect:enjs:format",
6967+ usage: "zuse",
6968+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#sectenjsformat",
6969+ desc: "Used in the Zuse library.",
6970+ },
6971+ {
6972+ name: "Encode json: String from ship",
6973+ symbol: "ship:enjs:format",
6974+ usage: "zuse",
6975+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#shipenjsformat",
6976+ desc: "Used in the Zuse library.",
6977+ },
6978+ {
6979+ name: "Decode json (unit): String as cord",
6980+ symbol: "so:dejs-soft:format",
6981+ usage: "zuse",
6982+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#sodejs-softformat",
6983+ desc: "Used in the Zuse library.",
6984+ },
6985+ {
6986+ name: "Decode json: String as cord",
6987+ symbol: "so:dejs:format",
6988+ usage: "zuse",
6989+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#sodejsformat",
6990+ desc: "Used in the Zuse library.",
6991+ },
6992+ {
6993+ name: "Decode json (unit): Parse string",
6994+ symbol: "su:dejs-soft:format",
6995+ usage: "zuse",
6996+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#sudejs-softformat",
6997+ desc: "Used in the Zuse library.",
6998+ },
6999+ {
7000+ name: "Decode json: Parse string",
7001+ symbol: "su:dejs:format",
7002+ usage: "zuse",
7003+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#sudejsformat",
7004+ desc: "Used in the Zuse library.",
7005+ },
7006+ {
7007+ name: "Encode json: Tank as string array",
7008+ symbol: "tank:enjs:format",
7009+ usage: "zuse",
7010+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#tankenjsformat",
7011+ desc: "Used in the Zuse library.",
7012+ },
7013+ {
7014+ name: "Encode json: String from tape",
7015+ symbol: "tape:enjs:format",
7016+ usage: "zuse",
7017+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#tapeenjsformat",
7018+ desc: "Used in the Zuse library.",
7019+ },
7020+ {
7021+ name: "Encode json: Millisecond timestamp",
7022+ symbol: "time:enjs:format",
7023+ usage: "zuse",
7024+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#timeenjsformat",
7025+ desc: "Used in the Zuse library.",
7026+ },
7027+ {
7028+ name: "Cord to line list",
7029+ symbol: "to-wain:format",
7030+ usage: "zuse",
7031+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#to-wainformat",
7032+ desc: "Used in the Zuse library.",
7033+ },
7034+ {
7035+ name: "Decode json: Unit fall",
7036+ symbol: "uf:dejs:format",
7037+ usage: "zuse",
7038+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#ufdejsformat",
7039+ desc: "Used in the Zuse library.",
7040+ },
7041+ {
7042+ name: "Decode json (unit): Null",
7043+ symbol: "ul:dejs-soft:format",
7044+ usage: "zuse",
7045+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#uldejs-softformat",
7046+ desc: "Used in the Zuse library.",
7047+ },
7048+ {
7049+ name: "Decode json: Null",
7050+ symbol: "ul:dejs:format",
7051+ usage: "zuse",
7052+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#uldejsformat",
7053+ desc: "Used in the Zuse library.",
7054+ },
7055+ {
7056+ name: "Decode json: Unit need",
7057+ symbol: "un:dejs:format",
7058+ usage: "zuse",
7059+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#undejsformat",
7060+ desc: "Used in the Zuse library.",
7061+ },
7062+ {
7063+ name: "Encode json: String from wall",
7064+ symbol: "wall:enjs:format",
7065+ usage: "zuse",
7066+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_1-5/#wallenjsformat",
7067+ desc: "Used in the Zuse library.",
7068+ },
7069+ {
7070+ name: "Decode json (unit): Full unit pole",
7071+ symbol: "za:dejs-soft:format",
7072+ usage: "zuse",
7073+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#zadejs-softformat",
7074+ desc: "Used in the Zuse library.",
7075+ },
7076+ {
7077+ name: "Decode json: Full unit pole",
7078+ symbol: "za:dejs:format",
7079+ usage: "zuse",
7080+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#zadejsformat",
7081+ desc: "Used in the Zuse library.",
7082+ },
7083+ {
7084+ name: "Decode json (unit): Collapse unit list",
7085+ symbol: "zl:dejs-soft:format",
7086+ usage: "zuse",
7087+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#zldejs-softformat",
7088+ desc: "Used in the Zuse library.",
7089+ },
7090+ {
7091+ name: "Decode json: Collapse unit list",
7092+ symbol: "zl:dejs:format",
7093+ usage: "zuse",
7094+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#zldejsformat",
7095+ desc: "Used in the Zuse library.",
7096+ },
7097+ {
7098+ name: "Decode json (unit): Collapse unit map",
7099+ symbol: "zm:dejs-soft:format",
7100+ usage: "zuse",
7101+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#zmdejs-softformat",
7102+ desc: "Used in the Zuse library.",
7103+ },
7104+ {
7105+ name: "Decode json: Collapse unit map",
7106+ symbol: "zm:dejs:format",
7107+ usage: "zuse",
7108+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#zmdejsformat",
7109+ desc: "Used in the Zuse library.",
7110+ },
7111+ {
7112+ name: "Decode json (unit): Unit tuple",
7113+ symbol: "zp:dejs-soft:format",
7114+ usage: "zuse",
7115+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_7/#zpdejs-softformat",
7116+ desc: "Used in the Zuse library.",
7117+ },
7118+ {
7119+ name: "Decode json: Unit tuple",
7120+ symbol: "zp:dejs:format",
7121+ usage: "zuse",
7122+ slug: "https://urbit.org/docs/hoon/reference/zuse/2d_6/#zpdejsformat",
7123+ desc: "Used in the Zuse library.",
7124+ },
65297125];
pages/using/[[...slug]].js+3−3
@@ -16,7 +16,7 @@ const breadcrumbs = (posts, paths) => {
1616 const results = [
1717 <Link href="/">Urbit</Link>,
1818 <span className="px-1">/</span>,
19− <Link href="/using">Operator's Manual</Link>,
19+ <Link href="/using">User's Manual</Link>,
2020 ];
2121 let thisLink = "/using";
2222 for (const path of paths) {
@@ -102,7 +102,7 @@ export default function UsingLayout({ posts, data, params, search, markdown }) {
102102 return (
103103 <>
104104 <Head>
105− <title>{data.title} • Operator's Manual • urbit.org</title>
105+ <title>{data.title} • User's Manual • urbit.org</title>
106106 {Meta(data)}
107107 </Head>
108108 <div className="flex w-screen h-screen min-h-screen w-screen sidebar">
@@ -113,7 +113,7 @@ export default function UsingLayout({ posts, data, params, search, markdown }) {
113113 breadcrumbs={breadcrumbs(posts, params.slug?.slice(0, -1) || "")}
114114 title={data.title}
115115 search={search}
116− section={"Operator's Manual"}
116+ section={"User's Manual"}
117117 params={params}
118118 >
119119 <div className="markdown">
vercel.json+5
@@ -3,6 +3,11 @@
33 "silent": true
44 },
55 "redirects": [
6+ {
7+ "source": "/using/os/getting-started",
8+ "destination": "/using/os/basics",
9+ "permanent": true
10+ },
611 {
712 "source": "/grants/(apprenticeships|proposals|bounties)/:page",
813 "destination": "/grants/:page",