on master help sign in
Merge pull request #1069 from tinnus-napbus/update-clay-docs

Update clay docs

commit4ec23b39378221a18841516afeac3ee9f65b0d59 authorpoprox <51337059+drbeefsupreme@users.noreply.github.com> dateWed 2 Jun 2021, 13:12 (5 years ago) parentf4ad20752a89d8
9 files changed+1816−1461
arvo/clay/_index.md+6−7 arvo/clay/clay.md+6−6 arvo/clay/examples.md+824 arvo/clay/foreign.md−412 arvo/clay/local-reads.md−783 arvo/clay/local-sub.md−249 arvo/clay/scry.md+425 arvo/clay/tasks.md+555 arvo/clay/using.md−4
arvo/clay/_index.md+6−7
@@ -23,15 +23,14 @@ reading and subscribing, syncing to Unix, and merging.
2323
2424Explanations of the many data types found throughout Clay.
2525
26−[Local Reads and Writes](@/docs/arvo/clay/local-reads.md)
26+[Scry Reference](@/docs/arvo/clay/scry.md)
2727
28−How local reads and writes work.
28+Reference for Clay's various scry endpoints.
2929
30−[Local Subscriptions](@/docs/arvo/clay/local-sub.md)
30+[API Reference](@/docs/arvo/clay/tasks.md)
3131
32−How local subscriptions work.
32+Details of the various `task`s you can use to interact with Clay.
3333
34−[Foreign Requests](@/docs/arvo/clay/foreign.md)
35−
36−How foreign reads and subscriptions work.
34+[Examples](@/docs/arvo/clay/examples.md)
3735
36+Example usage of the various Clay `task`s.
arvo/clay/clay.md+6−6
@@ -52,14 +52,14 @@ reading and subscribing, syncing to Unix, and merging. (Up to date as of April 2
5252
5353Explanations of the many data types found throughout Clay. (Up to date as of April 2021)
5454
55−[Local Reads and Writes](@/docs/arvo/clay/local-reads.md)
55+[Scry Reference](@/docs/arvo/clay/scry.md)
5656
57−How local reads and writes work.
57+Reference for Clay's various scry endpoints.
5858
59−[Local Subscriptions](@/docs/arvo/clay/local-sub.md)
59+[API Reference](@/docs/arvo/clay/tasks.md)
6060
61−How local subscriptions work.
61+Details of the various `task`s you can use to interact with Clay.
6262
63−[Foreign Requests](@/docs/arvo/clay/foreign.md)
63+[Examples](@/docs/arvo/clay/examples.md)
6464
65−How foreign reads and subscriptions work.
65+Example usage of the various Clay `task`s.
arvo/clay/examples.mdnew file+824
@@ -0,0 +1,824 @@
1++++
2+title = "Examples"
3+weight = 7
4+template = "doc.html"
5++++
6+
7+# Contents
8+
9+- [Introduction](#introduction)
10+- [%warp](#warp) - Read and Subscribe.
11+ - [%sing](#sing) - Read a file or directory.
12+ - [%next](#next) - Subscribe for the next change to a file or directory.
13+ - [%mult](#mult) - Subscribe for the next change to a set of files and/or directories.
14+ - [%many](#many) - Track changes to a `desk` for the specified range of revisions.
15+ - [Cancel Subscription](#cancel-subscription)
16+- [%info](#info) - Write and Modify.
17+ - [%ins](#ins) - Add a file.
18+ - [%del](#del) - Delete a file.
19+ - [%mut](#mut) - Change a file.
20+ - [Multiple Changes](#multiple-changes) - Change multiple files.
21+- [Manage Mounts](#manage-mounts)
22+ - [%boat](#boat) - List mounts.
23+ - [%mont](#mont) - Mount something.
24+ - [%ogre](#ogre) - Unmount something.
25+ - [%dirk](#dirk) - Commit changes.
26+- [Merge Desks](#merge-desks)
27+ - [%merg](#merg)
28+- [Permissions](#permissions)
29+ - [%perm](#perm) - Set file permissions.
30+ - [%cred](#cred) - Add permission group.
31+ - [%crew](#crew) - Get permission groups.
32+ - [%crow](#crow) - Get group usage.
33+- [Foreign Ships](#foreign-ships)
34+ - [%warp](#warp-remote) - Read a file on a foreign ship.
35+ - [%merg](#merg-remote) - Merge from a foreign `desk`.
36+
37+# Introduction
38+
39+This document contains a number of examples of interacting with Clay using its various `task`s. Sections correspond to the general details in the [API Reference](@/docs/arvo/clay/tasks.md) document.
40+
41+Most examples will either use `|pass` to just send a `task` or the following thread to send a `task` and take the resulting `gift`. You can save the following thread to the `ted` directory of your `%home` `desk`:
42+
43+`send-task-take-gift.hoon`
44+
45+```hoon
46+/- spider
47+/+ strandio
48+=, strand=strand:spider
49+^- thread:spider
50+|= arg=vase
51+=/ m (strand ,vase)
52+^- form:m
53+=/ uarg !< (unit task:clay) arg
54+?~ uarg
55+ (strand-fail:strand %no-arg ~)
56+=/ =task:clay u.uarg
57+=/ =card:agent:gall [%pass /foo %arvo %c task]
58+;< ~ bind:m (send-raw-card:strandio card)
59+;< res=[wire sign-arvo] bind:m take-sign-arvo:strandio
60+~& +>:res
61+(pure:m !>(~))
62+```
63+
64+# `%warp`
65+
66+See the [Read and Subscribe](@/docs/arvo/clay/tasks.md#warp) section of the [API Reference](@/docs/arvo/clay/tasks.md) document for general details.
67+
68+## `%sing`
69+
70+Here we'll look at reading files by passing Clay a `%warp` `task` with a `%sing` `rave` and receiving a `%writ` `gift` containing the data in response.
71+
72+
73+Using the `send-task-take-gift.hoon` thread, let's try reading `gen/hood/hi.hoon`:
74+
75+```
76+> -send-task-take-gift [%warp our %home ~ %sing %x da+now /gen/hood/hi/hoon]
77+```
78+
79+You should see something like this as the output:
80+
81+```
82+[ %writ
83+ p
84+ [ ~
85+ [ p=[p=%x q=[%da p=~2021.5.20..23.37.50..e79b] r=%home]
86+ q=/gen/hood/hi/hoon
87+ r
88+ [ p=%hoon
89+ q
90+ [ #t/@
91+ q
92+ 3.548.750.706.400.251.607.252.023.288.575.526.190.856.734.474.077.821.289.791.377.301.707.878.697.553.411.219.689.905.949.957.893.633.811.025.757.107.990.477.902.858.170.125.439.223.250.551.937.540.468.638.902.955.378.837.954.792.031.592.462.617.422.136.386.332.469.076.584.061.249.923.938.374.214.925.312.954.606.277.212.923.859.309.330.556.730.410.200.952.056.760.727.611.447.500.996.168.035.027.753.417.869.213.425.113.257.514.474.700.810.203.348.784.547.006.707.150.406.298.809.062.567.217.447.347.357.039.994.339.342.906
93+ ]
94+ ]
95+ ]
96+ ]
97+]
98+```
99+
100+The `cage` in the `riot` of the `%writ` contains the file's data due to our use of an `%x` `care`. It needn't be `%x` though. If we change it to `%u`, for example, we'll get a `?` `cage` instead:
101+
102+```
103+> -send-task-take-gift [%warp our %home ~ %sing %x da+now /gen/hood/hi/hoon]
104+[ %writ
105+ p
106+ [ ~
107+ [ p=[p=%u q=[%da p=~2021.5.20..23.42.21..bb33] r=%home]
108+ q=/gen/hood/hi/hoon
109+ r=[p=%flag q=[#t/?(%.y %.n) q=0]]
110+ ]
111+ ]
112+]
113+```
114+
115+Here's a breakdown of the `task` we sent:
116+
117+![%sing diagram](https://media.urbit.org/docs/arvo/clay/sing.png "%sing diagram")
118+
119+## `%next`
120+
121+Here we'll look at subscribing to the next version of a file by passing Clay a `%warp` `task` with a `%next` `rave` and receiving a `%writ` `gift` when the file changes.
122+
123+Using the `send-task-take-gift.hoon` thread, let's subscribe to the next version of `foo.txt`:
124+
125+```
126+> -send-task-take-gift [%warp our %home ~ %next %x da+now /foo/txt]
127+```
128+
129+Now, in unix, create a file called `foo.txt` in the root of the `home` directory of your ship. In the dojo, hit backspace to disconnect the thread from the dojo prompt and run `|commit %home`. You should see something like:
130+
131+```
132+> |commit %home
133+>=
134+[%writ p=[~ [p=[p=%x q=[%ud p=3] r=%home] q=/foo/txt r=[p=%txt q=[#t/*'' q=0]]]]]
135++ /~zod/home/3/foo/txt
136+```
137+
138+As you can see, the `riot` in the `%writ` includes a `cage` with the data of `/foo/txt` due to our use of an `%x` `care`.
139+
140+Now run the thread again, and this time delete the file in unix and again `|commit %home` in the dojo. You should see:
141+
142+```
143+> |commit %home
144+>=
145+[%writ p=~]
146+- /~zod/home/4/foo/txt
147+```
148+
149+You can see the `riot` is just `~` due to the file being deleted.
150+
151+Here's a breakdown of the task we sent:
152+
153+![%next diagram](https://media.urbit.org/docs/arvo/clay/next.png "%next diagram")
154+
155+## `%mult`
156+
157+Here we'll look at subscribing to the next version of multiple files by passing Clay a `%warp` `task` with a `%mult` `rave` and receiving a `%wris` `gift` when any of the files change.
158+
159+This thread will subscribe to `/foo/txt` with an `%x` `care` and `/bar/txt` with a `%u` `care`. It will print out the `%wris` it gets back from Clay.
160+
161+`sub-mult.hoon`
162+
163+```hoon
164+/- spider
165+/+ strandio
166+=, strand=strand:spider
167+^- thread:spider
168+|= arg=vase
169+=/ m (strand ,vase)
170+^- form:m
171+=/ files=(set (pair care:clay path))
172+ %- sy :~
173+ [%x /foo/txt]
174+ [%u /bar/txt]
175+ ==
176+;< =bowl:strand bind:m get-bowl:strandio
177+=/ =task:clay [%warp our.bowl %home ~ %mult da+now.bowl files]
178+=/ =card:agent:gall [%pass /mult %arvo %c task]
179+;< ~ bind:m (send-raw-card:strandio card)
180+;< response=(pair wire sign-arvo) bind:m take-sign-arvo:strandio
181+~& +.q.response
182+(pure:m !>(~))
183+```
184+
185+Save the above to `ted/sub-mult.hoon`, `|commit %home` and run with `-sub-mult`. Now, create `foo.txt` and `bar.txt` in your home directory, hit backspace in the dojo to disconnect the thread and run `|commit %home`. You should see something like:
186+
187+```
188+> |commit %home
189+>=
190+[%wris p=[%da p=~2021.4.27..06.07.08..5ec4] q={[p=%u q=/bar/txt] [p=%x q=/foo/txt]}]
191++ /~zod/home/151/foo/txt
192++ /~zod/home/151/bar/txt
193+```
194+
195+You'll notice that, unlike a `%writ`, the `%wris` doesn't give you the data. It merely tells you the `care`s and `path`s of the files that changed. If you need to actually get the data, you can just scry or send a request for the files in question.
196+
197+Now, run the thread again, open `bar.txt` in an editor, modify its contents, save it and `|commit %home`. You'll notice you didn't receive a `%wris`. This is because we subscribed to `/bar/txt` with `%u` care and its existence didn't change.
198+
199+Lastly, delete `foo.txt` and `|commit %home`. You should see something like:
200+
201+```
202+> |commit %home
203+>=
204+[%wris p=[%da p=~2021.4.27..06.15.03..0da4] q={[p=%x q=/foo/txt]}]
205+- /~zod/home/153/foo/txt
206+```
207+
208+As you can see, a relevant change to any of the subscribed files will trigger a response, not just when all of them change.
209+
210+Here's a breakdown of the `task` we sent:
211+
212+![subscribe mult diagram](https://media.urbit.org/docs/arvo/clay/sub-mult.png "subscribe mult diagram")
213+
214+## `%many`
215+
216+Here we'll look at subscribing to a range of changes to a `desk` by passing Clay a `%warp` `task` with a `%many` `rave` and receiving `%writ` `gift`s when changes occur.
217+
218+This thread will subscribe to changes to your `%home` `desk` for the next three minutes. The `track` is `%.y` so it will only inform you of changes, not send the full `nako`. It will only get updates if the specified file exists. It contains a `main-loop` that will take an arbitrary number of `sign`s and print them out in the dojo. Since it never ends, you'll need to stop it with the `:spider|kill` command in the dojo.
219+
220+`sub-many.hoon`
221+
222+```hoon
223+/- spider
224+/+ strandio
225+=, strand=strand:spider
226+|%
227+++ take-sign-loop
228+ =/ m (strand ,~)
229+ ^- form:m
230+ %- (main-loop:strandio ,~)
231+ :~ |= ~
232+ ^- form:m
233+ ;< res=(pair wire sign-arvo)
234+ bind:m
235+ ((handle:strandio ,(pair wire sign-arvo)) take-sign-arvo:strandio)
236+ ~& res
237+ (pure:m ~)
238+ ==
239+--
240+^- thread:spider
241+|= arg=vase
242+=/ m (strand ,vase)
243+^- form:m
244+=/ uarg !< (unit path) arg
245+?~ uarg
246+ (strand-fail:strand %no-arg ~)
247+=/ =path u.uarg
248+;< =bowl:strand bind:m get-bowl:strandio
249+=/ =task:clay [%warp our.bowl %home ~ %many %.y da+now.bowl da+(add ~m3 now.bowl) path]
250+=/ =card:agent:gall [%pass /many %arvo %c task]
251+;< ~ bind:m (send-raw-card:strandio card)
252+;< ~ bind:m take-sign-loop
253+(pure:m !>(~))
254+```
255+
256+Make sure `foo.txt` doesn't exist in the root of your `%home` `desk`. Save this to `ted/sub-many.hoon`, `|commit %home`, run it like `-sub-many /foo/txt`, and hit backspace in the dojo to free up the dojo prompt. Now, add a file called `bar.txt` to your `desk` and `|commit %home`. You should see something like:
257+
258+```
259+> |commit %home
260+>=
261++ /~zod/home/260/bar/txt
262+```
263+
264+Notice you've received no `%writ` from Clay. This is because `/foo/txt` doesn't exist. Now, create `foo.txt` and `|commit %home` again. You should see:
265+
266+```
267+> |commit %home
268+>=
269+[ p=/many
270+ q=[%clay [%writ p=[~ [p=[p=%w q=[%ud p=261] r=%home] q=/ r=[p=%null q=[#t/@n q=0]]]]]]
271+]
272++ /~zod/home/261/foo/txt
273+```
274+
275+Now that `/foo/txt` exists it will inform you of updates. Note that if you delete `/foo/txt` again it will again stop sending updates.
276+
277+Now try adding `baz.txt`:
278+
279+```
280+> |commit %home
281+>=
282+[ p=/many
283+ q=[%clay [%writ p=[~ [p=[p=%w q=[%ud p=262] r=%home] q=/ r=[p=%null q=[#t/@n q=0]]]]]]
284+]
285++ /~zod/home/262/baz/txt
286+```
287+
288+Now wait until the three minutes is up and try making a change, for example deleting `baz.txt`:
289+
290+```
291+> |commit %home
292+>=
293+[ p=/many
294+ q=[%clay [%writ p=[~ [p=[p=%w q=[%ud p=264] r=%home] q=/ r=[p=%null q=[#t/@n q=0]]]]]]
295+]
296+[p=/many q=[%clay [%writ p=~]]]
297+- /~zod/home/263/baz/txt
298+```
299+
300+You can see that along with the normal `%writ` it's also sent a second `%writ` with a null `riot` to indicate the subscription has ended. This is because it has now passed the end of the range of `case`s to which you subscribed.
301+
302+Run `:spider|kill` to stop the thread.
303+
304+Here's a breakdown of the `task` we sent:
305+
306+![subscribe many diagram](https://media.urbit.org/docs/arvo/clay/sub-many.png "subscribe many diagram")
307+
308+## Cancel Subscription
309+
310+Here we'll look at cancelling a subscription by sending Clay a `%warp` `task` with a null `(unit rave)` in the `riff`.
311+
312+This thread will subscribe to the `%next` version of `/foo/txt`, then immediately cancel the subscription and wait for a response to print (which it will never receive).
313+
314+`stop-sub.hoon`
315+
316+```hoon
317+/- spider
318+/+ strandio
319+=, strand=strand:spider
320+^- thread:spider
321+|= arg=vase
322+=/ m (strand ,vase)
323+^- form:m
324+;< =bowl:strand bind:m get-bowl:strandio
325+=/ =task:clay [%warp our.bowl %home ~ %next %x da+now.bowl /foo/txt]
326+=/ =card:agent:gall [%pass /next %arvo %c task]
327+;< ~ bind:m (send-raw-card:strandio card)
328+=. task [%warp our.bowl %home ~]
329+=. card [%pass /next %arvo %c task]
330+;< ~ bind:m (send-raw-card:strandio card)
331+;< =riot:clay bind:m (take-writ:strandio /next)
332+~& riot
333+(pure:m !>(~))
334+```
335+
336+Save the above to `ted/stop-sub.hoon`, `|commit %home`, run it with `-stop-sub` and hit backspace to detach it from the dojo prompt. Now, add `foo.txt` to the root of your `%home` `desk` and `|commit %home`. You should see:
337+
338+```
339+> |commit %home
340+>=
341++ /~zod/home/266/foo/txt
342+```
343+
344+As you can see we've received no `%writ`. We can thus conclude the subscription has successfully been cancelled.
345+
346+Run `:spider|kill` to stop the thread.
347+
348+Here's a breakdown of the `task` we sent:
349+
350+![cancel subscription diagram](https://media.urbit.org/docs/arvo/clay/stop-sub.png "cancel subscription diagram")
351+
352+# `%info`
353+
354+See the [Write and Modify](@/docs/arvo/clay/tasks.md#write-and-modify) section of the [API Reference](@/docs/arvo/clay/tasks.md) document for general details.
355+
356+## `%ins`
357+
358+Here we'll look at adding a file by sending Clay a `%info` `task` containing a `%ins` `miso`.
359+
360+Let's try adding a `foo.txt` file with 'foo' as its contents:
361+
362+```
363+> |pass [%c [%info %home %& [/foo/txt %ins %txt !>(~['foo'])]~]]
364++ /~zod/home/5/foo/txt
365+```
366+
367+If you have a look in the home of your pier you'll see there's now a file called `foo.txt` with the text `foo` in it.
368+
369+We've created the `cage` of the content like `[%txt !>(~['foo'])]`, if you want to write something besides a text file you'd just give it the appropriate `mark` and `vase`.
370+
371+Here's a breakdown of the `task` we sent:
372+
373+![%ins diagram](https://media.urbit.org/docs/arvo/clay/ins.png)
374+
375+## `%del`
376+
377+Here we'll look at deleting a file by sending Clay a `%info` `task` containing a `%del` `miso`.
378+
379+Let's try deleting the `foo.txt` file created in the [previous example](#ins):
380+
381+```
382+> |pass [%c [%info %home %& [/foo/txt %del ~]~]]
383+- /~zod/home/6/foo/txt
384+```
385+
386+If you have a look in the home of your pier you'll see the `foo.txt` file is now gone.
387+
388+Here's a breakdown of the `task` we sent:
389+
390+![%del diagram](https://media.urbit.org/docs/arvo/clay/del.png)
391+
392+## `%mut`
393+
394+Identical to the [%ins](#ins) example, just replace `%ins` with `%mut`.
395+
396+## Multiple Changes
397+
398+Here we'll look at changing multiple files in one request by sending Clay a `%info` `task` containing multiple `miso` in the `soba`.
399+
400+Since `soba` is just a `list` of `miso`, you can add a bunch of `miso` and they'll all be applied. This thread adds three files and then deletes them. Here there's only one type of `miso` in each request but you could mix different types together too.
401+
402+`multi-change.hoon`
403+
404+```hoon
405+/- spider
406+/+ strandio
407+=, strand=strand:spider
408+^- thread:spider
409+|= arg=vase
410+=/ m (strand ,vase)
411+^- form:m
412+=/ soba-a :~ [/foo/txt %ins %txt !>(['foo' ~])]
413+ [/bar/txt %ins %txt !>(['bar' ~])]
414+ [/baz/txt %ins %txt !>(['baz' ~])]
415+ ==
416+=/ soba-b :~ [/foo/txt %del ~]
417+ [/bar/txt %del ~]
418+ [/baz/txt %del ~]
419+ ==
420+;< ~ bind:m (send-raw-card:strandio [%pass /info %arvo %c %info %home %& soba-a])
421+;< ~ bind:m (send-raw-card:strandio [%pass /info %arvo %c %info %home %& soba-b])
422+(pure:m !>(~))
423+```
424+
425+Save to `ted/multi-change.hoon`, `|commit %home`, and run:
426+
427+```
428+> -multi-change
429++ /~zod/home/37/foo/txt
430++ /~zod/home/37/bar/txt
431++ /~zod/home/37/baz/txt
432+- /~zod/home/38/foo/txt
433+- /~zod/home/38/bar/txt
434+- /~zod/home/38/baz/txt
435+```
436+
437+# Manage Mounts
438+
439+See the [Manage Mounts](@/docs/arvo/clay/tasks.md#manage-mounts) section of the [API Reference](@/docs/arvo/clay/tasks.md) document for general details.
440+
441+## `%boat`
442+
443+Here we'll look at requesting the list of existing mount points on a ship by sending Clay a `%boat` `task` and receiving a `%hill` `gift`.
444+
445+Using the `send-task-take-gift.hoon` thread, let's make such a request:
446+
447+```
448+> -send-task-take-gift [%boat ~]
449+[%hill p=~[%home]]
450+```
451+
452+## `%mont`
453+
454+Here we'll look at mounting `desk`s, directories and files to unix by sending Clay a `%mont` `task`.
455+
456+Let's first try mounting our `%kids` desk:
457+
458+```
459+> |pass [%c [%mont %kids [our %kids da+now] /]]
460+```
461+
462+If you look in your pier, you should now see a `kids` folder which contains the contents of that `desk`.
463+
464+If we make a `%boat` request as detailed in the [%boat](#boat) section, we'll now see the mount point listed:
465+
466+```
467+> -send-task-take-gift [%boat ~]
468+[%hill p=~[%kids %home]]cruz gift. It looks like:
469+
470+[%cruz cez=(map @ta crew)] :: permission groups
471+The cez is just a map from group name to crew
472+```
473+
474+Note the mount point doesn't need to match a `desk`, file or directory. We can also do:
475+
476+```
477+> |pass [%c [%mont %wibbly-wobbly [our %home da+now] /]]
478+```
479+
480+And you'll now see that there's a `wibbly-wobbly` folder with the contents of the `%home` `desk`. You'll also notice we can mount the same file or directory more than once. There's no problem having `%home` mounted to both `home` and `wibbly-wobbly`. The only requirement is that their mount points be unique.
481+
482+Let's try mounting a subdirectory and a single folder:
483+
484+```
485+> |pass [%c [%mont %gen [our %home da+now] /gen]]
486+> |pass [%c [%mont %hi [our %home da+now] /gen/hood/hi]]
487+```
488+
489+If you look in your pier you'll now see a `gen` folder with the contents of `/gen` and a `hi.hoon` file by itself. Notice how the file extension has been automatically added.
490+
491+## `%ogre`
492+
493+Here we'll look at unmounting `desk`s, directories and files by sending Clay a `%ogre` `task`.
494+
495+Let's unmount what we mounted in the [%mont](#mont) section. First we'll unmount the `%kids` desk:
496+
497+```
498+|pass [%c [%ogre %kids]]
499+```
500+
501+Our custom mount point `%wibbly-wobbly`:
502+
503+```
504+|pass [%c [%ogre %wibbly-wobbly]]
505+```
506+
507+And the single `hi.hoon` we previously mounted by specifying its mount point `%hi`:
508+
509+```
510+|pass [%c [%ogre %hi]]
511+```
512+
513+If we specify a non-existent mount point it will fail with an error printed to the dojo like:
514+
515+```
516+> |pass [%c [%ogre %kids]]
517+[%not-mounted %kids]
518+```
519+
520+If we give it an unmounted `beam` it will not print an error but still won't work.
521+
522+## `%dirk`
523+
524+Here we'll look at committing changed files by sending Clay a `%dirk` `task`.
525+
526+This `task` performs the same function as the `|commit` dojo command.
527+
528+With your `%home` `desk` mounted, try adding a file and send a `%dirk` to commit the change:
529+
530+```
531+> |pass [%c [%dirk %home]]
532++ /~zod/home/12/foo/txt
533+```
534+
535+Clay will print the changed files to the dojo with a leading `+`, `-` or `:` to indicate a new file, deleted file and changed file respectively.
536+
537+If you have the same `desk` mounted to multiple points, a committed change in one mount will also update the others.
538+
539+# Merge Desks
540+
541+See the [Merge Desks](@/docs/arvo/clay/tasks.md#merge-desks) section of the [API Reference](@/docs/arvo/clay/tasks.md) document for general details.
542+
543+## `%merg`
544+
545+Here we'll look at merging `desk`s by sending Clay a `%merg` `task` and receiving a `%mere` `gift` in response.
546+
547+First, using the `send-task-take-gift.hoon` thread, let's try creating a new `desk`:
548+
549+```
550+> -send-task-take-gift [%merg %foo our %home da+now %init]
551+[%mere p=[%.y p={}]]
552+```
553+
554+Now if we scry for our `desk`s we'll see `%foo` is there:
555+
556+```
557+> .^((set desk) %cd /===)
558+{%home %foo %kids}
559+```
560+
561+Next, we'll create a merge conflict and try a couple of things. Mount `%foo` with `|mount /=foo=`, then add a `foo.txt` to both `desk`s but with different text in each and `|commit` them.
562+
563+Now we'll try merging `%home` into `%foo` with a `%mate` strategy:
564+
565+```
566+> -send-task-take-gift [%merg %foo our %home da+now %mate]
567+[ /foo
568+ [ %clay
569+ [ %mere
570+ p
571+ [ %.n
572+ p
573+ [ p=%mate-conflict
574+ q=~[[%rose p=[p="/" q="/" r=""] q=[i=[%leaf p="foo"] t=[i=[%leaf p="txt"] t=~]]]]
575+ ]
576+ ]
577+ ]
578+ ]
579+]
580+```
581+
582+As you can see, the merge has failed. Let's try again with a `%meld` strategy:
583+
584+```
585+> -send-task-take-gift [%merg %foo our %home da+now %meld]
586+[/foo [%clay [%mere p=[%.y p={/foo/txt}]]]]
587+```
588+
589+Now the merge has succeeded and the `%mere` notes the file with a merge conflict. If we try with a `%only-that` strategy:
590+
591+```
592+> -send-task-take-gift [%merg %foo our %home da+now %only-that]
593+[/foo [%clay [%mere p=[%.y p={}]]]]
594+: /~zod/foo/6/foo/txt
595+```
596+
597+...you can see it's overwritten the `foo/txt` in the `%foo` `desk` and the `%mere` now has an empty `set`, indicating no merge conflicts.
598+
599+Next, let's look at subscribing for future changes. Since the `case` is specified explicitly in the `%merge` `task`, we can set it in the future:
600+
601+```
602+> -send-task-take-gift [%merg %foo our %home da+(add ~m2 now) %only-that]
603+```
604+
605+Now change the text in the `foo.txt` in the `%home` `desk`, hit backspace to detach the thread and `|commit %home`. After the two minutes pass you should see:
606+
607+```
608+[/foo [%clay [%mere p=[%.y p={}]]]]
609+: /~zod/foo/7/foo/txt
610+```
611+
612+You can also specify it by revision number or label.
613+
614+# Permissions
615+
616+See the [Permissions](@/docs/arvo/clay/tasks.md#permissions) section of the [API Reference](@/docs/arvo/clay/tasks.md) document for general details.
617+
618+## `%perm`
619+
620+Here we'll look at setting permissions by sending Clay a `%perm` `task`.
621+
622+First, let's allow `~nes` to read `/gen/hood/hi/hoon`:
623+
624+```
625+> |pass [%c [%perm %home /gen/hood/hi/hoon %r ~ %white (sy [%.y ~nes]~)]]
626+```
627+
628+...and we'll do a `%p` scry to see that the permission was set:
629+
630+```
631+> .^([r=dict:clay w=dict:clay] %cp /===/gen/hood/hi/hoon)
632+[r=[src=/gen/hood/hi/hoon rul=[mod=%white who=[p={~nes} q={}]]] w=[src=/ rul=[mod=%white who=[p={} q={}]]]]
633+```
634+
635+You can see that `~nes` is now in the read whitelist. Next, let's try a write permission:
636+
637+```
638+> |pass [%c [%perm %home /ted %w ~ %white (sy [%.y ~nes]~)]]
639+```
640+
641+You can see `~nes` can now write to `/ted`:
642+
643+```
644+> .^([r=dict:clay w=dict:clay] %cp /===/ted)
645+[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ted rul=[mod=%white who=[p={~nes} q={}]]]]
646+```
647+
648+Since we've set it for the whole `/ted` directory, if we check a file inside it we'll see it also has this permission:
649+
650+```
651+> .^([r=dict:clay w=dict:clay] %cp /===/ted/aqua/ames/hoon)
652+[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ted rul=[mod=%white who=[p={~nes} q={}]]]]
653+```
654+
655+...and you'll notice that `src` tells us it's inherited the rule from `/ted`.
656+
657+Now let's try setting both read and write permissions:
658+
659+```
660+> |pass [%c [%perm %home /gen/help/hoon %rw `[%black (sy [%.y ~nes]~)] `[%white (sy [%.y ~nes]~)]]]
661+```
662+
663+```
664+ .^([r=dict:clay w=dict:clay] %cp /===/gen/help/hoon)
665+[r=[src=/gen/help/hoon rul=[mod=%black who=[p={~nes} q={}]]] w=[src=/gen/help/hoon rul=[mod=%white who=[p={~nes} q={}]]]]
666+```
667+
668+Lastly, let's look at deleting a permission rule we've previously set. To do that, we just send a null `(unit rule)` in the `rite`.
669+
670+For example, to remove a read permission (or write if you specify `%w`):
671+
672+```
673+> |pass [%c [%perm %home /gen/help/hoon %r ~]]
674+```
675+
676+```
677+> .^([r=dict:clay w=dict:clay] %cp /===/gen/help/hoon)
678+[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/gen/help/hoon rul=[mod=%white who=[p={~nes} q={}]]]]
679+```
680+
681+...and to remove both read and write at the same time:
682+
683+```
684+> |pass [%c [%perm %home /gen/help/hoon %rw ~ ~]]
685+```
686+
687+```
688+> .^([r=dict:clay w=dict:clay] %cp /===/gen/help/hoon)
689+[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ rul=[mod=%white who=[p={} q={}]]]]
690+```
691+
692+As you can see it's back to the default inherited from `/`.
693+
694+Here's a breakdown of a `%perm` task:
695+
696+![perm diagram](https://media.urbit.org/docs/arvo/clay/perm-diagram.png)
697+
698+## `%cred`
699+
700+Here we'll look at creating a permission group by sending Clay a `%cred` `task`.
701+
702+Let's create a group called `'foo'` with a few ships:
703+
704+```
705+|pass [%c [%crew 'foo' (sy ~[~zod ~nec ~bud ~wes ~sev])]]
706+```
707+
708+We'll check it with the next kind of `task`: [%crew](#crew).
709+
710+## `%crew`
711+
712+Here we'll look at retrieving permission groups by sending Clay a `%crew` `task` and receiving a `%cruz` `gift` in response.
713+
714+Let's check, using the `send-task-take-gift.hoon` thread, for the permission group created in the [%cred](#cred) example:
715+
716+```
717+> -send-task-take-gift [%crew ~]
718+[%cruz cez={[p=~.foo q={~nec ~bud ~wes ~zod ~sev}]}]
719+```
720+
721+## `%crow`
722+
723+Here we'll look at retrieving a list of all files and directories in all `desk`s which have permissions set for a group by sending Clay a `%crow` `task` and receiving a `%croz` `gift` in response.
724+
725+First we'll set a couple of permissions for the `foo` group we created in the [%cred](#cred) section:
726+
727+```
728+> |pass [%c [%perm %home /gen/hood/hi/hoon %w ~ %white (sy [%.n 'foo']~)]]
729+> |pass [%c [%perm %home /ted %w ~ %white (sy [%.n 'foo']~)]]
730+```
731+
732+Notice we use a `%.n` in the `whom` to indicate a group rather than the `%.y` of a ship.
733+
734+Now we'll use the `send-task-take-gift.hoon` thread to try `%crow`:
735+
736+```
737+> -send-task-take-gift [%crow 'foo']
738+[ %croz
739+ rus
740+ { [ p=%home
741+ q
742+ [ r={}
743+ w
744+ { [p=/gen/hood/hi/hoon q=[mod=%white who={[%.n p=~.foo]}]]
745+ [p=/ted q=[mod=%white who={[%.n p=~.foo]}]]
746+ }
747+ ]
748+ ]
749+ }
750+]
751+```
752+
753+# Foreign Ships
754+
755+See the [Foreign Ships](@/docs/arvo/clay/tasks.md#foreign-ships) section of the [API Reference](@/docs/arvo/clay/tasks.md) document for general details.
756+
757+## `%warp` - Remote
758+
759+Here we'll look at reading files on a foreign ship by sending Clay a `%warp` `task` with a foreign ship in the `wer` field and receiving a `%writ` `gift` in response.
760+
761+We'll use a fake ~nes as the the foreign ship and a fake ~zod as the local ship.
762+
763+First we'll set permissions on the foreign ship. Create a file called `foo.txt` in the `%home` of ~nes, then send a `%perm` request to allow ~zod to read and write the file:
764+
765+```
766+> |pass [%c [%perm %home /foo/txt %rw `[%white (sy [%.y ~zod]~)] `[%white (sy [%.y ~zod]~)]]]
767+```
768+
769+If we scry the file for its permissions with a `%p` `care`, we'll see ~zod is now whitelisted:
770+
771+```
772+> .^([r=dict:clay w=dict:clay] %cp /===/foo/txt)
773+[r=[src=/foo/txt rul=[mod=%white who=[p={~zod} q={}]]] w=[src=/foo/txt rul=[mod=%white who=[p={~zod} q={}]]]]
774+```
775+
776+Back on ~zod: Using the `send-task-take-gift.hoon` thread, send a `%x` read request for `/foo/txt` on ~nes like:
777+
778+```
779+> -send-task-take-gift [%warp ~nes %home ~ %sing %x da+now /foo/txt]
780+[ %writ
781+ p
782+ [ ~
783+ [ p=[p=%x q=[%da p=~2021.5.3..08.24.22..9ce7] r=%home]
784+ q=/foo/txt
785+ r=[p=%txt q=[#t/txt=*'' q=[7.303.014 0]]]
786+ ]
787+ ]
788+]
789+```
790+
791+As you can see, we've received a `%writ` containing the requested data just as we would with a local request. Let's try a `%u`:
792+
793+```
794+> -send-task-take-gift [%warp ~nes %home ~ %sing %u da+now /foo/txt]
795+[ %writ
796+ p
797+ [ ~
798+ [ p=[p=%u q=[%da p=~2021.5.3..08.26.32..88cf] r=%home]
799+ q=/foo/txt
800+ r=[p=%flag q=[#t/?(%.y %.n) q=0]]
801+ ]
802+ ]
803+]
804+```
805+
806+If we send a `%d` request however, it will crash:
807+
808+```
809+> -send-task-take-gift [%warp ~nes %home ~ %sing %d da+now /foo/txt]
810+call: failed
811+/sys/vane/clay/hoon:<[4.085 3].[4.314 5]>
812+...
813+/sys/vane/clay/hoon:<[1.365 7].[1.365 51]>
814+[ %clay-bad-foreign-request-care
815+ [%sing mood=[care=%d case=[%da p=~2021.5.3..20.04.57..1092] path=/foo/txt]]
816+]
817+/sys/vane/clay/hoon:<[1.365 48].[1.365 50]>
818+```
819+
820+## `%merg` - Remote
821+
822+To merge a foreign `desk` into a local one, you just send Clay a `%merg` `task` (as you would for a local merge) and specify the foreign ship in the `her` field. For an example, see the [%merg](#merg) section.
823+
824+The foreign ship will respond only if correct permissions have been set. See the [%perm](#perm) section for an example.
arvo/clay/foreign.mddeleted−412
@@ -1,412 +0,0 @@
1−+++
2−title = "Foreign Requests"
3−weight = 7
4−template = "doc.html"
5−+++
6−
7−Parts of this document may be out of date as of March 2021.
8−
9−Foreign reads and subscriptions are handled in much the same way as
10−local ones. The interface is the same -- a vane or app sends a `%warp`
11−kiss with the request. The difference is simply that the `sock` refers
12−to the foreign ship.
13−
14−Thus, we start in the same place -- in `++call`, handling `%warp`.
15−However, since the two side of the `sock` are different, we follow a
16−different path.
17−
18−```hoon
19− =+ wex=(do now p.q.hic p.q.q.hic ruf)
20− =+ ^= woo
21− ?~ q.q.q.hic
22− abet:(ease:wex hen)
23− abet:(eave:wex hen u.q.q.q.hic)
24− [-.woo (posh q.p.q.hic p.q.q.hic +.woo ruf)]
25−```
26−
27−If we compare this to how the local case was handled, we see that it's
28−not all that different. We use `++do` rather than `++un` and `++de` to
29−set up the core for the foreign ship. This gives us a `++de` core, so we
30−either cancel or begin the request by calling `++ease` or `++eave`,
31−exactly as in the local case. In either case, we call `++abet:de` to
32−resolve our various types of output into actual moves, as described in
33−the local case. Finally, we call `++posh` to update our raft, putting
34−the modified rung into the raft.
35−
36−We'll first trace through `++do`.
37−
38−```hoon
39− ++ do
40− |= [now=@da [who=ship him=ship] syd=@tas ruf=raft]
41− =+ ^= rug ^- rung
42− =+ rug=(~(get by hoy.ruf) him)
43− ?^(rug u.rug *rung)
44− =+ ^= red ^- rede
45− =+ yit=(~(get by rus.rug) syd)
46− ?^(yit u.yit `rede`[~2000.1.1 ~ [~ *rind] *dome])
47− ((de now ~ ~) [who him] syd red ran.ruf)
48−```
49−
50−If we already have a rung for this foreign ship, then we use that.
51−Otherwise, we create a new blank one. If we already have a rede in this
52−rung, then we use that, otherwise we create a blank one. An important
53−point to note here is that we let `ref` in the rede be `[~ *rind]`.
54−Recall, for domestic desks `ref` is null. We use this to distinguish
55−between foreign and domestic desks in `++de`.
56−
57−With this information, we create a `++de` core as usual.
58−
59−Although we've already covered `++ease` and `++eave`, we'll go through
60−them quickly again, highlighting the case of foreign request.
61−
62−```hoon
63− ++ ease :: release request
64− |= hen=duct
65− ^+ +>
66− ?~ ref +>
67− =+ rov=(~(got by qyx) hen)
68− =. qyx (~(del by qyx) hen)
69− (mabe rov (cury best hen))
70− =. qyx (~(del by qyx) hen)
71− |- ^+ +>+.$
72− =+ nux=(~(get by fod.u.ref) hen)
73− ?~ nux +>+.$
74− %= +>+.$
75− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
76− fod.u.ref (~(del by fod.u.ref) hen)
77− bom.u.ref (~(del by bom.u.ref) u.nux)
78− ==
79−```
80−
81−Here, we still remove the duct from our cult (we maintain a cult even
82−for foreign desks), but we also need to tell the foreign desk to cancel
83−our subscription. We do this by sending a request (by appending to
84−`say`, which gets resolved in `++abet:de` to a `%want` kiss to ames) to
85−the foreign ship to cancel the subscription. Since we don't anymore
86−expect a response on this duct, we remove it from `fod` and `bom`, which
87−are the maps between ducts, raves, and request sequence numbers.
88−Basically, we remove every trace of the subscription from our request
89−manager.
90−
91−In the case of `++eave`, where we're creating a new request, everything
92−is exactly identical to the case of the local request except `++duce`.
93−We said that `++duce` simply puts the request into our cult. This is
94−true for a domestic request, but distinctly untrue for foreign requests.
95−
96−```hoon
97− ++ duce :: produce request
98− |= [hen=duct rov=rove]
99− ^+ +>
100− =. qyx (~(put by qyx) hen rov)
101− ?~ ref +>.$
102− |- ^+ +>+.$ :: XX why?
103− =+ rav=(reve rov)
104− =+ ^= vaw ^- rave
105− ?. ?=([%& %v *] rav) rav
106− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
107− =+ inx=nix.u.ref
108− %= +>+.$
109− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
110− nix.u.ref +(nix.u.ref)
111− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
112− fod.u.ref (~(put by fod.u.ref) hen inx)
113− ==
114−```
115−
116−If we have a request manager (i.e. this is a foreign desk), then we do
117−the approximate inverse of `++ease`. We create a rave out of the given
118−request and send it off to the foreign desk by putting it in `say`. Note
119−that the rave is created to request the information starting at the next
120−revision number. Since this is a new request, we put it into `fod` and
121−`bom` to associate the request with its duct and its sequence number.
122−Since we're using another sequence number, we must increment `nix`,
123−which represents the next available sequence number.
124−
125−And that's really it for this side of the request. Requesting foreign
126−information isn't that hard. Let's see what it looks like on the other
127−side. When we get a request from another ship for information on our
128−ship, that comes to us in the form of a `%wart` from ames.
129−
130−We handle a `%wart` in `++call`, right next to where we handle the
131−`%warp` case.
132−
133−```hoon
134− %wart
135− ?> ?=(%re q.q.hic)
136− =+ ryf=((hard riff) s.q.hic)
137− :_ ..^$
138− :~ :- hen
139− :^ %pass [(scot %p p.p.q.hic) (scot %p q.p.q.hic) r.q.hic]
140− %c
141− [%warp [p.p.q.hic p.p.q.hic] ryf]
142− ==
143−```
144−
145−Every request we receive should be of type `riff`, so we coerce it into
146−that type. We just convert this into a new `%warp` kiss that we pass to
147−ourself. This gets handled like normal, as a local request. When the
148−request produces a value, it does so like normal as a `%writ`, which is
149−returned to `++take` along the path we just sent it on.
150−
151−```hoon
152− %writ
153− ?> ?=([@ @ *] tea)
154− =+ our=(need (slaw %p i.tea))
155− =+ him=(need (slaw %p i.t.tea))
156− :_ ..^$
157− :~ :- hen
158− [%pass ~ %a [%want [our him] [%r %re %c t.t.tea] p.+.q.hin]]
159− ==
160−```
161−
162−Since we encoded the ship we need to respond to in the path, we can just
163−pass our `%want` back to ames, so that we tell the requesting ship about
164−the new data.
165−
166−This comes back to the original ship as a `%waft` from ames, which comes
167−into `++take`, right next to where we handled `%writ`.
168−
169−```hoon
170− %waft
171− ?> ?=([@ @ ~] tea)
172− =+ syd=(need (slaw %tas i.tea))
173− =+ inx=(need (slaw %ud i.t.tea))
174− =+ ^= zat
175− =< wake
176− (knit:(do now p.+.q.hin syd ruf) [inx ((hard riot) q.+.q.hin)])
177− =^ mos ruf
178− =+ zot=abet.zat
179− [-.zot (posh q.p.+.q.hin syd +.zot ruf)]
180− [mos ..^$(ran.ruf ran.zat)] :: merge in new obj
181−```
182−
183−This gets the desk and sequence number from the path the request was
184−sent over. This determines exactly which request is being responded to.
185−We call `++knit:de` to apply the changes to our local desk, and we call
186−`++wake` to update our subscribers. Then we call `++abet:de` and
187−`++posh` as normal (like in `++eave`).
188−
189−We'll examine `++knit` and `++wake`, in that order.
190−
191−```hoon
192− ++ knit :: external change
193− |= [inx=@ud rot=riot]
194− ^+ +>
195− ?> ?=(^ ref)
196− |- ^+ +>+.$
197− =+ ruv=(~(get by bom.u.ref) inx)
198− ?~ ruv +>+.$
199− => ?. |(?=(~ rot) ?=(& -.q.u.ruv)) .
200− %_ .
201− bom.u.ref (~(del by bom.u.ref) inx)
202− fod.u.ref (~(del by fod.u.ref) p.u.ruv)
203− ==
204− ?~ rot
205− =+ rav=`rave`q.u.ruv
206− %= +>+.$
207− lim
208− ?.(&(?=(| -.rav) ?=(%da -.q.p.rav)) lim `@da`p.q.p.rav)
209− ::
210− haw.u.ref
211− ?. ?=(& -.rav) haw.u.ref
212− (~(put by haw.u.ref) p.rav ~)
213− ==
214− ?< ?=(%v p.p.u.rot)
215− =. haw.u.ref
216− (~(put by haw.u.ref) [p.p.u.rot q.p.u.rot q.u.rot] ~ r.u.rot)
217− ?. ?=(%w p.p.u.rot) +>+.$
218− |- ^+ +>+.^$
219− =+ nez=[%w [%ud let.dom] ~]
220− =+ nex=(~(get by haw.u.ref) nez)
221− ?~ nex +>+.^$
222− ?~ u.nex +>+.^$ :: should never happen
223− =. +>+.^$ =+ roo=(edis ((hard nako) u.u.nex))
224− ?>(?=(^ ref.roo) roo)
225− %= $
226− haw.u.ref (~(del by haw.u.ref) nez)
227− ==
228−```
229−
230−This is kind of a long [gate](/docs/glossary/gate/), but don't worry, it's not bad at all.
231−
232−First, we assert that we're not a domestic desk. That wouldn't make any
233−sense at all.
234−
235−Since we have the sequence number of the request, we can get the duct
236−and rave from `bom` in our request manager. If we didn't actually
237−request this data (or the request was canceled before we got it), then
238−we do nothing.
239−
240−Else, we remove the request from `bom` and `fod` unless this was a
241−subscription request and we didn't receive a null riot (which would
242−indicate the last message on the subscription).
243−
244−Now, if we received a null riot, then if this was a subscription request
245−by date, then we update `lim` in our request manager (representing the
246−latest time at which we have complete information for this desk) to the
247−date that was requested. If this was a single read request, then we put
248−the result in our simple cache `haw` to make future requests faster.
249−Then we're done.
250−
251−If we received actual data, then we put it into our cache `haw`. Unless
252−it's a `%w` request, we're done.
253−
254−If it is a `%w` request, then we try to get the `%w` at our current head
255−from the cache. In general, that should be the thing we just put in a
256−moment ago, but that is not guaranteed. The most common case where this
257−is different is when we receive desk updates out of order. At any rate,
258−since we now have new information, we need to apply it to our local copy
259−of the desk. We do so in `++edis`, and then we remove the stuff we just
260−applied from the cache, since it's not really a true "single read", like
261−what should really be in the cache.
262−
263−```hoon
264− ++ edis :: apply subscription
265− |= nak=nako
266− ^+ +>
267− %= +>
268− hit.dom (~(uni by hit.dom) gar.nak)
269− let.dom let.nak
270− lat.ran %+ roll (~(tap in bar.nak) ~)
271− =< .(yeb lat.ran)
272− |= [sar=blob yeb=(map lobe blob)]
273− =+ zax=(blob-to-lobe sar)
274− %+ ~(put by yeb) zax sar
275− hut.ran %+ roll (~(tap in lar.nak) ~)
276− =< .(yeb hut.ran)
277− |= [sar=yaki yeb=(map tako yaki)]
278− %+ ~(put by yeb) r.sar sar
279− ==
280−```
281−
282−This shows, of course, exactly why nako is defined the way it is. To
283−become completely up to date with the foreign desk, we need to merge
284−`hit` with the foreign one so that we have all the revision numbers. We
285−update `let` so that we know which revision is the head.
286−
287−We merge the new blobs in `lat`, keying them by their hash, which we get
288−from a call to `++blob-to-lobe`. Recall that the hash is stored in the
289−actual blob itself. We do the same thing to the new yakis, putting them
290−in `hut`, keyed by their hash.
291−
292−Now, our local dome should be exactly the same as the foreign one.
293−
294−This concludes our discussion of `++knit`. Now the changes have been
295−applied to our local copy of the desk, and we just need to update our
296−subscribers. We do so in `++wake:de`.
297−
298−```hoon
299− ++ wake :: update subscribers
300− ^+ .
301− =+ xiq=(~(tap by qyx) ~)
302− =| xaq=(list ,[p=duct q=rove])
303− |- ^+ ..wake
304− ?~ xiq
305− ..wake(qyx (~(gas by *cult) xaq))
306− ?- -.q.i.xiq
307− &
308− =+ cas=?~(ref ~ (~(get by haw.u.ref) `mood`p.q.i.xiq))
309− ?^ cas
310− %= $
311− xiq t.xiq
312− ..wake ?~ u.cas (blub p.i.xiq)
313− (blab p.i.xiq p.q.i.xiq u.u.cas)
314− ==
315− =+ nao=(~(case-to-aeon ze lim dom ran) q.p.q.i.xiq)
316− ?~ nao $(xiq t.xiq, xaq [i.xiq xaq])
317− $(xiq t.xiq, ..wake (balk p.i.xiq u.nao p.q.i.xiq))
318− ::
319− |
320− =+ mot=`moot`p.q.i.xiq
321− =+ nab=(~(case-to-aeon ze lim dom ran) p.mot)
322− ?~ nab
323− $(xiq t.xiq, xaq [i.xiq xaq])
324− =+ huy=(~(case-to-aeon ze lim dom ran) q.mot)
325− ?~ huy
326− =+ ptr=[%ud +(let.dom)]
327− %= $
328− xiq t.xiq
329− xaq [[p.i.xiq [%| ptr q.mot r.mot s.mot]] xaq]
330− ..wake =+ ^= ear
331− (~(lobes-at-path ze lim dom ran) let.dom r.p.q.i.xiq)
332− ?: =(s.p.q.i.xiq ear) ..wake
333− =+ fud=(~(make-nako ze lim dom ran) u.nab let.dom)
334− (bleb p.i.xiq let.dom fud)
335− ==
336− %= $
337− xiq t.xiq
338− ..wake =- (blub:- p.i.xiq)
339− =+ ^= ear
340− (~(lobes-at-path ze lim dom ran) u.huy r.p.q.i.xiq)
341− ?: =(s.p.q.i.xiq ear) (blub p.i.xiq)
342− =+ fud=(~(make-nako ze lim dom ran) u.nab u.huy)
343− (bleb p.i.xiq +(u.nab) fud)
344− ==
345− ==
346− --
347−```
348−
349−This is even longer than `++knit`, but it's pretty similar to `++eave`.
350−We loop through each of our subscribers `xiq`, processing each in turn.
351−When we're done, we just put the remaining subscribers back in our
352−subscriber list.
353−
354−If the subscriber is a single read, then, if this is a foreign desk
355−(note that `++wake` is called from other arms, and not only on foreign
356−desks). Obviously, if we find an identical request there, then we can
357−produce the result immediately. Referential transparency for the win. We
358−produce the result with a call to `++blab`. If this is a foreign desk
359−but the result is not in the cache, then we produce `++blub` (canceled
360−subscription with no data) for reasons entirely opaque to me. Seriously,
361−it seems like we should wait until we get an actual response to the
362−request. If someone figures out why this is, let me know. At any rate,
363−it seems to work.
364−
365−If this is a domestic desk, then we check to see if the case exists yet.
366−If it doesn't, then we simply move on to the next subscriber, consing
367−this one onto `xaq` so that we can check again the next time around. If
368−it does exist, then we call `++balk` to fulfill the request and produce
369−it.
370−
371−`++balk` is very simple, so we'll describe it here before we get to the
372−subscription case.
373−
374−```hoon
375− ++ balk :: read and send
376− |= [hen=duct oan=@ud mun=mood]
377− ^+ +>
378− =+ vid=(~(read-at-aeon ze lim dom ran) oan mun)
379− ?~ vid (blub hen) (blab hen mun u.vid)
380−```
381−
382−We call `++read-at-aeon` on the given request and aeon. If you recall,
383−this processes a `mood` at a particular aeon and produces the result, if
384−there is one. If there is data at the requested location, then we
385−produce it with `++blab`. Else, we call `++blub` to notify the
386−subscriber that no data can ever come over this subscriptioin since it
387−is now impossible for there to ever be data for the given request.
388−Because referential transparency.
389−
390−At any rate, back to `++wake`. If the given rave is a subscription
391−request, then we proceed similarly to how we do in `++eave`. We first
392−try to get the aeon referred to by the starting case. If it doesn't
393−exist yet, then we can't do anything interesting with this subscription,
394−so we move on to the next one.
395−
396−Otherwise, we try to get the aeon referred to by the ending case. If it
397−doesn't exist yet, then we produce all the information we can. We call
398−`++lobes-at-path` at the given aeon and path to see if the requested
399−path has actually changed. If it hasn't, then we don't produce anything;
400−else, we produce the correct nako by calling `++bleb` on the result of
401−`++make-nako`, as in `++eave`. At any rate, we move on to the next
402−subscription, putting back into our cult the current subscription with a
403−new start case of the next aeon after the present.
404−
405−If the aeon referred to by the ending case does exist, then we drop this
406−subscriber from our cult and satisfy its request immediately. This is
407−the same as before -- we check to see if the data at the path has
408−actually changed, producing it if it has; else, we call `++blub` since
409−no more data can be produced over this subscription.
410−
411−This concludes our discussion of foreign requests.
412−
arvo/clay/local-reads.mddeleted−783
@@ -1,783 +0,0 @@
1−+++
2−title = "Local Reads and Writes"
3−weight = 5
4−template = "doc.html"
5−+++
6−
7−Parts of this document may be out of date as of March 2021.
8−
9−There are two real types of interaction with a filesystem: you can read,
10−and you can write. We'll describe each process, detailing both the flow
11−of control followed by the kernel and the algorithms involved. The
12−simpler case is that of the read, so we'll begin with that.
13−
14−When a vane or an application wishes to read a file from the filesystem,
15−it sends a `%warp` kiss, as described above. Of course, you may request
16−a file on another ship and, being a global filesystem, clay will happily
17−produce it for you. That code pathway will be described in another
18−section; here, we will restrict ourselves to examining the case of a
19−read from a ship on our own pier.
20−
21−The kiss can request either a single version of a file node or a range
22−of versions of a desk. Here, we'll deal only with a request for a single
23−version.
24−
25−As in all vanes, a kiss enters clay via a call to `++call`. Scanning
26−through the arm, we quickly see where `%warp` is handled.
27−
28−```hoon
29− ?: =(p.p.q.hic q.p.q.hic)
30− =+ une=(un p.p.q.hic now ruf)
31− =+ wex=(di:une p.q.q.hic)
32− =+ ^= wao
33− ?~ q.q.q.hic
34− (ease:wex hen)
35− (eave:wex hen u.q.q.q.hic)
36− =+ ^= woo
37− abet:wao
38− [-.woo abet:(pish:une p.q.q.hic +.woo ran.wao)]
39−```
40−
41−We're following the familar patern of producing a list of moves and an
42−updated state. In this case, the state is `++raft`.
43−
44−We first check to see if the sending and receiving ships are the same.
45−If they're not, then this is a request for data on another ship. We
46−describe that process later. Here, we discuss only the case of a local
47−read.
48−
49−At a high level, the call to `++un` sets up the core for the domestic
50−ship that contains the files we're looking for. The call to `++di` sets
51−up the core for the particular desk we're referring to.
52−
53−After this, we perform the actual request. If there is no rave in the
54−riff, then that means we are cancelling a request, so we call
55−`++ease:de`. Otherwise, we start a subscription with `++eave:de`. We
56−call `++abet:de` to resolve our various types of output into actual
57−moves. We produce the moves we found above and the `++un` core resolved
58−with `++pish:un` (putting the modified desk in the room) and `++abet:un`
59−(putting the modified room in the raft).
60−
61−Much of this is fairly straightforward, so we'll only describe `++ease`,
62−`++eave`, and `++abet:de`. Feel free to look up the code to the other
63−steps -- it should be easy to follow.
64−
65−Although it's called last, it's usually worth examining `++abet` first,
66−since it defines in what ways we can cause side effects. Let's do that,
67−and also a few of the lines at the beginning of `++de`.
68−
69−```hoon
70− =| yel=(list ,[p=duct q=gift])
71− =| byn=(list ,[p=duct q=riot])
72− =| vag=(list ,[p=duct q=gift])
73− =| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]])
74− =| tag=(list ,[p=duct q=path c=note])
75− |%
76− ++ abet
77− ^- [(list move) rede]
78− :_ red
79− ;: weld
80− %+ turn (flop yel)
81− |=([a=duct b=gift] [hun %give b])
82− ::
83− %+ turn (flop byn)
84− |=([a=duct b=riot] [a %give [%writ b]])
85− ::
86− %+ turn (flop vag)
87− |=([a=duct b=gift] [a %give b])
88− ::
89− %+ turn (flop say)
90− |= [a=duct b=path c=ship d=[p=@ud q=riff]]
91− :- a
92− [%pass b %a %want [who c] [%q %re p.q.d (scot %ud p.d) ~] q.d]
93− ::
94− %+ turn (flop tag)
95− |=([a=duct b=path c=note] [a %pass b c])
96− ==
97−```
98−
99−This is very simple code. We see there are exactly five different kinds
100−of side effects we can generate.
101−
102−In `yel` we put gifts that we wish to be sent along the `hun:room` duct
103−to dill. See the documentation for `++room` above. This is how we
104−display messages to the terminal.
105−
106−In `byn` we put riots that we wish returned to subscribers. Recall that
107−a riot is a response to a subscription. These are returned to our
108−subscribers in the form of a `%writ` gift.
109−
110−In `vag` we put gifts along with the ducts on which to send them. This
111−allows us to produce arbitrary gifts, but in practice this is only used
112−to produce `%ergo` gifts.
113−
114−In `say` we put messages we wish to pass to ames. These messages are
115−used to request information from clay on other piers. We must provide
116−not only the duct and the request (the riff), but also the return path,
117−the other ship to talk to, and the sequence number of the request.
118−
119−In `tag` we put arbitrary notes we wish to pass to other vanes. For now,
120−the only notes we pass here are `%wait` and `%rest` to the timer vane.
121−
122−Now that we know what kinds of side effects we may have, we can jump
123−into the handling of requests.
124−
125−```hoon
126− ++ ease :: release request
127− |= hen=duct
128− ^+ +>
129− ?~ ref +>
130− =+ rov=(~(got by qyx) hen)
131− =. qyx (~(del by qyx) hen)
132− (mabe rov (cury best hen))
133− =. qyx (~(del by qyx) hen)
134− |- ^+ +>+.$
135− =+ nux=(~(get by fod.u.ref) hen)
136− ?~ nux +>+.$
137− %= +>+.$
138− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
139− fod.u.ref (~(del by fod.u.ref) hen)
140− bom.u.ref (~(del by bom.u.ref) u.nux)
141− ==
142−```
143−
144−This is called when we're cancelling a subscription. For domestic desks,
145−`ref` is null, so we're going to cancel any timer we might have created.
146−We first delete the duct from our map of requests, and then we call
147−`++mabe` with `++best` to send a `%rest` kiss to the timer vane if we
148−have started a timer. We'll describe `++best` and `++mabe` momentarily.
149−
150−Although we said we're not going to talk about foreign requests yet,
151−it's easy to see that for foreign desks, we cancel any outstanding
152−requests for this duct and send a message over ames to the other ship
153−telling them to cancel the subscription.
154−
155−```hoon
156− ++ best
157− |= [hen=duct tym=@da]
158− %_(+> tag :_(tag [hen /tyme %t %rest tym]))
159−```
160−
161−This simply pushes a `%rest` note onto `tag`, from where it will be
162−passed back to arvo to be handled. This cancels the timer at the given
163−duct (with the given time).
164−
165−```hoon
166− ++ mabe :: maybe fire function
167− |* [rov=rove fun=$+(@da _+>.^$)]
168− ^+ +>.$
169− %- fall :_ +>.$
170− %- bind :_ fun
171− ^- (unit ,@da)
172− ?- -.rov
173− %&
174− ?. ?=(%da -.q.p.rov) ~
175− `p.q.p.rov
176− %|
177− =* mot p.rov
178− %+ hunt
179− ?. ?=(%da -.p.mot) ~
180− ?.((lth now p.p.mot) ~ [~ p.p.mot])
181− ?. ?=(%da -.q.mot) ~
182− ?.((lth now p.q.mot) [~ now] [~ p.q.mot])
183− ==
184−```
185−
186−This decides whether the given request can only be satsified in the
187−future. In that case, we call the given function with the time in the
188−future when we expect to have an update to give to this request. This is
189−called with `++best` to cancel timers and with `++bait` to start them.
190−
191−For single requests, we have a time if the request is for a particular
192−time (which is assumed to be in the future). For ranges of requests, we
193−check both the start and end cases to see if they are time cases. If so,
194−we choose the earlier time.
195−
196−If any of those give us a time, then we call the given funciton with the
197−smallest time.
198−
199−The more interesting case is, of course, when we're not cancelling a
200−subscription but starting one.
201−
202−```hoon
203− ++ eave :: subscribe
204− |= [hen=duct rav=rave]
205− ^+ +>
206− ?- -.rav
207− &
208− ?: &(=(p.p.rav %u) !=(p.q.p.rav now))
209− ~& [%clay-fail p.q.p.rav %now now]
210− !!
211− =+ ver=(aver p.rav)
212− ?~ ver
213− (duce hen rav)
214− ?~ u.ver
215− (blub hen)
216− (blab hen p.rav u.u.ver)
217−```
218−
219−There are two types of subscriptions -- either we're requesting a single
220−file or we're requesting a range of versions of a desk. We'll dicuss the
221−simpler case first.
222−
223−First, we check that we're not requesting the `rang` from any time other
224−than the present. Since we don't store that information for any other
225−time, we can't produce it in a referentially transparent manner for any
226−time other than the present.
227−
228−Then, we try to read the requested `mood:clay` `p.rav`. If we can't access
229−the request data right now, we call `++duce` to put the request in our
230−queue to be satisfied when the information becomes available.
231−
232−This case occurs when we make a request for a case whose (1) date is
233−after the current date, (2) number is after the current number, or (3)
234−label is not yet used.
235−
236−```hoon
237− ++ duce :: produce request
238− |= [hen=duct rov=rove]
239− ^+ +>
240− =. qyx (~(put by qyx) hen rov)
241− ?~ ref
242− (mabe rov (cury bait hen))
243− |- ^+ +>+.$ :: XX why?
244− =+ rav=(reve rov)
245− =+ ^= vaw ^- rave
246− ?. ?=([%& %v *] rav) rav
247− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
248− =+ inx=nix.u.ref
249− %= +>+.$
250− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
251− nix.u.ref +(nix.u.ref)
252− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
253− fod.u.ref (~(put by fod.u.ref) hen inx)
254− ==
255−```
256−
257−The code for `++duce` is nearly the exact inverse of `++ease`, which in
258−the case of a domestic desk is very simple -- we simply put the duct and
259−rave into `qyx` and possibly start a timer with `++mabe` and `++bait`.
260−Recall that `ref` is null for domestic desks and that `++mabe` fires the
261−given function with the time we need to be woken up at, if we need to be
262−woken up at a particular time.
263−
264−```hoon
265− ++ bait
266− |= [hen=duct tym=@da]
267− %_(+> tag :_(tag [hen /tyme %t %wait tym]))
268−```
269−
270−This sets an alarm by sending a `%wait` card with the given time to the
271−timer vane.
272−
273−Back in `++eave`, if `++aver` returned `[~ ~]`, then we cancel the
274−subscription. This occurs when we make (1) a `%x` request for a file
275−that does not exist, (2) a `%w` request with a case that is not a
276−number, or (3) a `%w` request with a nonempty path. The `++blub` is
277−exactly what you would expect it to be.
278−
279−```hoon
280− ++ blub :: ship stop
281− |= hen=duct
282− %_(+> byn [[hen ~] byn])
283−```
284−
285−We notify the duct that we're cancelling their subscription since it
286−isn't satisfiable.
287−
288−Otherwise, we have received the desired information, so we send it on to
289−the subscriber with `++blab`.
290−
291−```hoon
292− ++ blab :: ship result
293− |= [hen=duct mun=mood dat=*]
294− ^+ +>
295− +>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn])
296−```
297−
298−The most interesting arm called in `++eave` is, of course, `++aver`,
299−where we actually try to read the data.
300−
301−```hoon
302− ++ aver :: read
303− |= mun=mood
304− ^- (unit (unit ,*))
305− ?: &(=(p.mun %u) !=(p.q.mun now)) :: prevent bad things
306− ~& [%clay-fail p.q.mun %now now]
307− !!
308− =+ ezy=?~(ref ~ (~(get by haw.u.ref) mun))
309− ?^ ezy ezy
310− =+ nao=(~(case-to-aeon ze lim dom ran) q.mun)
311− ?~(nao ~ [~ (~(read-at-aeon ze lim dom ran) u.nao mun)])
312−```
313−
314−We check immediately that we're not requesting the `rang` for any time
315−other than the present.
316−
317−If this is a foreign desk, then we check our cache for the specific
318−request. If either this is a domestic desk or we don't have the request
319−in our cache, then we have to actually go read the data from our dome.
320−
321−We need to do two things. First, we try to find the number of the commit
322−specified by the given case, and then we try to get the data there.
323−
324−Here, we jump into `arvo/zuse.hoon`, which is where much of the
325−algorithmic code is stored, as opposed to the clay interface, which is
326−stored in `arvo/clay.hoon`. We examine `++case-to-aeon:ze`.
327−
328−```hoon
329− ++ case-to-aeon :: case-to-aeon:ze
330− |= lok=case :: act count through
331− ^- (unit aeon)
332− ?- -.lok
333− %da
334− ?: (gth p.lok lim) ~
335− |- ^- (unit aeon)
336− ?: =(0 let) [~ 0] :: avoid underflow
337− ?: %+ gte p.lok
338− =< t
339− %- tako-to-yaki
340− %- aeon-to-tako
341− let
342− [~ let]
343− $(let (dec let))
344− ::
345− %tas (~(get by lab) p.lok)
346− %ud ?:((gth p.lok let) ~ [~ p.lok])
347− ==
348−```
349−
350−We handle each type of `case:clay` differently. The latter two types are
351−easy.
352−
353−If we're requesting a revision by label, then we simply look up the
354−requested label in `lab` from the given dome. If it exists, that is our
355−aeon; else we produce null, indicating the requested revision does not
356−yet exist.
357−
358−If we're requesting a revision by number, we check if we've yet reached
359−that number. If so, we produce the number; else we produce null.
360−
361−If we're requesting a revision by date, we check first if the date is in
362−the future, returning null if so. Else we start from the most recent
363−revision and scan backwards until we find the first revision committed
364−before that date, and we produce that. If we requested a date before any
365−revisions were committed, we produce `0`.
366−
367−The definitions of `++aeon-to-tako` and `++tako-to-yaki` are trivial.
368−
369−```hoon
370− ++ aeon-to-tako ~(got by hit)
371−
372− ++ tako-to-yaki ~(got by hut) :: grab yaki
373−```
374−
375−We simply look up the aeon or tako in their respective maps (`hit` and
376−`hut`).
377−
378−Assuming we got a valid version number, `++aver` calls
379−`++read-at-aeon:ze`, which reads the requested data at the given
380−revision.
381−
382−```hoon
383− ++ read-at-aeon :: read-at-aeon:ze
384− |= [oan=aeon mun=mood] :: seek and read
385− ^- (unit)
386− ?: &(?=(%w p.mun) !?=(%ud -.q.mun)) :: NB only for speed
387− ?^(r.mun ~ [~ oan])
388− (read:(rewind oan) mun)
389−```
390−
391−If we're requesting the revision number with a case other than by
392−number, then we go ahead and just produce the number we were given.
393−Otherwise, we call `++rewind` to rewind our state to the given revision,
394−and then we call `++read` to get the requested information.
395−
396−```hoon
397− ++ rewind :: rewind:ze
398− |= oan=aeon :: rewind to aeon
399− ^+ +>
400− ?: =(let oan) +>
401− ?: (gth oan let) !! :: don't have version
402− +>(ank (checkout-ankh q:(tako-to-yaki (aeon-to-tako oan))), let oan)
403−```
404−
405−If we're already at the requested version, we do nothing. If we're
406−requesting a version later than our head, we are unable to comply.
407−
408−Otherwise, we get the hash of the commit at the number, and from that we
409−get the commit itself (the yaki), which has the map of path to lobe that
410−represents a version of the filesystem. We call `++checkout-ankh` to
411−checkout the commit, and we replace `ank` in our context with the
412−result.
413−
414−```hoon
415− ++ checkout-ankh :: checkout-ankh:ze
416− |= hat=(map path lobe) :: checkout commit
417− ^- ankh
418− %- cosh
419− %+ roll (~(tap by hat) ~)
420− |= [[pat=path bar=lobe] ank=ankh]
421− ^- ankh
422− %- cosh
423− ?~ pat
424− =+ zar=(lobe-to-noun bar)
425− ank(q [~ (sham zar) zar])
426− =+ nak=(~(get by r.ank) i.pat)
427− %= ank
428− r %+ ~(put by r.ank) i.pat
429− $(pat t.pat, ank (fall nak _ankh))
430− ==
431−```
432−
433−Twice we call `++cosh`, which hashes a commit, updating `p` in an
434−`ankh`. Let's jump into that algorithm before we describe
435−`++checkout-ankh`.
436−
437−```hoon
438− ++ cosh :: locally rehash
439− |= ank=ankh :: NB v/unix.c
440− ank(p rehash:(zu ank))
441−```
442−
443−We simply replace `p` in the hash with the `cash` we get from a call to
444−`++rehash:zu`.
445−
446−```hoon
447− ++ zu !: :: filesystem
448− |= ank=ankh :: filesystem state
449− =| myz=(list ,[p=path q=miso]) :: changes in reverse
450− =| ram=path :: reverse path into
451− |%
452− ++ rehash :: local rehash
453− ^- cash
454− %+ mix ?~(q.ank 0 p.u.q.ank)
455− =+ axe=1
456− |- ^- cash
457− ?~ r.ank _@
458− ;: mix
459− (shaf %dash (mix axe (shaf %dush (mix p.n.r.ank p.q.n.r.ank))))
460− $(r.ank l.r.ank, axe (peg axe 2))
461− $(r.ank r.r.ank, axe (peg axe 3))
462− ==
463−```
464−
465−`++zu` is a core we set up with a particular filesystem node to traverse
466−a checkout of the filesystem and access the actual data inside it. One
467−of the things we can do with it is to create a recursive hash of the
468−node.
469−
470−In `++rehash`, if this node is a file, then we xor the remainder of the
471−hash with the hash of the contents of the file. The remainder of the
472−hash is `0` if we have no children, else we descend into our children.
473−Basically, we do a half SHA-256 of the xor of the axis of this child and
474−the half SHA-256 of the xor of the name of the child and the hash of the
475−child. This is done for each child and all the results are xored
476−together.
477−
478−Now we return to our discussion of `++checkout-ankh`.
479−
480−We fold over every path in this version of the filesystem and create a
481−great ankh out of them. First, we call `++lobe-to-noun` to get the raw
482−data referred to be each lobe.
483−
484−```hoon
485− ++ lobe-to-noun :: grab blob
486− |= p=lobe :: ^- *
487− %- blob-to-noun
488− (lobe-to-blob p)
489−```
490−
491−This converts a lobe into the raw data it refers to by first getting the
492−blob with `++lobe-to-blob` and converting that into data with
493−`++blob-to-noun`.
494−
495−```hoon
496− ++ lobe-to-blob ~(got by lat) :: grab blob
497−```
498−
499−This just grabs the blob that the lobe refers to.
500−
501−```hoon
502− ++ blob-to-noun :: grab blob
503− |= p=blob
504− ?- -.p
505− %delta (lump r.p (lobe-to-noun q.p))
506− %direct q.p
507− %indirect q.p
508− ==
509−```
510−
511−If we have either a direct or an indirect blob, then the data is stored
512−right in the blob. Otherwise, we have to reconstruct it from the diffs.
513−We do this by calling `++lump` on the diff in the blob with the data
514−obtained by recursively calling the parent of this blob.
515−
516−```hoon
517− ++ lump :: apply patch
518− |= [don=udon src=*]
519− ^- *
520− ?+ p.don ~|(%unsupported !!)
521− %a
522− ?+ -.q.don ~|(%unsupported !!)
523− %a q.q.don
524− %c (lurk ((hard (list)) src) p.q.don)
525− %d (lure src p.q.don)
526− ==
527− ::
528− %c
529− =+ dst=(lore ((hard ,@) src))
530− %- roly
531− ?+ -.q.don ~|(%unsupported !!)
532− %a ((hard (list ,@t)) q.q.don)
533− %c (lurk dst p.q.don)
534− ==
535− ==
536−```
537−
538−This is defined in `arvo/hoon.hoon` for historical reasons which are
539−likely no longer applicable. Since the `++umph` structure will likely
540−change we convert clay to be a typed filesystem, we'll only give a
541−high-level description of this process. If we have a `%a` udon, then
542−we're performing a trivial replace, so we produce simply `q.q.don`. If
543−we have a `%c` udon, then we're performing a list merge (as in, for
544−example, lines of text). The merge is performed by `++lurk`.
545−
546−```hoon
547− ++ lurk :: apply list patch
548− |* [hel=(list) rug=(urge)]
549− ^+ hel
550− =+ war=`_hel`~
551− |- ^+ hel
552− ?~ rug (flop war)
553− ?- -.i.rug
554− &
555− %= $
556− rug t.rug
557− hel (slag p.i.rug hel)
558− war (weld (flop (scag p.i.rug hel)) war)
559− ==
560− ::
561− |
562− %= $
563− rug t.rug
564− hel =+ gur=(flop p.i.rug)
565− |- ^+ hel
566− ?~ gur hel
567− ?>(&(?=(^ hel) =(i.gur i.hel)) $(hel t.hel, gur t.gur))
568− war (weld q.i.rug war)
569− ==
570− ==
571−```
572−
573−We accumulate our final result in `war`. If there's nothing more in our
574−list of merge instructions (unces), we just reverse `war` and produce
575−it. Otherwise, we process another unce. If the unce is of type `&`, then
576−we have `p.i.rug` lines of no changes, so we just copy them over from
577−`hel` to `war`. If the unice is of type `|`, then we verify that the
578−source lines (in `hel`) are what we expect them to be (`p.i.rug`),
579−crashing on failure. If they're good, then we append the new lines in
580−`q.i.rug` onto `war`.
581−
582−And that's really it. List merges are pretty easy. Anyway, if you
583−recall, we were discussing `++checkout-ankh`.
584−
585−```hoon
586− ++ checkout-ankh :: checkout-ankh:ze
587− |= hat=(map path lobe) :: checkout commit
588− ^- ankh
589− %- cosh
590− %+ roll (~(tap by hat) ~)
591− |= [[pat=path bar=lobe] ank=ankh]
592− ^- ankh
593− %- cosh
594− ?~ pat
595− =+ zar=(lobe-to-noun bar)
596− ank(q [~ (sham zar) zar])
597− =+ nak=(~(get by r.ank) i.pat)
598− %= ank
599− r %+ ~(put by r.ank) i.pat
600− $(pat t.pat, ank (fall nak _ankh))
601− ==
602−```
603−
604−If the path is null, then we calculate `zar`, the raw data at the path
605−`pat` in this version. We produce the given ankh with the correct data.
606−
607−Otherwise, we try to get the child we're looking at from our parent
608−ankh. If it's already been created, this succeeds; otherwise, we simply
609−create a default blank ankh. We place ourselves in our parent after
610−recursively computing our children.
611−
612−This algorithm really isn't that complicated, but it may not be
613−immediately obvious why it works. An example should clear everything up.
614−
615−Suppose `hat` is a map of the following information.
616−
617−```
618− /greeting --> "customary upon meeting"
619− /greeting/english --> "hello"
620− /greeting/spanish --> "hola"
621− /greeting/russian/short --> "привет"
622− /greeting/russian/long --> "Здравствуйте"
623− /farewell/russian --> "до свидания"
624−```
625−
626−Furthermore, let's say that we process them in this order:
627−
628−```
629− /greeting/english
630− /greeting/russian/short
631− /greeting/russian/long
632− /greeting
633− /greeting/spanish
634− /farewell/russian
635−```
636−
637−Then, the first path we process is `/greeting/english` . Since our path
638−is not null, we try to get `nak`, but because our ankh is blank at this
639−point it doesn't find anything. Thus, update our blank top-level ankh
640−with a child `%greeting`. and recurse with the blank `nak` to create the
641−ankh of the new child.
642−
643−In the recursion, we our path is `/english` and our ankh is again blank.
644−We try to get the `english` child of our ankh, but this of course fails.
645−Thus, we update our blank `/greeting` ankh with a child `english`
646−produced by recursing.
647−
648−Now our path is null, so we call `++lobe-to-noun` to get the actual
649−data, and we place it in the brand-new ankh.
650−
651−Next, we process `/greeting/russian/short`. Since our path is not null,
652−we try to get the child named `%greeting`, which does exist since we
653−created it earlier. We put modify this child by recursing on it. Our
654−path is now `/russian/short`, so we look for a `%russian` child in our
655−`/greeting` ankh. This doesn't exist, so we add it by recursing. Our
656−path is now `/short`, so we look for a `%short` child in our
657−`/greeting/russian` ankh. This doesn't exist, so we add it by recursing.
658−Now our path is null, so we set the contents of this node to `"привет"`,
659−and we're done processing this path.
660−
661−Next, we process `/greeting/russian/long`. This proceeds similarly to
662−the previous except that now the ankh for `/greeting/russian` already
663−exists, so we simply reuse it rather than creating a new one. Of course,
664−we still must create a new `/greeting/russian/long` ankh.
665−
666−Next, we process `/greeting`. This ankh already exists, so after we've
667−recursed once, our path is null, and our ankh is not blank -- it already
668−has two children (and two grandchildren). We don't touch those, though,
669−since a node may be both a file and a directory. We just add the
670−contents of the file -- "customary upon meeting" -- to the existing
671−ankh.
672−
673−Next, we process `/greeting/spanish`. Of course, the `/greeting` ankh
674−already exists, but it doesn't have a `%spanish` child, so we create
675−that, taking care not to disturb the contents of the `/greeting` file.
676−We put "hola" into the ankh and call it good.
677−
678−Finally, we process `/farewell/russian`. Here, the `/farewell` ankh
679−doesn't exist, so we create it. Clearly the newly-created ankh doesn't
680−have any children, so we have to add a `%russian` child, and in this
681−child we put our last content -- "до свидания".
682−
683−We hope it's fairly obvious that the order we process the paths doesn't
684−affect the final ankh tree. The tree will be constructed in a very
685−different order depending on what order the paths come in, but the
686−resulting tree is independent of order.
687−
688−At any rate, we were talking about something important, weren't we? If
689−you recall, that concludes our discussion of `++rewind`, which was
690−called from `++read-at-aeon`. In summary, `++rewind` returns a context
691−in which our current state is (very nearly) as it was when the specified
692−version of the desk was the head. This allows `++read-at-aeon` to call
693−`++read` to read the requested information.
694−
695−```hoon
696− ++ read :: read:ze
697− |= mun=mood :: read at point
698− ^- (unit)
699− ?: ?=(%v p.mun)
700− [~ `dome`+<+<.read]
701− ?: &(?=(%w p.mun) !?=(%ud -.q.mun))
702− ?^(r.mun ~ [~ let])
703− ?: ?=(%w p.mun)
704− =+ ^= yak
705− %- tako-to-yaki
706− %- aeon-to-tako
707− let
708− ?^(r.mun ~ [~ [t.yak (forge-nori yak)]])
709− ::?> ?=(^ hit) ?^(r.mun ~ [~ i.hit]) :: what do?? need [@da nori]
710− (query(ank ank:(descend-path:(zu ank) r.mun)) p.mun)
711−```
712−
713−If we're requesting the dome, then we just return that immediately.
714−
715−If we're requesting the revision number of the desk and we're not
716−requesting it by number, then we just return the current number of this
717−desk. Note of course that this was really already handled in
718−`++read-at-aeon`.
719−
720−If we're requesting a `%w` with a specific revision number, then we do
721−something or other with the commit there. It's kind of weird, and it
722−doesn't seem to work, so we'll ignore this case.
723−
724−Otherwise, we descend into the ankh tree to the given path with
725−`++descend-path:zu`, and then we handle specific request in `++query`.
726−
727−```hoon
728− ++ descend-path :: descend recursively
729− |= way=path
730− ^+ +>
731− ?~(way +> $(way t.way, +> (descend i.way)))
732−```
733−
734−This is simple recursion down into the ankh tree. `++descend` descends
735−one level, so this will eventually get us down to the path we want.
736−
737−```hoon
738− ++ descend :: descend
739− |= lol=@ta
740− ^+ +>
741− =+ you=(~(get by r.ank) lol)
742− +>.$(ram [lol ram], ank ?~(you [*cash ~ ~] u.you))
743−```
744−
745−`ram` is the path that we're at, so to descend one level we push the
746−name of this level onto that path. We update the ankh with the correct
747−one at that path if it exists; else we create a blank one.
748−
749−Once we've decscended to the correct level, we need to actually deal
750−with the request.
751−
752−```hoon
753− ++ query :: query:ze
754− |= ren=?(%u %v %x %y %z) :: endpoint query
755− ^- (unit ,*)
756− ?- ren
757− %u [~ `rang`+<+>.query]
758− %v [~ `dome`+<+<.query]
759− %x ?~(q.ank ~ [~ q.u.q.ank])
760− %y [~ as-arch]
761− %z [~ ank]
762− ==
763−```
764−
765−Now that everything's set up, it's really easy. If they're requesting
766−the rang, dome, or ankh, we give it to them. If the contents of a file,
767−we give it to them if it is in fact a file. If the `arch`, then we
768−calculate it with `++as-arch`.
769−
770−```hoon
771− ++ as-arch :: as-arch:ze
772− ^- arch :: arch report
773− :+ p.ank
774− ?~(q.ank ~ [~ p.u.q.ank])
775− |- ^- (map ,@ta ,~)
776− ?~ r.ank ~
777− [[p.n.r.ank ~] $(r.ank l.r.ank) $(r.ank r.r.ank)]
778−```
779−
780−This very simply strips out all the "real" data and returns just our own
781−hash, the hash of the file contents (if we're a file), and a map of the
782−names of our immediate children.
783−
arvo/clay/local-sub.mddeleted−249
@@ -1,249 +0,0 @@
1−+++
2−title = "Local Subscriptions"
3−weight = 6
4−template = "doc.html"
5−+++
6−
7−Parts of this document may be out of date as of March 2021.
8−
9−A subscription to a range of revisions of a desk initially follows the
10−same path that a single read does. In `++aver`, we checked the head of
11−the given rave. If the head was `&`, then it was a single request, so we
12−handled it above. If `|`, then we handle it with the following code.
13−
14−```hoon
15− =+ nab=(~(case-to-aeon ze lim dom ran) p.p.rav)
16− ?~ nab
17− ?> =(~ (~(case-to-aeon ze lim dom ran) q.p.rav))
18− (duce hen (rive rav))
19− =+ huy=(~(case-to-aeon ze lim dom ran) q.p.rav)
20− ?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab))))
21− (blub hen)
22− =+ top=?~(huy let.dom u.huy)
23− =+ sar=(~(lobes-at-path ze lim dom ran) u.nab r.p.rav)
24− =+ ear=(~(lobes-at-path ze lim dom ran) top r.p.rav)
25− =. +>.$
26− ?: =(sar ear) +>.$
27− =+ fud=(~(make-nako ze lim dom ran) u.nab top)
28− (bleb hen u.nab fud)
29− ?^ huy
30− (blub hen)
31− =+ ^= ptr ^- case
32− [%ud +(let.dom)]
33− (duce hen `rove`[%| ptr q.p.rav r.p.rav ear])
34− ==
35−```
36−
37−Recall that `++case-to-aeon:ze` produces the revision number that a case
38−corresponds to, if it corresponds to any. If it doesn't yet correspond
39−to a revision, then it produces null.
40−
41−Thus, we first check to see if we've even gotten to the beginning of the
42−range of revisions requested. If not, then we assert that we haven't yet
43−gotten to the end of the range either, because that would be really
44−strange. If not, then we immediately call `++duce`, which, if you
45−recall, for a local request, simply puts this duct and rove into our
46−cult `qyx`, so that we know who to respond to when the revision does
47−appear.
48−
49−If we've already gotten to the first revision, then we can produce some
50−content immediately. If we've also gotten to the final revision, and
51−that revision is earlier than the start revision, then it's a bad
52−request and we call `++blub`, which tells the subscriber that his
53−subscription will not be satisfied.
54−
55−Otherwise, we find the data at the given path at the beginning of the
56−subscription and at the last available revision in the subscription. If
57−they're the same, then we don't send a notification. Otherwise, we call
58−`++gack`, which creates the `++nako` we need to produce. We call
59−`++bleb` to actually produce the information.
60−
61−If we already have the last requested revision, then we also tell the
62−subscriber with `++blub` that the subscription will receive no further
63−updates.
64−
65−If there will be more revisions in the subscription, then we call
66−`++duce`, adding the duct to our subscribers. We modify the rove to
67−start at the next revision since we've already handled all the revisions
68−up to the present.
69−
70−We glossed over the calls to `++lobes-at-path`, `++make-nako`, and
71−`++bleb`, so we'll get back to those right now. `++bleb` is simple, so
72−we'll start with that.
73−
74−```hoon
75− ++ bleb :: ship sequence
76− |= [hen=duct ins=@ud hip=nako]
77− ^+ +>
78− (blab hen [%w [%ud ins] ~] hip)
79−```
80−
81−We're given a duct, the beginning revision number, and the nako that
82−contains the updates since that revision. We use `++blab` to produce
83−this result to the subscriber. The case is `%w` with a revision number
84−of the beginning of the subscription, and the data is the nako itself.
85−
86−We call `++lobes-at-path:ze` to get the data at the particular path.
87−
88−```hoon
89− ++ lobes-at-path :: lobes-at-path:ze
90− |= [oan=aeon pax=path] :: data at path
91− ^- (map path lobe)
92− ?: =(0 oan) ~
93− %- mo
94− %+ skim
95− %. ~
96− %~ tap by
97− =< q
98− %- tako-to-yaki
99− %- aeon-to-tako
100− oan
101− |= [p=path q=lobe]
102− ?| ?=(~ pax)
103− ?& !?=(~ p)
104− =(-.pax -.p)
105− $(p +.p, pax +.pax)
106− == ==
107−```
108−
109−At revision zero, the theoretical common revision between all
110−repositories, there is no data, so we produce null.
111−
112−We get the list of paths (paired with their lobe) in the revision
113−referred to by the given number and we keep only those paths which begin
114−with `pax`. Converting to a map, we now have a map from the subpaths at
115−the given path to the hash of their data. This is simple and efficient
116−to calculate and compare to later revisions. This allows us to easily
117−tell if a node or its children have changed.
118−
119−Finally, we will describe `++make-nako:ze`.
120−
121−```hoon
122− ++ make-nako :: gack a through b
123− |= [a=aeon b=aeon]
124− ^- [(map aeon tako) aeon (set yaki) (set blob)]
125− :_ :- b
126− =- [(takos-to-yakis -<) (lobes-to-blobs ->)]
127− %+ reachable-between-takos
128− (~(get by hit) a) :: if a not found, a=0
129− (aeon-to-tako b)
130− ^- (map aeon tako)
131− %- mo %+ skim (~(tap by hit) ~)
132− |= [p=aeon *]
133− &((gth p a) (lte p b))
134−```
135−
136−We need to produce four things -- the numbers of the new commits, the
137−number of the latest commit, the new commits themselves, and the new
138−data itself.
139−
140−The first is fairly easy to produce. We simply go over our map of
141−numbered commits and produce all those numbered greater than `a` and not
142−greater than `b`.
143−
144−The second is even easier to produce -- `b` is clearly our most recent
145−commit.
146−
147−The third and fourth are slightly more interesting, though not too
148−terribly difficult. First, we call `++reachable-between-takos`.
149−
150−```hoon
151− ++ reachable-between-takos
152− |= [a=(unit tako) b=tako] :: pack a through b
153− ^- [(set tako) (set lobe)]
154− =+ ^= sar
155− ?~ a ~
156− (reachable-takos r:(tako-to-yaki u.a))
157− =+ yak=`yaki`(tako-to-yaki b)
158− %+ new-lobes-takos (new-lobes ~ sar) :: get lobes
159− |- ^- (set tako) :: walk onto sar
160− ?: (~(has in sar) r.yak)
161− ~
162− =+ ber=`(set tako)`(~(put in `(set tako)`~) `tako`r.yak)
163− %- ~(uni in ber)
164− ^- (set tako)
165− %+ roll p.yak
166− |= [yek=tako bar=(set tako)]
167− ^- (set tako)
168− ?: (~(has in bar) yek) :: save some time
169− bar
170− %- ~(uni in bar)
171− ^$(yak (tako-to-yaki yek))
172−```
173−
174−We take a possible starting commit and a definite ending commit, and we
175−produce the set of commits and the set of data between them.
176−
177−We let `sar` be the set of commits reachable from `a`. If `a` is null,
178−then obviously no commits are reachable. Otherwise, we call
179−`++reachable-takos` to calculate this.
180−
181−```hoon
182− ++ reachable-takos :: reachable
183− |= p=tako :: XX slow
184− ^- (set tako)
185− =+ y=(tako-to-yaki p)
186− =+ t=(~(put in _(set tako)) p)
187− %+ roll p.y
188− |= [q=tako s=_t]
189− ?: (~(has in s) q) :: already done
190− s :: hence skip
191− (~(uni in s) ^$(p q)) :: otherwise traverse
192−```
193−
194−We very simply produce the set of the given tako plus its parents,
195−recursively.
196−
197−Back in `++reachable-between-takos`, we let `yak` be the yaki of `b`,
198−the ending commit. With this, we create a set that is the union of `sar`
199−and all takos reachable from `b`.
200−
201−We pass `sar` into `++new-lobes` to get all the lobes referenced by any
202−tako referenced by `a`. The result is passed into `++new-lobes-takos` to
203−do the same, but not recomputing those in already calculated last
204−sentence. This produces the sets of takos and lobes we need.
205−
206−```hoon
207− ++ new-lobes :: object hash set
208− |= [b=(set lobe) a=(set tako)] :: that aren't in b
209− ^- (set lobe)
210− %+ roll (~(tap in a) ~)
211− |= [tak=tako bar=(set lobe)]
212− ^- (set lobe)
213− =+ yak=(tako-to-yaki tak)
214− %+ roll (~(tap by q.yak) ~)
215− |= [[path lob=lobe] far=_bar]
216− ^- (set lobe)
217− ?~ (~(has in b) lob) :: don't need
218− far
219− =+ gar=(lobe-to-blob lob)
220− ?- -.gar
221− %direct (~(put in far) lob)
222− %delta (~(put in $(lob q.gar)) lob)
223− %indirect (~(put in $(lob s.gar)) lob)
224− ==
225−```
226−
227−Here, we're creating a set of lobes referenced in a commit in `a`. We
228−start out with `b` as the initial set of lobes, so we don't need to
229−recompute any of the lobes referenced in there.
230−
231−The algorithm is pretty simple, so we won't bore you with the details.
232−We simply traverse every commit in `a`, looking at every blob referenced
233−there, and, if it's not already in `b`, we add it to `b`. In the case of
234−a direct blob, we're done. For a delta or an indirect blob, we
235−recursively add every blob referenced within the blob.
236−
237−```hoon
238− ++ new-lobes-takos :: garg & repack
239− |= [b=(set lobe) a=(set tako)]
240− ^- [(set tako) (set lobe)]
241− [a (new-lobes b a)]
242−```
243−
244−Here, we just update the set of lobes we're given with the commits we're
245−given and produce both sets.
246−
247−This concludes our discussion of a local subscription.
248−
249−
arvo/clay/scry.mdnew file+425
@@ -0,0 +1,425 @@
1++++
2+title = "Scry Reference"
3+weight = 5
4+template = "doc.html"
5++++
6+
7+The various Clay scries are specified by a `care`, which is a single character corresponding with a Clay submodule. Apart from `%s` they just take a `path` to a `desk`, file or directory. All examples are dojo commands, the ='s in the path are automatically populated by the dojo like:
8+
9+```
10+> /===
11+[~.~zod ~.home ~.~2021.4.26..02.29.03..d31b ~]
12+```
13+
14+## Contents
15+
16+- [%a](#a) - Build a `hoon` file.
17+- [%b](#b) - Dynamic `mark`.
18+- [%c](#c) - Dynamic `mark` conversion.
19+- [%d](#d) - List `desk`s.
20+- [%e](#e) - Static `mark`.
21+- [%f](#f) - Static `mark` conversion.
22+- [%p](#p) - File permissions.
23+- [%r](#r) - Vase-wrapped file data.
24+- [%s](#s) - Miscellaneous scries:
25+ - [%yaki](#yaki) - `yaki:clay` of the specified commit.
26+ - [%blob](#blob) - `blob:clay` of file.
27+ - [%hash](#hash) - Content hash of the specified commit.
28+ - [%cage](#cage) - `cage` of the data of a file.
29+ - [%open](#open) - Compile prelude of file.
30+ - [%late](#late) - Most recent `case` of `desk`.
31+ - [%base](#base) - Mergebase of two `desk`s.
32+- [%t](#t) - List files in directory.
33+- [%u](#u) - Check for existence of file.
34+- [%v](#v) - Desk state.
35+- [%w](#w) - Revision number of the given `desk` `case`.
36+- [%x](#x) - Raw data of file.
37+- [%y](#y) - `arch` of a file or directory.
38+- [%z](#z) - Content hash of a file or directory.
39+
40+## %a
41+
42+A scry with a `care` of `%a` will build a `hoon` file and return it as a `vase`.
43+
44+Example:
45+
46+```
47+.^(vase %ca /===/lib/strandio/hoon)
48+```
49+
50+## %b
51+
52+A scry with a `care` of `%b` will produce a `dais:clay` processed `mark` core for the specified `mark`. The `path` in the scry is a `mark`.
53+
54+Example:
55+
56+```
57+.^(dais:clay %cb /===/txt)
58+```
59+
60+## %c
61+
62+A scry with a `care` of `%c` will produce a `tube:clay` dynamically typed `mark` conversion gate. The `path` specifies two `mark`s - *from* and *to*, like `/txt/noun`.
63+
64+Example:
65+
66+```
67+> =a .^(tube:clay %cc /===/txt/mime)
68+> !< mime (a !>(~['foo']))
69+[p=/text/plain q=[p=3 q=7.303.014]]
70+```
71+
72+## %d
73+
74+A scry with a `care` of `%d` will return a `(set desk)` of the `desk`s that exist on your ship.
75+
76+Example:
77+
78+```
79+> .^((set desk) %cd /===)
80+{%home %kids}
81+```
82+
83+## %e
84+
85+A scry with a `care` of `%e` will return a statically typed `nave:clay` `mark` core in a `vase`. The `path` in the scry specifies the `mark`.
86+
87+Example:
88+
89+```
90+.^(vase %ce /===/noun)
91+```
92+
93+## %f
94+
95+A scry with a `care` of `%f` will return a static `mark` conversion gate. The `path` specifies two `mark`s - *from* and *to*, like `/txt/mime`.
96+
97+```
98+> =a .^($-(text mime) %cf /===/txt/mime)
99+> (a ~['foo'])
100+[p=/text/plain q=[p=3 q=7.303.014]]
101+```
102+
103+## %p
104+
105+A scry with a `care` of `%p` will return the permissions of the file or directory in question. The type returned is a `[dict:clay dict:clay]` where the head is read permissions and the tail is write permissions.
106+
107+If the specified file or directory has no permissions set, it will default to the permissions of its parent. If nothing above it has permissions set, it will default to empty whitelists. If the specified file or directory doesn't exist, it will also return the default empty whitelist.
108+
109+Example:
110+
111+```
112+> .^([dict:clay dict:clay] %cp /===/gen)
113+[[src=/ rul=[mod=%white who=[p={} q={}]]] src=/ rul=[mod=%white who=[p={} q={}]]]
114+```
115+
116+## %r
117+
118+A scry with a `care` of `%r` will return the data of the given file wrapped in a `vase` or crash if it's a directory. It's basically just a vase-wrapped `%x` scry.
119+
120+Examples:
121+
122+```
123+> .^(vase %cr /===/gen/hood/hi/hoon)
124+[ #t/@
125+ q
126+ 3.548.750.706.400.251.607.252.023.288.575.526.190.856.734.474.077.821.289.791.377.301.707.878.697.553.411.219.689.905.949.957.893.633.811.025.757.107.990.477.902.858.170.125.439.223.250.551.937.540.468.638.902.955.378.837.954.792.031.592.462.617.422.136.386.332.469.076.584.061.249.923.938.374.214.925.312.954.606.277.212.923.859.309.330.556.730.410.200.952.056.760.727.611.447.500.996.168.035.027.753.417.869.213.425.113.257.514.474.700.810.203.348.784.547.006.707.150.406.298.809.062.567.217.447.347.357.039.994.339.342.906
127+]
128+```
129+
130+```
131+> !< @t .^(vase %cr /===/gen/hood/hi/hoon)
132+':: Helm: send message to an urbit\0a::\0a:::: /hoon/hi/hood/gen\0a ::\0a/? 310\0a:- %say\0a|=([^ [who=ship mez=$@(~ [a=tape ~])] ~] helm-send-hi+[who ?~(mez ~ `a.mez)])\0a'
133+```
134+
135+```
136+> .^(vase %cr /===/gen)
137+Crash!
138+```
139+
140+## %s
141+
142+A scry with a `care` of `%s` is for miscellaneous internal and debug functions and is liable to change in the future.
143+
144+Rather than just a `path` to a file, the head of the `path` is tagged with one of `%yaki %blob %hash %cage %open %late %base` and the tail depends on which tag you use. We'll look at each in turn.
145+
146+### %yaki
147+
148+This will return the [yaki:clay](@/docs/arvo/clay/data-types.md#yaki-clay-commit) of the specified commit. It takes a [tako:clay](@/docs/arvo/clay/data-types.md#tako-clay-commit-reference).
149+
150+Example:
151+
152+Here we scry the [dome:clay](@/docs/arvo/clay/data-types.md#dome-desk-data) for `/===`, get the latest `tako:clay` and the do a `%s` scry for the `yaki:clay` in question.
153+
154+```
155+> =/ =dome:clay .^(dome:clay %cv /===)
156+ =/ =tako:clay (~(got by hit.dome) let.dome)
157+ .^(yaki:clay %cs /===/yaki/(scot %uv tako))
158+[ p=~[80.174.473.756.485.530.520.259.753.935.584.637.641.665.425.899.348.092.348.244.635.557.986.495.151.006]
159+ q
160+ { [p=/mar/hark/graph-hook-update/hoon q=0v5.ea0bj.21s5c.mjrop.ishic.fpkvl.e5bbs.91kc9.tdo41.ifi06.60v41]
161+ [p=/gen/hood/autocommit/hoon q=0v19.rh7jv.sa67o.t3jrb.4sdvs.7c45f.pv2u0.ragik.psp20.agqd8.8srkj]
162+ ...
163+ [p=/tests/lib/primitive-rsa/hoon q=0v1g.3qmq3.6i15q.arh6h.lfsqu.gvc9m.ql6m5.e2rdr.vnnt9.tptc6.mv9u7]
164+ [p=/tests/sys/vane/gall/hoon q=0va.alspc.qptqn.7tuj0.bgecg.1093t.gtsjs.up03k.d1fmk.4jrh8.2tdfa]
165+ }
166+ r=88.666.797.531.755.181.802.690.473.856.185.443.710.929.766.582.249.039.904.824.278.074.149.777.897.099
167+ t=~2021.4.16..10.41.57..3565
168+]
169+```
170+
171+### %blob
172+
173+This will return the [blob:clay](@/docs/arvo/clay/data-types.md#blob-clay-data) of some file. It takes a [lobe:clay](@/docs/arvo/clay/data-types.md#lobe-clay-data-reference).
174+
175+Example:
176+
177+Here we grab the `lobe:clay` of `/gen/hood/hi/hoon` with a `%y` scry, then use it to do a `%s` scry for the `blob:clay` of the file.
178+
179+```
180+> =/ =arch .^(arch %cy /===/gen/hood/hi/hoon)
181+ ?~ fil.arch
182+ ~
183+ .^(blob:clay %cs /===/blob/(scot %uv u.fil.arch))
184+[ %direct
185+ p=0vp.k7nsm.qkdr3.t17rp.33bae.8gajg.v27gi.40itr.2u9qa.nppbt.7k255
186+ q
187+ [ p=%hoon
188+ q
189+3.548.750.706.400.251.607.252.023.288.575.526.190.856.734.474.077.821.289.791.377.301.707.878.697.553.411.219.689.905.949.957.893.633.811.025.757.107.990.477.902.858.170.125.439.223.250.551.937.540.468.638.902.955.378.837.954.792.031.592.462.617.422.136.386.332.469.076.584.061.249.923.938.374.214.925.312.954.606.277.212.923.859.309.330.556.730.410.200.952.056.760.727.611.447.500.996.168.035.027.753.417.869.213.425.113.257.514.474.700.810.203.348.784.547.006.707.150.406.298.809.062.567.217.447.347.357.039.994.339.342.906
190+ ]
191+]
192+```
193+
194+### %hash
195+
196+This will return the `@uvI` content hash of the specified commit. It takes a `tako:clay`.
197+
198+Example:
199+
200+Here we grab the `dome:clay` for `/===` with a `%v` scry, get the latest `tako:clay` and then do a `%s` `%hash` scry for it.
201+
202+```
203+> =/ =dome:clay .^(dome:clay %cv /===)
204+ =/ =tako:clay (~(got by hit.dome) let.dome)
205+ .^(tako:clay %cs /===/hash/(scot %uv tako))
206+0v16.er7uq.oke4u.cru7u.nglu9.q3su7.6ub1o.bh4qk.r5uav.ut12d.5rdl5
207+```
208+
209+### %cage
210+
211+This will return a `cage` of the data of some file. It takes a `lobe:clay`.
212+
213+Example:
214+
215+Here we grab the `lobe:clay` of `/gen/hood/hi/hoon` with a `%y` scry, then use it to do a `%s` scry for the `cage` of the data.
216+
217+```
218+> =/ =arch .^(arch %cy /===/gen/hood/hi/hoon)
219+ ?~ fil.arch
220+ ~
221+ .^(cage %cs /===/cage/(scot %uv u.fil.arch))
222+[ p=%hoon
223+ q
224+ [ #t/@t
225+ q
226+3.548.750.706.400.251.607.252.023.288.575.526.190.856.734.474.077.821.289.791.377.301.707.878.697.553.411.219.689.905.949.957.893.633.811.025.757.107.990.477.902.858.170.125.439.223.250.551.937.540.468.638.902.955.378.837.954.792.031.592.462.617.422.136.386.332.469.076.584.061.249.923.938.374.214.925.312.954.606.277.212.923.859.309.330.556.730.410.200.952.056.760.727.611.447.500.996.168.035.027.753.417.869.213.425.113.257.514.474.700.810.203.348.784.547.006.707.150.406.298.809.062.567.217.447.347.357.039.994.339.342.906
227+ ]
228+]
229+```
230+
231+### %open
232+
233+This is like a `%a` scry but it only compiles the prelude to the file, e.g. the Ford rune imports. Proper documentation for this will be done as part of Ford documentaton at a later date.
234+
235+### %late
236+
237+This will return the most recent revision number of a `desk` that has been fully downloaded. The type it returns is a `cass:clay`. The `case` in the `beak` must be a revision number rather than a date. You can just provide a case of `1` since it returns the latest regardless. If we have nothing for the specified `desk`, this will just return the bunt of a `cass:clay` like `cass=[ud=0 da=~2000.1.1]`.
238+
239+Example:
240+
241+```
242+> .^(=cass:clay %cs /(scot %p (sein:title our now our))/kids/1/late)
243+cass=[ud=50 da=~2021.4.22..10.38.50..57a8]
244+```
245+
246+```
247+> .^(=cass:clay %cs /~sampel/kids/1/late)
248+cass=[ud=0 da=~2000.1.1]
249+```
250+
251+### %base
252+
253+This will return the mergebase (i.e. most recent common ancestor) between two `desk`s. The type it returns is a `(list tako:clay)`. The first `desk` will just be the one in the `beak` `path` prefix and the second will be specified like `/ship/desk` at the end of the scry `path`. If there is no common ancestor between the two `desk`s, this will just produce an empty `list`.
254+
255+Examples:
256+
257+```
258+> .^((list tako:clay) %cs /===/base/(scot %p (sein:title our now our))/kids)
259+~[102.787.244.596.033.419.950.995.540.301.493.841.569.518.772.322.508.085.465.561.801.703.148.627.263.473]
260+```
261+
262+```
263+> .^((list tako:clay) %cs /===/base/~sampel/kids)
264+~
265+```
266+
267+## %t
268+
269+A scry with a `care` of `%t` will return a `(list path)` of all files in the given directory, or just a `(list path)` of the single file if it's a file. This is done recursively so will provide files in subdirectories as well. The paths will be fully qualified except for the `ship`, `desk` and `case`. If the directory or file specified does not exist, it will return an empty `list`.
270+
271+Examples:
272+
273+```
274+> .^((list path) %ct /===/app/landscape)
275+~[
276+ /app/landscape/css/index/css
277+ /app/landscape/img/favicon/png
278+ /app/landscape/img/imageupload/png
279+ /app/landscape/img/touch_icon/png
280+ /app/landscape/index/html
281+ /app/landscape/js/channel/js
282+]
283+```
284+
285+```
286+> .^((list path) %ct /===/gen/group-store/add/hoon)
287+~[/gen/group-store/add/hoon]
288+```
289+
290+```
291+> .^((list path) %ct /===/foobar)
292+~
293+```
294+
295+## %u
296+
297+A scry with a `care` of `%u` will return a `?` depending on whether the file exists. It will produce `%.n` if it's a directory or doesn't exist and will produce `%.y` if it's a file and exists.
298+
299+Examples:
300+
301+```
302+> .^(? %cu /===/app)
303+%.n
304+```
305+
306+```
307+> .^(? %cu /===/gen/code/hoon)
308+%.y
309+```
310+
311+```
312+> .^(? %cu /===/foobar)
313+%.n
314+```
315+
316+## %v
317+
318+A scry with a care of `%v` will return the entire state of a `desk` as a `dome:clay`.
319+
320+Example:
321+
322+```
323+> =a .^(dome:clay %cv /===)
324+> let.a
325+1
326+```
327+
328+Note: If you try printing this it will take forever and probably OOM your ship.
329+
330+## %w
331+
332+A scry with a `care` of `%w` will return the revision number and date of a given `case`. The type returned is a `cass:clay` like `[ud=@ud da=@da]` where `ud` is the revision number and `da` is the date.
333+
334+Example:
335+
336+```
337+> .^(cass:clay %cw /===)
338+[ud=2 da=~2021.4.13..19.12.49..3389]
339+```
340+
341+## %x
342+
343+A scry with a `care` of `%x` will return the raw data of a file as an `@` or crash if it's a directory.
344+
345+
346+Examples:
347+
348+```
349+> .^(@ %cx /===/gen/hood/hi/hoon)
350+3.548.750.706.400.251.607.252.023.288.575.526.190.856.734.474.077.821.289.791.377.301.707.878.697.553.411.219.689.905.949.957.893.633.811.025.757.107.990.477.902.858.170.125.439.223.250.551.937.540.468.638.902.955.378.837.954.792.031.592.462.617.422.136.386.332.469.076.584.061.249.923.938.374.214.925.312.954.606.277.212.923.859.309.330.556.730.410.200.952.056.760.727.611.447.500.996.168.035.027.753.417.869.213.425.113.257.514.474.700.810.203.348.784.547.006.707.150.406.298.809.062.567.217.447.347.357.039.994.339.342.906
351+```
352+
353+```
354+> .^(@t %cx /===/gen/hood/hi/hoon)
355+':: Helm: send message to an urbit\0a::\0a:::: /hoon/hi/hood/gen\0a ::\0a/? 310\0a:- %say\0a|=([^ [who=ship mez=$@(~ [a=tape ~])] ~] helm-send-hi+[who ?~(mez ~ `a.mez)])\0a'
356+```
357+
358+```
359+> .^(@ %cx /===/gen/hood)
360+Crash!
361+```
362+
363+## %y
364+
365+A scry with a `care` of `%y` will return the `arch` of a file or directory.
366+
367+An `arch` is a `[fil=(unit lobe:clay) dir=(map @ta ~)]`. The `fil` will contain the `lobe:clay` hash if it's a file, otherwise it will be null. The `dir` will contain a map of the files and directories it contains, otherwise it will be null.
368+
369+It will return the bunt of an `arch` if the file or directory is not found.
370+
371+Examples:
372+
373+```
374+> .^(arch %cy /===/gen/group-store)
375+[ fil=~
376+ dir
377+ { [p=~.allow-ships q=~]
378+ [p=~.add q=~]
379+ [p=~.ban-ranks q=~]
380+ [p=~.remove q=~]
381+ [p=~.create q=~]
382+ [p=~.join q=~]
383+ [p=~.allow-ranks q=~]
384+ [p=~.ban-ships q=~]
385+ }
386+]
387+```
388+
389+```
390+> .^(arch %cy /===/gen/group-store/allow-ships)
391+[fil=~ dir={[p=~.hoon q=~]}]
392+```
393+
394+```
395+> .^(arch %cy /===/gen/group-store/allow-ships/hoon)
396+[fil=[~ 0vb.g8sqs.7gjm9.bl3vu.nk677.h5be1.g9eg3.4v1jo.00ivf.g8ndu.48a53] dir={}]
397+```
398+
399+```
400+> .^(arch %cy /===/foobar)
401+[fil=~ dir={}]
402+```
403+
404+## %z
405+
406+A scry with a `care` of `%z` will return the hash of a file or the recursive hash of a directory. If the file or directory doesn't exist it will return a null value.
407+
408+The type returned is a `@uxI`.
409+
410+Examples:
411+
412+```
413+> .^(@uvI %cz /===/gen)
414+0v5.itmhj.lt7ak.lgr1k.dr7vu.u7u9s.ko5rf.idfcr.ukrd2.t088n.3ml1k
415+```
416+
417+```
418+> .^(@uvI %cz /===/gen/code/hoon)
419+0v1t.vi1pf.3ba4n.87g6h.dcc1p.4t4l8.rm6a9.b4de4.v77qc.p9dc0.p8289
420+```
421+
422+```
423+> .^(@uvI %cz /===/foobar)
424+0v0
425+```
arvo/clay/tasks.mdnew file+555
@@ -0,0 +1,555 @@
1++++
2+title = "API Reference"
3+weight = 6
4+template = "doc.html"
5++++
6+
7+# Contents
8+
9+- [Introduction](#introduction)
10+- [%warp](#warp) - Read and Subscribe.
11+ - [%sing](#sing) - Read a file or directory.
12+ - [%next](#next) - Subscribe for the next change to a file or directory.
13+ - [%mult](#mult) - Subscribe for the next change to a set of files and/or directories.
14+ - [%many](#many) - Track changes to a `desk` for the specified range of revisions.
15+ - [Cancel Subscription](#cancel-subscription)
16+- [Write and Modify](#write-and-modify)
17+ - [%info](#info)
18+- [Manage Mounts](#manage-mounts)
19+ - [%boat](#boat) - List mounts.
20+ - [%mont](#mont) - Mount something.
21+ - [%ogre](#ogre) - Unmount something.
22+ - [%dirk](#dirk) - Commit changes.
23+- [Merge Desks](#merge-desks)
24+ - [%merg](#merg)
25+- [Permissions](#permissions)
26+ - [%perm](#perm) - Set file permissions.
27+ - [%cred](#cred) - Add permission group.
28+ - [%crew](#crew) - Get permission groups.
29+ - [%crow](#crow) - Get group usage.
30+- [Foreign Ships](#foreign-ships)
31+ - [%warp](#warp-remote) - Read a file on a foreign ship.
32+ - [%merg](#merg-remote) - Merge from a foreign `desk`.
33+
34+# Introduction
35+
36+This document details all the `task`s you're likely to use to interact with Clay, as well as the `gift`s you'll receive in response. Each section has a corresponding practical example in the [Examples](@/docs/arvo/clay/examples.md) document. Many of the types referenced are detailed in the [Data Types](@/docs/arvo/clay/data-types.md) document. It may also be useful to look at the `++ clay` section of `/sys/lull.hoon` in Arvo where these `task`s, `gift`s and data structures are defined.
37+
38+The focus of this document is on interacting with Clay from userspace applications and threads, so it doesn't delve into the internal mechanics of Clay from a kernel development perspective.
39+
40+# `%warp`
41+
42+A `%warp` `task` is for reading a subscribing to files and directories.
43+
44+### Accepts
45+
46+```hoon
47+[wer=ship rif=riff]
48+```
49+
50+The `wer` field is the target ship. The `(unit rave)` of the [riff](@/docs/arvo/clay/data-types.md#riff-clay-request-desist) is null to cancel an existing subscription, otherwise the [rave](@/docs/arvo/clay/data-types.md#rave-clay-general-subscription-request) is tagged with one of:
51+
52+- `%sing` - Read a single file or directory.
53+- `%next` - Subscribe for the next change to a file or directory.
54+- `%mult` - Subscribe for the next change to a set of files and/or directories.
55+- `%many` - Track changes to a desk for the specified range of revisions.
56+
57+We'll look at each of these in more detail below.
58+
59+### Returns
60+
61+Clay responds to a `%mult` request with a `%wris` `gift`, and the rest with a `%writ` `gift`.
62+
63+A `%wris` `gift` looks like:
64+
65+```hoon
66+[%wris p=[%da p=@da] q=(set (pair care path))] :: many changes
67+```
68+
69+...and a `%writ` `gift` looks like:
70+
71+```hoon
72+[%writ p=riot] :: response
73+```
74+
75+The `unit` of the [riot](@/docs/arvo/clay/data-types.md#riot-clay-response) will be null if the target file cannot be found or if a subscription has ended (depending on context). Otherwise it will have a [rant](@/docs/arvo/clay/data-types.md#rant-clay-response-data) with a `cage` containing the data you requested. Its contents will vary depending on the kind of request and `care`.
76+
77+Now we'll look at each of the `rave` request types in turn.
78+
79+## `%sing`
80+
81+```hoon
82+[%sing =mood]
83+```
84+
85+This `rave` is for reading a single file or directory immediately.
86+
87+The `care` of the [mood](@/docs/arvo/clay/data-types.md#mood-clay-single-subscription-request) will determine what you can read and what type of data will be returned. See the [care](@/docs/arvo/clay/data-types.md#care-clay-clay-submode) documentation and [scry](@/docs/arvo/clay/scry.md) documentation for details on the various `care`s.
88+
89+The [case](@/docs/arvo/clay/data-types.md#case-specifying-a-commit) specifies the `desk` revision and you can use whichever kind you prefer. The `path` will usually be a path to a file or directory like `/gen/hood/hi/hoon` but may be something else depending on the `care`.
90+
91+### Example
92+
93+[See here for an example of using %sing.](@/docs/arvo/clay/examples.md#sing)
94+
95+## `%next`
96+
97+```hoon
98+[%next =mood] :: await next version
99+```
100+
101+This subscribes to the next version of the specified file. See [here](@/docs/arvo/clay/data-types.md#mood-clay-single-subscription-request) for details of the `mood` structure.
102+
103+If you subscribe to the current `case` of the `desk`, Clay will not respond until the file changes. If you subscribe to a previous `case` of the `desk` and the file has changed in between then and now, it will immediately return the first change it comes across in that range. For example, if you're currently at `case` `100`, subscribe to case `50` and the file in question has been modified at both `60` and `80`, clay will immediately return the version of the file at `case` `60`.
104+
105+### Example
106+
107+[See here for an example of using %next.](@/docs/arvo/clay/examples.md#next)
108+
109+## `%mult`
110+
111+```hoon
112+[%mult =mool] :: next version of any
113+```
114+
115+This subscribes to the next version of a `set` of files or directories. Clay will only send a single response, and it will send it when *any* of the specified files change. For example, if you subscribe to both `/foo/txt` and `/bar/txt`, and only `/foo/txt` changes, Clay will send a response indicating a change to `/foo/txt`. If `/bar/txt` changes subsequently, it will not tell you. If more than one file changes at once, it will tell you about each of the changes in the one response.
116+
117+The behaviour with respect to requesting old `case`s is the same as explained in the [`%next`](#next) section above.
118+
119+The `mool` specified in the request is this structure:
120+
121+```hoon
122++$ mool [=case paths=(set (pair care path))] :: requests in desk
123+```
124+
125+You can use a different `care` for each of the files specified by the `path` if you like. Significantly, the `care` will determine whether Clay sends a response for a given change. For example, if you subscribe to an existing `/foo/txt` with a `%u` `care` and `/foo/txt` is modified but isn't deleted, Clay will *not* tell you. However, if you subscribe with an `%x` `care`, it *will* tell you.
126+
127+### Example
128+
129+[See here for an example of using %mult.](@/docs/arvo/clay/examples.md#mult)
130+
131+## `%many`
132+
133+```hoon
134+[%many track=? =moat] :: track range
135+```
136+
137+This subscribes to all changes to a `desk` for the specified range of `case`s. Note that you're unlikely to use this directly, it's mostly used implicitly if you make a `%sing` or `%next` request with a `%v` `care` to a foreign `desk`. Regardless, we'll have a look at it for completeness.
138+
139+If the `track` is `%.y` it will just return a `%writ` like:
140+
141+```hoon
142+[%writ p=[~ [p=[p=%w q=[%ud p=256] r=%home] q=/ r=[p=%null q=[#t/@n q=0]]]]]
143+```
144+
145+...that merely informs you of a change. If you want the actual data you'll have to request it separately.
146+
147+If the `track` is `%.n`, the `cage` of the `%writ` will contain a [nako](@/docs/arvo/clay/data-types.md#nako-subscription-response-data) with the relevant data for all changes to a desk between what you have and the `case` requested. It is very large and fairly complicated. The `nako` structure is defined in the `clay.hoon` source file itself rather than in `lull.hoon` or elsewhere since you're unlikely to work with it yourself.
148+
149+The `from` and `to` fields of the [moat](@/docs/arvo/clay/data-types.md#moat-clay-range-subscription-request) specify the range of `case`s for which to subscribe. The range is *inclusive*. It can be specified by date or by revision number, whichever you prefer.
150+
151+The `path` in the `moat` is a path to a file or directory. If it's `~` it refers to the root of the `desk` in question. This lets you say "only inform me of changes to the `desk` if the specified file or directory exists". If it doesn't exist, Clay will not send you anything.
152+
153+When you reach the end of the subscribed range of `case`s, Clay will send you a `%writ` with a null `riot` to inform you the subscription has ended like:
154+
155+```hoon
156+[%writ p=~]
157+```
158+
159+### Example
160+
161+[See here for an example of using %many.](@/docs/arvo/clay/examples.md#many)
162+
163+## Cancel Subscription
164+
165+To cancel a subscription, you just send a `%warp` with a null `(unit rave)` in the `riff`. Clay will cancel the subscription based on the `wire`. The request is exactly the same regardless of which type of `rave` you subscribed with originally.
166+
167+### Example
168+
169+[See here for an example of cancelling a subscription.](@/docs/arvo/clay/examples.md#cancel-subscription)
170+
171+# Write and Modify
172+
173+## `%info`
174+
175+To write or modify a file, we send Clay a `%info` `task`.
176+
177+### Accepts
178+
179+```hoon
180+[des=desk dit=nori]
181+```
182+
183+The `%|` tag in the [nori](@/docs/arvo/clay/data-types.md#nori-clay-repository-action) is not currently supported and will crash with a `%labelling-not-implemented` if used, so you can focus on the `%&` part. The [soba](@/docs/arvo/clay/data-types.md#soba-clay-delta) in the `nori` is just a list of changes so you can make more than one change in one request. Its `path` is just the path to a file like `/gen/hood/hi/hoon` and the [miso](@/docs/arvo/clay/data-types.md#miso-clay-ankh-delta) is one of these types of requests:
184+
185+- `%del` - Delete a file.
186+- `%ins` - Insert file. This will also replace an existing file.
187+- `%dif` - This has not yet been implemented so will crash with a `%dif-not-implemented` error.
188+- `%mut` - Change a file. At the time of writing this behaves identically to `%ins` so its use merely informs the reader.
189+
190+### Returns
191+
192+Clay does not give any response to an `%info` `task` so don't expect a `sign` back.
193+
194+### Example
195+
196+Here are examples of using each of these as well as making multiple changes in one request:
197+
198+- [%del](@/docs/arvo/clay/examples.md#del)
199+- [%ins](@/docs/arvo/clay/examples.md#ins)
200+- [%mut](@/docs/arvo/clay/examples.md#mut)
201+- [Multiple Changes](@/docs/arvo/clay/examples.md#multiple-changes)
202+
203+
204+# Manage Mounts
205+
206+Here we'll look at managing Clay unix mounts programmatically.
207+
208+There are four Clay `task`s relevant to mounts:
209+
210+- [%boat](#boat) - List mounts.
211+- [%mont](#mont) - Mount something.
212+- [%ogre](#ogre) - Unmount something.
213+- [%dirk](#dirk) - Commit changes.
214+
215+## `%boat`
216+
217+A `%boat` `task` requests the list of existing mounts.
218+
219+### Accepts
220+
221+```hoon
222+~
223+```
224+
225+A `%boat` `task` does not take any arguments.
226+
227+### Returns
228+
229+The type it returns is a `%hill` `gift`, which looks like:
230+
231+```hoon
232+[%hill p=(list @tas)]
233+```
234+
235+...where the `@tas` is the name of the mount point.
236+
237+### Example
238+
239+[See here for an example of using %boat.](@/docs/arvo/clay/examples.md#boat)
240+
241+## `%mont`
242+
243+
244+A `%mont` `task` mounts the specified `beam` to the specified `term` mount point.
245+
246+### Accepts
247+
248+```hoon
249+[pot=term bem=beam]
250+```
251+
252+A `beam:clay` is the following structure:
253+
254+```hoon
255++$ beam [[p=ship q=desk r=case] s=path] :: global name
256+```
257+
258+You can mount the whole desk with a `path` of `/`, and you can also mount subdirectories or even individual files. If you want to mount an individual file, you must exclude its `mark` from the path. For example, if you want to mount `/gen/hood/hi/hoon`, you'd specify `/gen/hood/hi`. It will automatically be given the correct file extension when mounted. If you include the `hoon` mark it will crash (and currently crash your ship).
259+
260+### Returns
261+
262+Clay does not return a `gift` in response to a `%mont` `%task`.
263+
264+### Example
265+
266+[See here for an example of using %mont.](@/docs/arvo/clay/examples.md#mont)
267+
268+## `%ogre`
269+
270+A `%ogre` `task` unmounts the specified mount.
271+
272+### Accepts
273+
274+```hoon
275+[pot=$@(desk beam)]
276+```
277+
278+It's defined in `lull.hoon` as taking `$@(desk beam)` but in fact it will only unmount the target when specified as a `term` mount name. Passing it a `desk` will incidentally work if the mount is named the same as the `desk` but otherwise it won't work. Passing it a `beam:clay` will simply not work.
279+
280+### Returns
281+
282+Clay does not return a `gift` in response to a `%ogre` `task`.
283+
284+### Example
285+
286+[See here for an example of using %ogre.](@/docs/arvo/clay/examples.md#ogre)
287+
288+## `%dirk`
289+
290+A `%dirk` `task` commits changes in the target mount.
291+
292+### Accepts
293+
294+```hoon
295+des=desk
296+```
297+
298+It's defined in `lull.hoon` as taking a `desk` but like [%ogre](#ogre), it actually takes the name of a mount point rather than a `desk` as is specified.
299+
300+### Returns
301+
302+Clay does not return a `gift` in response to a `%dirk` `task`.
303+
304+### Example
305+
306+[See here for an example of using %dirk.](@/docs/arvo/clay/examples.md#dirk)
307+
308+# Merge Desks
309+
310+## `%merg`
311+
312+A `%merg` `task` will merge the specified source `desk` into the target local `desk`.
313+
314+### Accepts
315+
316+```hoon
317+$: des=desk :: target
318+ her=@p dem=desk cas=case :: source
319+ how=germ :: method
320+==
321+```
322+The `germ` specifies the merge strategy. You can refer to the [Strategies](@/docs/arvo/clay/using.md#strategies) section of the [Using Clay](@/docs/arvo/clay/using.md) document for details of each `germ`.
323+
324+If you're merging into a new `desk` you must use `%init`, all other strategies will fail. If the desk already exists, you cannot use `%init`. Otherwise, you're free to use whichever you'd like.
325+
326+### Returns
327+
328+Clay will respond to the request with a `%mere` `gift` which looks like:
329+
330+```hoon
331+[%mere p=(each (set path) (pair term tang))] :: merge result
332+```
333+
334+If the merge succeeded, `p` will look like `[%mere p=[%.y p={}]]` where `p.p` is the set of files which had a merge conflict. For example, `[%mere p=[%.y p={/foo/txt}]]` means there was a conflict with `/foo/txt`. An empty set means there were no conflicts.
335+
336+If the merge failed, `p` will have a head of `%.n` and then a `[term tang]` where the `term` is an error message and the `tang` contains additional details, for example:
337+
338+```hoon
339+[ %mere
340+ p
341+ [ %.n
342+ p=[p=%mate-conflict q=~[[%rose p=[p="/" q="/" r=""] q=~[[%leaf p="foo"] [%leaf p="txt"]]]]]
343+ ]
344+]
345+```
346+
347+### Example
348+
349+[See here for an example of using %merg.](@/docs/arvo/clay/examples.md#merg)
350+
351+# Permissions
352+
353+For each file or directory, there is both a read permission and a write permission. Each may be set separately and is either a whitelist or a blacklist (but not both). The whitelist/blacklist contains a `set` of ships and/or groups which are allowed or banned respectively. If it's an empty whitelist it means all foreign ships are denied. If it's an empty blacklist it means all foreign ships are allowed.
354+
355+If permissions are not set for a particular file, they will be inherited from the directory in which it resides. If *that* directory has no permissions set, they will be inherited from another level up, and so on to the `desk`'s root directory. If the root directory has no permissions set, it will have the default permissions of an empty whitelist, meaning "deny all".
356+
357+A group is called a `crew` and is just a `set` of ships with a `@ta` name.
358+
359+The permissions for each file or directory are a pair of `dict:clay` where the head is read permissions and the tail is write permissions.
360+
361+A `dict:clay` is this structure:
362+
363+```hoon
364++$ dict [src=path rul=real] :: effective permission
365+```
366+
367+The `src` path is where the permissions were inherited from and the `real` is this structure:
368+
369+```hoon
370+ +$ real :: resolved permissions
371+ $: mod=?(%black %white) ::
372+ who=(pair (set ship) (map @ta crew)) ::
373+ == ::
374+```
375+
376+So if we scry for permissions with a `%p` `care`, it'll look like:
377+
378+```hoon
379+> .^([r=dict:clay w=dict:clay] %cp /===/lib/strandio/hoon)
380+[r=[src=/ rul=[mod=%white who=[p={} q={}]]] w=[src=/ rul=[mod=%white who=[p={} q={}]]]]
381+```
382+
383+There are four permission-related `task`s which you can pass to Clay.
384+
385+A `%perm` `task` is for setting permissions, and the other three are for managing groups:
386+
387+- `%cred` - Add permission group.
388+- `%crew` - Get permission groups.
389+- `%crow` - Get group usage.
390+
391+We'll look at each of these in turn.
392+
393+## `%perm`
394+
395+A `%perm` `task` sets permissions for the target file or directory.
396+
397+Note this will replace existing permissions rather than add to them, so if you want to add a ship to an existing whitelist or whatever you'll have to first read the existing permissions, add the ship, then send the whole lot back.
398+
399+### Accepts
400+
401+```hoon
402+[des=desk pax=path rit=rite]
403+```
404+
405+The `pax` path is the file or directory whose permissions you want to change, and the `rite` is this structure:
406+
407+```hoon
408++$ rite :: new permissions
409+ $% [%r red=(unit rule)] :: for read
410+ [%w wit=(unit rule)] :: for write
411+ [%rw red=(unit rule) wit=(unit rule)] :: for read and write
412+```
413+
414+Where a `rule` is this structure:
415+
416+```hoon
417++$ rule [mod=?(%black %white) who=(set whom)] :: node permission
418+```
419+
420+...and finally `whom` is this:
421+
422+```hoon
423++$ whom (each ship @ta) :: ship or named crew
424+```
425+
426+As the comment suggests, the `@ta` is the name of a `crew` (group).
427+
428+### Returns
429+
430+Clay does not return a `gift` in response to a `%perm` `task`.
431+
432+### Example
433+
434+[See here for an example of using %perm.](@/docs/arvo/clay/examples.md#perm)
435+
436+## `%cred`
437+
438+This simply creates a permission group.
439+
440+### Accepts
441+
442+```hoon
443+[nom=@ta cew=crew]
444+```
445+
446+The `nom` is a name for the group and the `crew` is just a `(set ship)`:
447+
448+```hoon
449++$ crew (set ship) :: permissions group
450+```
451+
452+### Returns
453+
454+Clay does not return a `gift` in response to a `%cred` `task`.
455+
456+### Example
457+
458+[See here for an example of using %cred.](@/docs/arvo/clay/examples.md#cred)
459+
460+## `%crew`
461+
462+This retrieves all permission groups.
463+
464+### Accepts
465+
466+```hoon
467+~
468+```
469+
470+A `%crew` `task` takes no arguments.
471+
472+### Returns
473+
474+Clay wil return a `%cruz` `gift`. It looks like:
475+
476+```hoon
477+[%cruz cez=(map @ta crew)] :: permission groups
478+```
479+
480+The `cez` is just a map from group name to `crew` which is just a `(set ship)`.
481+
482+### Example
483+
484+[See here for an example of using %crew.](@/docs/arvo/clay/examples.md#crew)
485+
486+## `%crow`
487+
488+A `%crow` `task` retrieves all files and directories in all `desk`s which have permissions set for the group in question. It will not return inherited permissions, only those explicitly set.
489+
490+### Accepts
491+
492+```hoon
493+nom=@ta
494+```
495+
496+The `nom` is the name of a `crew`.
497+
498+### Returns
499+
500+The `gift` you get back is a `%croz` which looks like:
501+
502+```hoon
503+[%croz rus=(map desk [r=regs w=regs])] :: rules for group
504+```
505+
506+...where `regs` is this structure:
507+
508+```hoon
509++$ regs (map path rule) :: rules for paths
510+```
511+
512+### Example
513+
514+[See here for an example of using %crow.](@/docs/arvo/clay/examples.md#crow)
515+
516+# Foreign Ships
517+
518+Here we'll looking at making Clay requests to a foreign ship.
519+
520+As it currently stands, it's not possible to write to a foreign `desk`. Additionally, remote scries are not implemented. That leaves requests to read files (`%warp`) and merge desks (`%merg`), which we'll look at next.
521+
522+## `%warp` - Remote
523+
524+To read files on a foreign `desk`, you just send Clay a `%warp` `task` (as you would for a local read) and specify the target ship in the `wer` field. For details on making such requests, see the [Read and Subscribe](#warp) section.
525+
526+Clay only allows a subset of `care`s to be used remotely. They are:
527+
528+- `%u` - Check for existence of file.
529+- `%v` - Get entire `dome:clay` state of a desk.
530+- `%w` - Get revision number.
531+- `%x` - Get data of file.
532+- `%y` - Get `arch` of file or directory.
533+- `%z` - Get content hash of file or directory.
534+
535+Any other `care` will crash with a `%clay-bad-foreign-request-care` error.
536+
537+The foreign ship will respond only if correct permissions have been set. See the [Permissions](#permissions) section for details.
538+
539+Note that if you're reading a whole `desk` or directory, all subfolders and files must also permit reading. If even a single file does not permit you reading it, the foreign ship will not respond to the request.
540+
541+### Example
542+
543+[See here for examples of requests to foreign ships.](@/docs/arvo/clay/examples.md#foreign-ships)
544+
545+## `%merg` - Remote
546+
547+To merge a foreign `desk` into a local one, you just send Clay a `%merg` `task` (as you would for a local merge) and specify the foreign ship in the `her` field. For details on making such requests, see the [Merge Desks](#merge-desks) section.
548+
549+The foreign ship will respond only if correct permissions have been set. See the [Permissions](#permissions) section for details. By default, a ship's `%kids` desk is set to be publicly readable, so unless permissions have been manually modified, you should be able to merge from any `%kids` `desk`.
550+
551+Note that all subfolders and individual files within the `desk` must permit your reading in order for the merge to succeed. If even one file does not permit you reading it, the remote ship will not respond to the request at all.
552+
553+### Example
554+
555+[See here for examples of requests to foreign ships.](@/docs/arvo/clay/examples.md#foreign-ships)
arvo/clay/using.md−4
@@ -49,10 +49,6 @@ from the start to the end triggers a response. Since a `%many`
4949request doesn't ask for any particular data, there aren't `%u`,
5050`%x`, and `%y` versions for it.
5151
52−For further information, see [Local Reads](@/docs/arvo/clay/local-reads.md),
53−[Local Subscriptions](@/docs/arvo/clay/local-sub.md), and [Foreign
54−Requests](@/docs/arvo/clay/foreign.md)
55−
5652### Unix sync
5753
5854Usage: