on master help sign in
34 files changed+4353−132
since splitsnapshots
unifiedsplit
.gitignore+8 INSTRUCTIONS.md+60 dev/elm-live.sh+6−1 frontend/assets/css/main.css+63 frontend/assets/img/logo.png frontend/assets/js/tilt.js+51 frontend/elm.json+24−3 frontend/index.html+9−7 frontend/src/Main.elm+178−107 zod/seax/app/seax.hoon+68−11 zod/seax/lib/engines.hoon+2−1 zod/seax/lib/engines/urbit-dev.hoon+29 zod/seax/lib/graph-store.hoon+919 zod/seax/lib/migrate.hoon+19 zod/seax/lib/rank.hoon+2−2 zod/seax/lib/resource.hoon+57 zod/seax/lib/strand.hoon+1 zod/seax/lib/strandio.hoon+812 zod/seax/sur/cite.hoon+57 zod/seax/sur/diary-0.hoon+323 zod/seax/sur/diary.hoon+335 zod/seax/sur/epic.hoon+15 zod/seax/sur/graph-store.hoon+272 zod/seax/sur/group-store.hoon+39 zod/seax/sur/group.hoon+109 zod/seax/sur/groups.hoon+364 zod/seax/sur/hark-store.hoon+159 zod/seax/sur/meta.hoon+21 zod/seax/sur/metadata-store.hoon+138 zod/seax/sur/notes.hoon+74 zod/seax/sur/post.hoon+91 zod/seax/sur/pull-hook.hoon+11 zod/seax/sur/resource.hoon+10 zod/seax/sur/spider.hoon+27
.gitignorenew file+8
@@ -0,0 +1,8 @@
1+frontend/elm-stuff
2+frontend/elm.js
3+zod/base
4+zod/.bin
5+zod/.http.ports
6+zod/.run
7+zod/.urb
8+zod/.vere.lock
INSTRUCTIONS.mdnew file+60
@@ -0,0 +1,60 @@
1+# Installation Instructions
2+
3+1. Create a folder and name it whatever you want.
4+
5+```bash
6+$ mkdir seax-project
7+$ cd seax-project
8+```
9+2. Inside the folder, `clone` the **airlock** library and the **seax** project.
10+
11+```bash
12+$ git clone https://github.com/ilyakooo0/airlock
13+$ git clone https://github.com/ilyakooo0/seax
14+```
15+3. Download the v2.11 pill.
16+
17+```bash
18+$ wget https://bootstrap.urbit.org/urbit-v2.11.pill
19+```
20+4. Start your fake zod using the pill.
21+
22+```bash
23+$ urbit -B urbit-v2.11.pill -F zod
24+```
25+
26+5. Now, inside dojo run the following:
27+```bash
28+dojo> |new-desk %seax
29+dojo> |mount %seax
30+```
31+
32+6. Back in your shell, run:
33+```bash
34+$ rm -r zod/seax
35+$ cp -r seax/zod/seax zod/seax
36+```
37+
38+7. In the dojo install the seax agent and allow cross-site origin requests from localhost.
39+```bash
40+dojo> |commit %seax
41+dojo> |install our %seax
42+dojo> |pass [%e [%approve-origin 'http://localhost:8000']]
43+```
44+
45+8. While your urbit is running in another terminal run:
46+```bash
47+$ ./seax/dev/elm-live.sh
48+```
49+The above command will start the frontend which communicates with your zod ship
50+using the Elm airlock library.
51+
52+Now, you can go to your browser at `http://localhost:8000/`.
53+The seax app should be displaying a search bar. You might need to refresh the page once before using the app.
54+You'll know that everything works if you see the "< ~zod: Opening airlock!" message in your dojo.
55+
56+# Usage Instructions
57+
58+Now, you can fill in the search bar with any term you like.
59+Clicking "search" will iniate collect any relevant results from the configured search sources.
60+In the results page, you can click on any of the sources to filter to only results from that source.
dev/elm-live.sh+6−1
@@ -4,4 +4,9 @@ set -e
44
55cd "$(dirname "$0")/../frontend"
66
7−nix run nixpkgs#elmPackages.elm-live -- src/Main.elm --start-page=index.html -- --debug --output=elm.js "$@"
7+if [[ -z $(command -v nix) ]] && [[ -z $(command -v elm-live) ]]; then
8+ echo "Please install either 'nix' or 'elm-live'" && exit 1
9+fi
10+
11+command -v nix && nix run nixpkgs#elmPackages.elm-live -- src/Main.elm --start-page=index.html -- --debug --output=elm.js "$@"
12+command -v elm-live && elm-live src/Main.elm --start-page=index.html -- --debug --output=elm.js "$@"
frontend/assets/css/main.cssnew file+63
@@ -0,0 +1,63 @@
1+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@200&family=Roboto+Mono:wght@200&family=Roboto:wght@300&display=swap');
2+
3+.button {
4+ border: none;
5+ color: white;
6+ padding: 15px 32px;
7+ text-align: center;
8+ text-decoration: none;
9+ font-size: 16px;
10+ display: inline-block;
11+ margin: 4px 2px;
12+ cursor: pointer;
13+ border-radius: 0;
14+ box-shadow: 0 2px 2px #888888;
15+}
16+
17+.shadow {
18+ shadow: 0 2px 2px #888888;
19+}
20+
21+.result {
22+}
23+
24+.result:hover {
25+ text-decoration: underline;
26+}
27+
28+.search:hover {
29+ text-decoration: underline;
30+}
31+
32+.wavy {
33+ animation-name: wavy;
34+ animation-duration: 4.2s;
35+ animation-timing-function: ease-in-out;
36+ animation-iteration-count: infinite;
37+ position: relative;
38+ top: 0;
39+ left: 0;
40+}
41+@keyframes wavy {
42+ 0% {
43+ top: 0px;
44+ }
45+ 50% {
46+ top: -15px;
47+ }
48+ 100% {
49+ top: 0px;
50+ }
51+}
52+
53+.result-link {
54+ color: #000;
55+ text-decoration: none;
56+ font-size: 12px !important;
57+}
58+
59+.result-title {
60+ color: #000;
61+ text-decoration: none;
62+ font-size: 16px;
63+}
frontend/assets/img/logo.pngnew file

Binary file not shown.

frontend/assets/js/tilt.jsnew file+51
@@ -0,0 +1,51 @@
1+/* Store the element in el */
2+let el = document.getElementById('tilt')
3+
4+/* Get the height and width of the element */
5+const height = el.clientHeight
6+const width = el.clientWidth
7+
8+/* Define function a */
9+function handleMove(e) {
10+
11+ if (el.id != 'tilt') return; /* TODO: Fix this hack. */
12+
13+ /*
14+ * Get position of mouse cursor
15+ * With respect to the element
16+ * On mouseover
17+ */
18+ /* Store the x position */
19+ const xVal = e.layerX
20+ /* Store the y position */
21+ const yVal = e.layerY
22+
23+ /*
24+ * Calculate rotation valuee along the Y-axis
25+ * Here the multiplier 20 is to
26+ * Control the rotation
27+ * You can change the value and see the results
28+ */
29+ const yRotation = 20 * ((xVal - width / 2) / width)
30+
31+ /* Calculate the rotation along the X-axis */
32+ const xRotation = -20 * ((yVal - height / 2) / height)
33+
34+ /* Generate string for CSS transform property */
35+ const string = 'perspective(500px) scale(1.0) rotateX(' + xRotation + 'deg) rotateY(' + yRotation + 'deg)'
36+
37+ /* Apply the calculated transformation */
38+ el.style.transform = string
39+}
40+
41+/* Add listener for mouseout event, remove the rotation */
42+el.addEventListener('mouseout', function() {
43+ el.style.transform = 'perspective(500px) scale(1) rotateX(0) rotateY(0)'
44+})
45+
46+/*
47+ * Add a listener for mousemove event
48+ * Which will trigger function 'handleMove'
49+ * On mousemove
50+ */
51+let mouseMoveEL = el.addEventListener('mousemove', handleMove)
frontend/elm.json+24−3
@@ -7,7 +7,9 @@
77 "elm-version": "0.19.1",
88 "dependencies": {
99 "direct": {
10+ "Evelios/elm-hash": "1.0.0",
1011 "TSFoster/elm-bytes-extra": "1.3.0",
12+ "avh4/elm-color": "1.0.0",
1113 "cmditch/elm-bigint": "2.0.1",
1214 "elm/browser": "1.0.2",
1315 "elm/bytes": "1.0.8",
@@ -20,25 +22,44 @@
2022 "elm/url": "1.0.0",
2123 "elm-community/list-extra": "8.7.0",
2224 "elm-community/maybe-extra": "5.3.0",
25+ "elm-community/string-extra": "4.0.1",
2326 "figbus/elm-urbit-api": "4.0.1",
27+ "hecrj/html-parser": "2.4.0",
28+ "ianmackenzie/elm-1d-parameter": "1.0.1",
29+ "ianmackenzie/elm-3d-camera": "3.1.0",
30+ "ianmackenzie/elm-3d-scene": "1.0.1",
31+ "ianmackenzie/elm-geometry": "3.11.0",
32+ "ianmackenzie/elm-triangular-mesh": "1.1.0",
33+ "ianmackenzie/elm-units": "2.10.0",
2434 "jasonliang-dev/elm-heroicons": "2.0.0",
2535 "jxxcarlson/hex": "4.0.0",
36+ "marcosh/elm-html-to-unicode": "1.0.4",
2637 "mdgriffith/elm-animator": "1.1.1",
2738 "mdgriffith/elm-ui": "1.1.8",
39+ "rtfeldman/elm-css": "18.0.0",
2840 "rtfeldman/elm-hex": "1.0.0",
29− "toastal/either": "3.6.3"
41+ "toastal/either": "3.6.3",
42+ "zwilias/elm-html-string": "2.0.2"
3043 },
3144 "indirect": {
3245 "AdrianRibao/elm-derberos-date": "1.2.3",
33− "avh4/elm-color": "1.0.0",
46+ "NoRedInk/elm-string-conversions": "1.0.1",
3447 "bitsoflogic/elm-radixint": "2.0.0",
48+ "bonzaico/murmur3": "1.0.0",
49+ "chain-partners/elm-bignum": "1.0.1",
3550 "elm/file": "1.0.5",
3651 "elm/parser": "1.1.0",
3752 "elm/random": "1.0.0",
3853 "elm/regex": "1.0.0",
3954 "elm/virtual-dom": "1.0.3",
40− "ianmackenzie/elm-units": "2.10.0",
55+ "elm-explorations/linear-algebra": "1.0.3",
56+ "elm-explorations/webgl": "1.1.3",
57+ "ianmackenzie/elm-float-extra": "1.1.0",
58+ "ianmackenzie/elm-geometry-linear-algebra-interop": "2.0.2",
59+ "ianmackenzie/elm-interval": "3.1.0",
60+ "ianmackenzie/elm-units-interval": "3.2.0",
4161 "ktonon/elm-word": "2.1.2",
62+ "myrho/elm-round": "1.0.5",
4263 "robinheghan/murmur3": "1.0.0"
4364 }
4465 },
frontend/index.html+9−7
@@ -2,23 +2,24 @@
22<html lang="en">
33 <head>
44 <meta charset="UTF-8" />
5+ <link rel="stylesheet" href="assets/css/main.css" >
56 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
67 <style>
78 body {
8− font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
99 margin: 0;
1010 }
11− @keyframes bobbing {
11+ @keyframes shimmer {
1212 from {
13− transform: translateY(-30px);
13+ color: rgb(204, 204, 204)
1414 }
1515 to {
16− transform: traslateY(0);
16+ color: rgb(50, 50, 50)
1717 }
1818 }
19− .bobbing {
20− animation-duration: 2s;
21− animation-name: bobbing;
19+
20+ .shimmer {
21+ animation-duration: 0.6s;
22+ animation-name: shimmer;
2223 animation-iteration-count: infinite;
2324 animation-direction: alternate;
2425 animation-timing-function: ease-in-out;
@@ -30,5 +31,6 @@
3031 <script src="/elm.js"></script>
3132 <script type="module" src="/script.js"></script>
3233 </body>
34+ <script type="text/javascript" src="assets/js/tilt.js" defer></script>
3335</html>
3436
frontend/src/Main.elm+178−107
@@ -10,10 +10,19 @@ import Element.Events as Events exposing (onClick)
1010import Element.Font as Font
1111import Element.Input as Input
1212import Element.Keyed as Keyed
13+import Html exposing (Html, hr)
1314import Html.Attributes
15+import Html.Parser
16+import Html.String
17+import Html.String
18+import Html.Styled.Attributes exposing (css)
19+import Html.Styled.Attributes exposing (css)
20+import Html.Events exposing (on)
1421import Json.Decode as JD
22+import List
1523import List.Extra
1624import Set exposing (Set)
25+import String.Extra exposing (stripTags)
1726import Time exposing (Posix)
1827import Ur
1928import Ur.Cmd
@@ -22,7 +31,10 @@ import Ur.Jam exposing (isSig)
2231import Ur.Run
2332import Ur.Sub
2433import Ur.Types exposing (Noun(..))
25−
34+import Url
35+import ElmEscapeHtml
36+import Json.Encode
37+import Hash
2638
2739url : String
2840url =
@@ -61,7 +73,6 @@ type alias SearchResult =
6173 , engines : Set String
6274 }
6375
64−
6576type Msg
6677 = Noop
6778 | GotShipName String
@@ -79,7 +90,7 @@ main =
7990 { init =
8091 ( { ship = Nothing
8192 , search = ""
82− , initiatedSearch = Just "urbit"
93+ , initiatedSearch = Nothing
8394 , searchResults = []
8495 , resultTimelines = Dict.empty
8596 , engines = []
@@ -93,7 +104,27 @@ main =
93104 |> Ur.Cmd.cmd
94105 )
95106 , update = update
96− , view = \model -> { title = "%seax", body = [ view model |> layout [] ] }
107+ , view =
108+ \model ->
109+ { title = "%seax"
110+ , body =
111+ [ view model
112+ |> layout
113+ [ Font.family
114+ [ Font.typeface "monospace"
115+ , Font.typeface "system-ui"
116+ , Font.typeface "-apple-system"
117+ , Font.typeface "BlinkMacSystemFont"
118+ , Font.typeface "Segoe UI"
119+ , Font.typeface "Roboto"
120+ , Font.typeface "Helvetica"
121+ , Font.typeface "Arial"
122+ , Font.sansSerif
123+ ]
124+ , clipX
125+ ]
126+ ]
127+ }
97128 , subscriptions = \model -> Animator.toSubscription Tick model (animator model)
98129 , createEventSource = createEventSource
99130 , urbitSubscriptions =
@@ -128,40 +159,51 @@ main =
128159 }
129160
130161
131−debug : (String -> String) -> D.Deconstructor a -> D.Deconstructor a
132−debug log f noun =
133− case f noun of
134− Just x ->
135− Just x
136−
137− Nothing ->
138− let
139− _ =
140− log (prettyNoun noun)
141− in
142− Nothing
143−
144−
145−prettyNoun : Noun -> String
146−prettyNoun noun =
147− let
148− go isRhs n =
149− case n of
150− Atom a ->
151− if isSig a then
152− "~"
162+logoView : List (Attribute Msg) -> Element Msg
163+logoView attributes =
164+ Element.image (List.append [ Html.Attributes.id "tilt" |> htmlAttribute ] attributes)
165+ { src = "assets/img/logo.png", description = "%seax logo" }
153166
154− else
155− "@"
167+noSearchResultsView : Element Msg
168+noSearchResultsView = Element.el
169+ [ Html.Attributes.style "padding" "1em" |> htmlAttribute
170+ , width (px 500)
171+ , Font.size 15
172+ , Html.Attributes.class "wavy" |> htmlAttribute
173+ ]
174+ (Element.text """No results found... :)
175+We'll try and find you something.
176+Just come back later.""")
177+
178+subtleLinkView : String -> String -> Element Msg
179+subtleLinkView text href =
180+ Element.el
181+ [ Font.size 15
182+ , pointer
183+ , mouseOver
184+ [ Font.color (rgb 0.1 0.7 0.7)
185+ ]
186+ ]
187+ (Element.html (Html.a [ Html.Attributes.href href ] [ Html.text text ]))
156188
157− Cell ( lhs, rhs ) ->
158− if isRhs then
159− go False lhs ++ " " ++ go True rhs
189+aboutView : Element Msg
190+aboutView = row [ centerX, padding 10, spacing 10]
191+ [ subtleLinkView "[About]" "https://vagos.github.io/seax"
192+ , subtleLinkView "[Code]" "https://github.com/ilyakooo0/seax"
193+ ]
160194
161− else
162− "[" ++ go False lhs ++ " " ++ go True rhs ++ "]"
163− in
164− go False noun
195+titleEmoji : String -> String
196+titleEmoji title =
197+ let maxUnicode = 0x1F3F0
198+ minUnicode = 0x1F300
199+ in title |> Hash.fromString
200+ |> Hash.toString
201+ |> String.toInt
202+ |> Maybe.withDefault 0
203+ |> (\x -> ((modBy (maxUnicode - minUnicode) x) + minUnicode))
204+ |> Char.fromCode
205+ |> String.fromChar
206+ |> (\x -> x ++ " ")
165207
166208
167209view : Model -> Element Msg
@@ -169,61 +211,66 @@ view model =
169211 case model.initiatedSearch of
170212 Nothing ->
171213 column [ centerX, centerY, padding 8, spacing 16 ]
172− [ el [ centerX, Font.size 67, Font.heavy ] (text "%seax")
214+ [ logoView [ centerX, width (px 510), height (px 161) ]
173215 , searchView model
216+ , aboutView
174217 ]
175218
176− Just query ->
219+ Just _ ->
177220 column [ width fill, spacing 16 ]
178− [ row [ spacing 16, width fill ]
179− [ searchView model |> el [ padding 8 ]
180− , model.engines
181− |> List.filter (\( _, state ) -> state /= Failed)
182− |> List.map
183− (\( name, state ) ->
184− text ("%" ++ name)
185− |> el
186− ([ Font.size 43
187− , Font.bold
188− ]
189− ++ (if Set.isEmpty model.selectedEngines then
190− []
191−
192− else if Set.member name model.selectedEngines then
193− []
221+ [ column [ spacing 16, width (minimum 0 fill), padding 8]
222+ [ row [] [ logoView [height (px 40)], searchView model |> el [] ]
223+ , row [ spacing 8, paddingEach { top = 16, bottom = 16, left = 0, right = 0 } ]
224+ (if List.isEmpty model.engines then
225+ []
226+ else
227+ [ text "Sources: "
228+ , model.engines
229+ |> List.filter (\( _, state ) -> state /= Failed)
230+ |> List.map
231+ (\( name, state ) ->
232+ text ("%" ++ name)
233+ |> el
234+ (Font.bold
235+ :: (if Set.isEmpty model.selectedEngines then
236+ []
194237
195− else
196− [ Font.color (rgb 0.8 0.8 0.8)
197− ]
198− )
199− ++ (case state of
200− Loading ->
201− [ Html.Attributes.class "bobbing" |> htmlAttribute
202− , Font.color (rgb 0.8 0.8 0.8)
238+ else if Set.member name model.selectedEngines then
239+ []
240+
241+ else
242+ [ Font.color (rgb 0.8 0.8 0.8)
203243 ]
244+ )
245+ ++ (case state of
246+ Loading ->
247+ [ Html.Attributes.class "shimmer" |> htmlAttribute
248+ ]
204249
205− Completed ->
206− [ mouseOver
207− [ Font.color (rgb 0.6 0.6 0.6)
250+ Completed ->
251+ [ mouseOver
252+ [ Font.color (rgb 0.6 0.6 0.6)
253+ ]
254+ , pointer
255+ , Events.onClick (ToggleSearchEngine name)
208256 ]
209− , pointer
210− , Events.onClick (ToggleSearchEngine name)
211− ]
212257
213− Failed ->
214− []
215− )
216− )
217− )
218− |> row
219− [ spacing 16
220− , clipX
221− , scrollbarX
222− , width fill
223− , height (px 62)
224− ]
258+ Failed ->
259+ []
260+ )
261+ )
262+ )
263+ |> wrappedRow
264+ [ spacing 8
265+ , width fill
266+ ]
267+ ]
268+ )
225269 ]
226− , Keyed.column [ width fill, padding 8 ]
270+ , (if List.isEmpty model.searchResults then
271+ noSearchResultsView
272+ else
273+ Keyed.column [ width (minimum 0 fill), padding 8 ]
227274 (model.searchResults
228275 |> List.filter
229276 (\{ engines } ->
@@ -238,7 +285,7 @@ view model =
238285 ( link
239286 , column
240287 [ spacing 4
241− , width fill
288+ , width (minimum 0 fill)
242289 , pointer
243290 , alpha
244291 (Animator.move
@@ -260,38 +307,70 @@ view model =
260307 |> Maybe.map Tuple.first
261308 |> Maybe.withDefault (Animator.init 0)
262309 )
263− (\i -> toFloat i * 47 |> Animator.at)
310+ (\i -> toFloat i * 0 |> Animator.at)
264311 |> String.fromFloat
265312 )
266313 ++ "px"
267314 )
268315 |> htmlAttribute
269− , Html.Attributes.style "position" "absolute" |> htmlAttribute
316+ , Html.Attributes.style "margin-bottom" "1em" |> htmlAttribute
317+ , Html.Attributes.style "padding" "0.5em" |> htmlAttribute
318+ , Html.Attributes.class "result" |> htmlAttribute
270319 ]
271− [ [ text title ]
272− |> paragraph
273− [ Font.size 16
274− , width fill
275− , Html.Attributes.style "text-overflow" "ellipsis" |> htmlAttribute
320+ [ (Element.html
321+ (Html.a
322+ [ Html.Attributes.href link
323+ , Html.Attributes.class "result-title"
324+ , Html.Attributes.target "_blank"
276325 ]
277− , [ text link ]
278− |> paragraph
279− [ Font.size 12
280− , Html.Attributes.style "text-overflow" "ellipsis" |> htmlAttribute
281− , width fill
282− , Font.color (rgb 0.7 0.7 0.7)
326+ [ Html.text
327+ (Maybe.withDefault ""
328+ (Url.percentDecode
329+ (ElmEscapeHtml.unescape
330+ (stripTags
331+ ((titleEmoji title) ++ title)
332+ ))))
333+ ]
334+ )
335+ )
336+ , text link
337+ |> el
338+ [ Font.color (rgb 0.7 0.7 0.7)
339+ , Html.Attributes.class "result-link" |> htmlAttribute
283340 ]
284341 ]
285342 )
286343 )
287− )
344+ ))
345+ , Element.html (Html.hr [Html.Attributes.style "width" "95%"] [])
346+ , aboutView
288347 ]
289348
290349
350+onEnter : msg -> Element.Attribute msg
351+onEnter msg =
352+ Element.htmlAttribute
353+ (Html.Events.on "keyup"
354+ (JD.field "key" JD.string
355+ |> JD.andThen
356+ (\key ->
357+ if key == "Enter" then
358+ JD.succeed msg
359+
360+ else
361+ JD.fail "Not the enter key"
362+ )
363+ )
364+ )
365+
366+
291367searchView : { a | search : String } -> Element Msg
292368searchView model =
293369 row [ spacing 8 ]
294− [ Input.text [ width (px 250) ]
370+ [ Input.text
371+ [ Html.Attributes.class "shadow" |> htmlAttribute, width (px 400)
372+ , onEnter (Search model.search)
373+ ]
295374 { onChange = UpdateSearch
296375 , placeholder = Nothing
297376 , text = model.search
@@ -301,23 +380,15 @@ searchView model =
301380 { label =
302381 text "search"
303382 |> el
304− [ Border.width 4
305− , padding 4
383+ [ Html.Attributes.class "search" |> htmlAttribute
384+ , Border.width 2
385+ , padding 6
306386 , Font.size 29
307− , Font.bold
308− , Border.color (rgb 0 0 0)
309− , Background.color (rgb 0 0 0)
310− , Font.color (rgb 1 1 1)
311− , mouseOver
312− [ Font.color (rgb 0 0 0)
313− , Background.color (rgb 1 1 1)
314− ]
315387 ]
316388 , onPress = Just (Search model.search)
317389 }
318390 ]
319391
320−
321392update : Msg -> Model -> ( Model, Ur.Cmd.Cmd Msg )
322393update msg model =
323394 case msg of
zod/seax/app/seax.hoon+68−11
@@ -1,6 +1,6 @@
11/- *seax
2−/+ dbug, engines, rank, sink
3−
2+/- diary
3+/+ dbug, engines, rank, sink, strandio
44|%
55+$ query cord
66+$ search-state
@@ -10,11 +10,15 @@ $:
1010==
1111+$ state-0
1212$:
13+ notes=shelf:diary
1314 search-subscriptions=(map query search-state)
15+ peers=_(silt ~[~zod ~racfer-hattes])
16+ alive-peers=(set @p)
1417==
1518+$ poke
1619 $%
17− [%search query=tape]
20+ [%add-peers (set @p)]
21+ [%get-notes ~]
1822 ==
1923++ rank-results
2024 |= search-results=(map term (unit (list search-result)))
@@ -39,6 +43,8 @@ $:
3943 ^- task:iris
4044 [%request [%'GET' (crip (url.engine (trip query))) ~ ~] *outbound-config:iris]
4145 [%pass ~[%search-result query engine-name] %arvo %i req]
46+ ++ liveness-interval ~s30
47+ ++ gossip-interval ~s30
4248--
4349
4450=/ state *state-0
@@ -52,6 +58,7 @@ $:
5258 (~(get by search-results:(~(got by search-subscriptions.state) query)) engine)
5359 ?~ results %loading
5460 ?~ +.results %failed
61+ ?~ +>.results %failed
5562 %completed
5663=* search-results
5764 |= =query
@@ -70,7 +77,10 @@ $:
7077%- agent:dbug
7178|_ =bowl:gall
7279+* this .
73−++ on-init `..on-init
80+ liveness-behn-card [%pass /check-liveness %arvo %b %wait (add now.bowl liveness-interval)]
81+ gossip-behn-card [%pass /gossip %arvo %b %wait (add now.bowl gossip-interval)]
82+++ on-init
83+ [~[liveness-behn-card gossip-behn-card] this]
7484++ on-save !>(state)
7585++ on-load
7686 |= =vase
@@ -80,10 +90,16 @@ $:
8090 state state
8191 ==
8292++ on-poke
83− |= =cage
93+ |= [=mark =vase]
8494 ^- (quip card:agent:gall _this)
85− `this
86−
95+ =/ poke !<(poke vase)
96+ ~& poke
97+ ?- -.poke
98+ %add-peers
99+ [~ this(peers.state (~(put in (~(uni in peers.state) +.poke)) src.bowl))]
100+ %get-notes
101+ `this(notes.state .^(shelf:diary %gx /(scot %p our.bowl)/diary/(scot %da now.bowl)/shelf/noun))
102+ ==
87103++ on-watch
88104 |= =path
89105 ?+ path !!
@@ -102,13 +118,22 @@ $:
102118 =. search-subscriptions.state
103119 (~(put by search-subscriptions.state) query subscription)
104120 [~[flush:(sink query)] this]
121+ [%ping ~]
122+ ~& path
123+ :-
124+ :~
125+ [%give %fact ~ %noun !>(%pong)]
126+ [%give %kick ~ ~]
127+ ==
128+ this
129+
105130 ==
106131
107132:: This was not tested because it requires waiting 12 hours.
108133++ on-leave
109134 |= =path
110− ?+ path !!
111− [%search query ~]
135+ ?+ path `this
136+ [%search query ~]
112137 =/ query +<.path
113138 ~& path
114139 =/ search-state (~(got by search-subscriptions.state) query)
@@ -123,7 +148,17 @@ $:
123148++ on-peek
124149 |= path
125150 ~
126−++ on-agent |=([wire sign:agent:gall] !!)
151+++ on-agent
152+ |= [=wire =sign:agent:gall]
153+ ?+ wire `this
154+ [%alive ~]
155+ ?+ -.sign `this
156+ %fact
157+ ~& "{<src.bowl>} is alive"
158+ =. alive-peers.state (~(put in alive-peers.state) src.bowl)
159+ `this
160+ ==
161+ ==
127162++ on-arvo
128163 |= [=wire =sign-arvo]
129164 ^- (quip card:agent:gall _this)
@@ -145,8 +180,30 @@ $:
145180 =. search-subscriptions.state
146181 (~(put by search-subscriptions.state) query search-subscription)
147182 =^ card sink (sync:sink (sink-for-query query))
183+ ~& (current-engines query)
148184 [~[card] this]
185+ [%check-liveness ~]
186+ =/ checks
187+ %+ turn ~(tap in peers.state)
188+ |= peer=@p
189+ [%pass /alive %agent [peer %seax] %watch /ping]
190+ =. peers.state alive-peers.state
191+ =. alive-peers.state *(set @p)
192+ =/ timer
193+ liveness-behn-card
194+ :-
195+ [timer checks]
196+ this
197+ [%gossip ~]
198+ :-
199+ :- gossip-behn-card
200+ %+ turn ~(tap in peers.state)
201+ |= peer=@p
202+ [%pass / %agent [peer %seax] %poke %noun !>([%add-peers peers.state])]
203+ this
149204 ==
150−++ on-fail |=([term tang] `..on-init)
205+++ on-fail
206+ |= [term =tang]
207+ ((slog tang) `this)
151208--
152209
zod/seax/lib/engines.hoon+2−1
@@ -1,5 +1,5 @@
11/- *seax
2−/+ engines-yep, engines-crowdview, engines-wiby, engines-alexandria
2+/+ engines-yep, engines-crowdview, engines-wiby, engines-alexandria, engines-urbit-dev
33
44^- engines
55
@@ -10,5 +10,6 @@
1010 [name=%crowdview engine=engines-crowdview weight=.2]
1111 [name=%wiby engine=engines-wiby weight=.2]
1212 [name=%alexandria engine=engines-alexandria weight=.2]
13+ [name=%urbit-dev engine=engines-urbit-dev weight=.2]
1314==
1415
zod/seax/lib/engines/urbit-dev.hoonnew file+29
@@ -0,0 +1,29 @@
1+/- *seax
2+
3+^- engine
4+=<
5+|%
6+++ url
7+ |= query=tape
8+ ^- tape
9+ %+ weld
10+ "https://urbit.org/api/dev-search?q="
11+ (en-urlt:html query)
12+++ results
13+ |= response=mime-data:iris
14+ ^- (unit (list search-result))
15+ =/ body q.data.response
16+ ;< jon=json _biff (de:json:html body)
17+ (apex jon)
18+--
19+::
20+|%
21+++ apex
22+ =, dejs-soft:format
23+ %- ot
24+ ~[glossary+(ar parse-search-result)]
25+++ parse-search-result
26+ =, dejs-soft:format
27+ %- ot
28+ ~[[%'name' so] [%'url' so]]
29+--
zod/seax/lib/graph-store.hoonnew file+919
@@ -0,0 +1,919 @@
1+/- sur=graph-store, pos=post, pull-hook, hark=hark-store
2+/+ res=resource, migrate
3+=< [sur .]
4+=< [pos .]
5+=, sur
6+=, pos
7+|%
8+++ hark-content
9+ |= =content
10+ ^- content:hark
11+ ?- -.content
12+ %text content
13+ %mention ship+ship.content
14+ %url text+url.content
15+ %code text+'A code excerpt'
16+ %reference text+'A reference'
17+ ==
18+::
19+++ hark-contents
20+ |= cs=(list content)
21+ (turn cs hark-content)
22+:: NOTE: move these functions to zuse
23+++ nu :: parse number as hex
24+ |= jon=json
25+ ?> ?=([%s *] jon)
26+ (rash p.jon hex)
27+::
28+++ re :: recursive reparsers
29+ |* [gar=* sef=_|.(fist:dejs-soft:format)]
30+ |= jon=json
31+ ^- (unit _gar)
32+ =- ~! gar ~! (need -) -
33+ ((sef) jon)
34+::
35+++ dank :: tank
36+ ^- $-(json (unit tank))
37+ =, ^? dejs-soft:format
38+ %+ re *tank |. ~+
39+ %- of :~
40+ leaf+sa
41+ palm+(ot style+(ot mid+sa cap+sa open+sa close+sa ~) lines+(ar dank) ~)
42+ rose+(ot style+(ot mid+sa open+sa close+sa ~) lines+(ar dank) ~)
43+ ==
44+::
45+++ orm ((on atom node) gth)
46+++ orm-log ((on time logged-update) gth)
47+::
48+++ enjs
49+ =, enjs:format
50+ |%
51+ ::
52+ ++ signatures
53+ |= s=^signatures
54+ ^- json
55+ [%a (turn ~(tap in s) signature)]
56+ ::
57+ ++ signature
58+ |= s=^signature
59+ ^- json
60+ %- pairs
61+ :~ [%signature s+(scot %ux p.s)]
62+ [%ship (ship q.s)]
63+ [%life (numb r.s)]
64+ ==
65+ ::
66+ ++ index
67+ |= ind=^index
68+ ^- json
69+ :- %s
70+ ?: =(~ ind)
71+ '/'
72+ %+ roll ind
73+ |= [cur=@ acc=@t]
74+ ^- @t
75+ =/ num (numb cur)
76+ ?> ?=(%n -.num)
77+ (rap 3 acc '/' p.num ~)
78+ ::
79+ ++ uid
80+ |= u=^uid
81+ ^- json
82+ %- pairs
83+ :~ [%resource (enjs:res resource.u)]
84+ [%index (index index.u)]
85+ ==
86+ ::
87+ ++ content
88+ |= c=^content
89+ ^- json
90+ ?- -.c
91+ %mention (frond %mention (ship ship.c))
92+ %text (frond %text s+text.c)
93+ %url (frond %url s+url.c)
94+ %reference (frond %reference (reference +.c))
95+ %code
96+ %+ frond %code
97+ %- pairs
98+ :- [%expression s+expression.c]
99+ :_ ~
100+ :- %output
101+ :: virtualize output rendering, +tank:enjs:format might crash
102+ ::
103+ =/ result=(each (list json) tang)
104+ (mule |.((turn output.c tank)))
105+ ?- -.result
106+ %& a+p.result
107+ %| a+[a+[%s '[[output rendering error]]']~]~
108+ ==
109+ ==
110+ ::
111+ ++ reference
112+ |= ref=^reference
113+ |^
114+ %+ frond -.ref
115+ ?- -.ref
116+ %graph (graph +.ref)
117+ %group (group +.ref)
118+ %app (app +.ref)
119+ ==
120+ ::
121+ ++ graph
122+ |= [grp=res gra=res idx=^index]
123+ %- pairs
124+ :~ graph+s+(enjs-path:res gra)
125+ group+s+(enjs-path:res grp)
126+ index+(index idx)
127+ ==
128+ ::
129+ ++ group
130+ |= grp=res
131+ s+(enjs-path:res grp)
132+ ::
133+ ++ app
134+ |= [=^ship =desk p=^path]
135+ %- pairs
136+ :~ ship+s+(scot %p ship)
137+ desk+s+desk
138+ path+(path p)
139+ ==
140+ --
141+ ::
142+ ++ maybe-post
143+ |= mp=^maybe-post
144+ ^- json
145+ ?- -.mp
146+ %| s+(scot %ux p.mp)
147+ %& (post p.mp)
148+ ==
149+ ::
150+ ++ post
151+ |= p=^post
152+ ^- json
153+ %- pairs
154+ :~ [%author (ship author.p)]
155+ [%index (index index.p)]
156+ [%time-sent (time time-sent.p)]
157+ [%contents [%a (turn contents.p content)]]
158+ [%hash ?~(hash.p ~ s+(scot %ux u.hash.p))]
159+ [%signatures (signatures signatures.p)]
160+ ==
161+ ::
162+ ++ update
163+ |= upd=^update
164+ ^- json
165+ |^ (frond %graph-update (pairs ~[(encode q.upd)]))
166+ ::
167+ ++ encode
168+ |= upd=action
169+ ^- [cord json]
170+ ?- -.upd
171+ %add-graph
172+ :- %add-graph
173+ %- pairs
174+ :~ [%resource (enjs:res resource.upd)]
175+ [%graph (graph graph.upd)]
176+ [%mark ?~(mark.upd ~ s+u.mark.upd)]
177+ [%overwrite b+overwrite.upd]
178+ ==
179+ ::
180+ %remove-graph
181+ [%remove-graph (enjs:res resource.upd)]
182+ ::
183+ %add-nodes
184+ :- %add-nodes
185+ %- pairs
186+ :~ [%resource (enjs:res resource.upd)]
187+ [%nodes (nodes nodes.upd)]
188+ ==
189+ ::
190+ %remove-posts
191+ :- %remove-posts
192+ %- pairs
193+ :~ [%resource (enjs:res resource.upd)]
194+ [%indices (indices indices.upd)]
195+ ==
196+ ::
197+ %add-signatures
198+ :- %add-signatures
199+ %- pairs
200+ :~ [%uid (uid uid.upd)]
201+ [%signatures (signatures signatures.upd)]
202+ ==
203+ ::
204+ %remove-signatures
205+ :- %remove-signatures
206+ %- pairs
207+ :~ [%uid (uid uid.upd)]
208+ [%signatures (signatures signatures.upd)]
209+ ==
210+ ::
211+ %add-tag
212+ :- %add-tag
213+ %- pairs
214+ :~ [%term s+term.upd]
215+ [%uid (uid uid.upd)]
216+ ==
217+ ::
218+ %remove-tag
219+ :- %remove-tag
220+ %- pairs
221+ :~ [%term s+term.upd]
222+ [%uid (uid uid.upd)]
223+ ==
224+ ::
225+ %archive-graph
226+ [%archive-graph (enjs:res resource.upd)]
227+ ::
228+ %unarchive-graph
229+ [%unarchive-graph (enjs:res resource.upd)]
230+ ::
231+ %keys
232+ [%keys [%a (turn ~(tap in resources.upd) enjs:res)]]
233+ ::
234+ %tags
235+ [%tags [%a (turn ~(tap in tags.upd) |=(=term s+term))]]
236+ ::
237+ %run-updates
238+ [%run-updates ~]
239+ ::
240+ %tag-queries
241+ :- %tag-queries
242+ %- pairs
243+ %+ turn ~(tap by tag-queries.upd)
244+ |= [=term uids=(set ^uid)]
245+ ^- [cord json]
246+ [term [%a (turn ~(tap in uids) uid)]]
247+ ==
248+ ::
249+ ++ graph
250+ |= g=^graph
251+ ^- json
252+ %- pairs
253+ %+ turn
254+ (tap:orm g)
255+ |= [a=atom n=^node]
256+ ^- [@t json]
257+ :_ (node n)
258+ =/ idx (numb a)
259+ ?> ?=(%n -.idx)
260+ p.idx
261+ ::
262+ ++ node
263+ |= n=^node
264+ ^- json
265+ %- pairs
266+ :~ [%post (maybe-post post.n)]
267+ :- %children
268+ ?- -.children.n
269+ %empty ~
270+ %graph (graph +.children.n)
271+ ==
272+ ==
273+ ::
274+ ++ nodes
275+ |= m=(map ^index ^node)
276+ ^- json
277+ %- pairs
278+ %+ turn ~(tap by m)
279+ |= [n=^index o=^node]
280+ ^- [@t json]
281+ :_ (node o)
282+ =/ idx (index n)
283+ ?> ?=(%s -.idx)
284+ p.idx
285+ ::
286+ ++ indices
287+ |= i=(set ^index)
288+ ^- json
289+ [%a (turn ~(tap in i) index)]
290+ ::
291+ --
292+ --
293+::
294+++ dejs
295+ =, dejs:format
296+ |%
297+ ++ update
298+ |= jon=json
299+ ^- ^update
300+ :- *time
301+ ^- action
302+ =< (decode jon)
303+ |%
304+ ++ decode
305+ %- of
306+ :~ [%add-nodes add-nodes]
307+ [%remove-posts remove-posts]
308+ [%add-signatures add-signatures]
309+ [%remove-signatures remove-signatures]
310+ ::
311+ [%add-graph add-graph]
312+ [%remove-graph remove-graph]
313+ ::
314+ [%add-tag add-tag]
315+ [%remove-tag remove-tag]
316+ ::
317+ [%archive-graph archive-graph]
318+ [%unarchive-graph unarchive-graph]
319+ [%run-updates run-updates]
320+ ::
321+ [%keys keys]
322+ [%tags tags]
323+ [%tag-queries tag-queries]
324+ ==
325+ ::
326+ ++ add-graph
327+ %- ot
328+ :~ [%resource dejs:res]
329+ [%graph graph]
330+ [%mark (mu so)]
331+ [%overwrite bo]
332+ ==
333+ ::
334+ ++ graph
335+ |= a=json
336+ ^- ^graph
337+ =/ or-mp ((on atom ^node) gth)
338+ %+ gas:or-mp ~
339+ %+ turn ~(tap by ((om node) a))
340+ |* [b=cord c=*]
341+ ^- [atom ^node]
342+ => .(+< [b c]=+<)
343+ [(rash b dem) c]
344+ ::
345+ ++ remove-graph (ot [%resource dejs:res]~)
346+ ++ archive-graph (ot [%resource dejs:res]~)
347+ ++ unarchive-graph (ot [%resource dejs:res]~)
348+ ::
349+ ++ add-nodes
350+ %- ot
351+ :~ [%resource dejs:res]
352+ [%nodes nodes]
353+ ==
354+ ::
355+ ++ nodes (op ;~(pfix fas (more fas dem)) node)
356+ ::
357+ ++ node
358+ %- ot
359+ :~ [%post maybe-post]
360+ [%children internal-graph]
361+ ==
362+ ::
363+ ++ internal-graph
364+ |= jon=json
365+ ^- ^internal-graph
366+ ?~ jon
367+ [%empty ~]
368+ [%graph (graph jon)]
369+ ::
370+ ++ maybe-post
371+ |= jon=json
372+ ^- ^maybe-post
373+ ?~ jon !!
374+ ?+ -.jon !!
375+ %s [%| (nu jon)]
376+ %o [%& (post jon)]
377+ ==
378+ ::
379+ ++ post
380+ %- ot
381+ :~ [%author (su ;~(pfix sig fed:ag))]
382+ [%index index]
383+ [%time-sent di]
384+ [%contents (ar content)]
385+ [%hash (mu nu)]
386+ [%signatures (as signature)]
387+ ==
388+ ::
389+ ++ content
390+ %- of
391+ :~ [%mention (su ;~(pfix sig fed:ag))]
392+ [%text so]
393+ [%url so]
394+ [%reference reference]
395+ [%code eval]
396+ ==
397+ ::
398+ ++ reference
399+ |^
400+ %- of
401+ :~ graph+graph
402+ group+dejs-path:res
403+ app+app
404+ ==
405+ ::
406+ ++ graph
407+ %- ot
408+ :~ group+dejs-path:res
409+ graph+dejs-path:res
410+ index+index
411+ ==
412+ ::
413+ ++ app
414+ %- ot
415+ :~ ship+(su ;~(pfix sig fed:ag))
416+ desk+so
417+ path+pa
418+ ==
419+ --
420+ ::
421+ ++ tang
422+ |= jon=^json
423+ ^- ^tang
424+ ?> ?=(%a -.jon)
425+ %- zing
426+ %+ turn
427+ p.jon
428+ |= jo=^json
429+ ^- (list tank)
430+ ?> ?=(%a -.jo)
431+ %+ turn
432+ p.jo
433+ |= j=^json
434+ ?> ?=(%s -.j)
435+ ^- tank
436+ leaf+(trip p.j)
437+ ::
438+ ++ eval
439+ %- ot
440+ :~ expression+so
441+ output+tang
442+ ==
443+ ::
444+ ++ remove-posts
445+ %- ot
446+ :~ [%resource dejs:res]
447+ [%indices (as index)]
448+ ==
449+ ::
450+ ++ add-signatures
451+ %- ot
452+ :~ [%uid uid]
453+ [%signatures (as signature)]
454+ ==
455+ ::
456+ ++ remove-signatures
457+ %- ot
458+ :~ [%uid uid]
459+ [%signatures (as signature)]
460+ ==
461+ ::
462+ ++ signature
463+ %- ot
464+ :~ [%hash nu]
465+ [%ship (su ;~(pfix sig fed:ag))]
466+ [%life ni]
467+ ==
468+ ::
469+ ++ uid
470+ %- ot
471+ :~ [%resource dejs:res]
472+ [%index index]
473+ ==
474+ ::
475+ ++ index (su ;~(pfix fas (more fas dem)))
476+ ::
477+ ++ add-tag
478+ %- ot
479+ :~ [%term so]
480+ [%uid uid]
481+ ==
482+ ::
483+ ++ remove-tag
484+ %- ot
485+ :~ [%term so]
486+ [%uid uid]
487+ ==
488+ ::
489+ ++ keys
490+ |= =json
491+ *resources
492+ ::
493+ ++ tags
494+ |= =json
495+ *(set term)
496+ ::
497+ ++ tag-queries
498+ |= =json
499+ *^tag-queries
500+ ::
501+ ++ run-updates
502+ |= a=json
503+ ^- [resource update-log]
504+ [*resource *update-log]
505+ --
506+ ++ pa
507+ |= j=json
508+ ^- path
509+ ?> ?=(%s -.j)
510+ ?: =('/' p.j) /
511+ (stab p.j)
512+ ::
513+ --
514+::
515+++ create
516+ |_ [our=ship now=time]
517+ ++ post
518+ |= [=index contents=(list content)]
519+ ^- ^post
520+ :* our
521+ index
522+ now
523+ contents
524+ ~
525+ *signatures
526+ ==
527+ --
528+::
529+++ upgrade
530+ |%
531+ ::
532+ :: +two
533+ ::
534+ ++ marked-graph-to-two
535+ |= [=graph:one m=(unit mark)]
536+ [(graph-to-two graph) m]
537+ ::
538+ ++ graph-to-two
539+ |= =graph:one
540+ (graph:(upgrade ,post:one ,maybe-post:two) graph post-to-two)
541+ ::
542+ ++ post-to-two
543+ |= p=post:one
544+ ^- maybe-post:two
545+ [%& p]
546+ ::
547+ ::
548+ :: +one
549+ ::
550+ ++ update-log-to-one
551+ |= =update-log:zero
552+ ^- update-log:one
553+ %+ gas:orm-log:one *update-log:one
554+ %+ turn (tap:orm-log:zero update-log)
555+ |= [=time =logged-update:zero]
556+ ^- [^time logged-update:one]
557+ :- time
558+ :- p.logged-update
559+ (logged-update-to-one q.logged-update)
560+ ::
561+ ++ logged-update-to-one
562+ |= upd=logged-update-0:zero
563+ ^- logged-action:one
564+ ?+ -.upd upd
565+ %add-graph upd(graph (graph-to-one graph.upd))
566+ %add-nodes upd(nodes (~(run by nodes.upd) node-to-one))
567+ ==
568+ ::
569+ ++ node-to-one
570+ |= =node:zero
571+ (node:(upgrade ,post:zero ,post:one) node post-to-one)
572+ ::
573+ ++ graph-to-one
574+ |= =graph:zero
575+ (graph:(upgrade ,post:zero ,post:one) graph post-to-one)
576+ ::
577+ ++ marked-graph-to-one
578+ |= [=graph:zero m=(unit mark)]
579+ [(graph-to-one graph) m]
580+ ::
581+ ++ post-to-one
582+ |= p=post:zero
583+ ^- post:one
584+ p(contents (contents-to-one contents.p))
585+ ::
586+ ++ contents-to-one
587+ |= cs=(list content:zero)
588+ ^- (list content:one)
589+ %+ murn cs
590+ |= =content:zero
591+ ^- (unit content:one)
592+ ?: ?=(%reference -.content) ~
593+ `content
594+ ::
595+ ++ upgrade
596+ |* [in-pst=mold out-pst=mold]
597+ =>
598+ |%
599+ ++ in-orm
600+ ((on atom in-node) gth)
601+ +$ in-node
602+ [post=in-pst children=in-internal-graph]
603+ +$ in-graph
604+ ((mop atom in-node) gth)
605+ +$ in-internal-graph
606+ $~ [%empty ~]
607+ $% [%graph p=in-graph]
608+ [%empty ~]
609+ ==
610+ ::
611+ ++ out-orm
612+ ((on atom out-node) gth)
613+ +$ out-node
614+ [post=out-pst children=out-internal-graph]
615+ +$ out-graph
616+ ((mop atom out-node) gth)
617+ +$ out-internal-graph
618+ $~ [%empty ~]
619+ $% [%graph p=out-graph]
620+ [%empty ~]
621+ ==
622+ --
623+ |%
624+ ::
625+ ++ graph
626+ |= $: gra=in-graph
627+ fn=$-(in-pst out-pst)
628+ ==
629+ ^- out-graph
630+ %+ gas:out-orm *out-graph
631+ ^- (list [atom out-node])
632+ %+ turn (tap:in-orm gra)
633+ |= [a=atom n=in-node]
634+ ^- [atom out-node]
635+ [a (node n fn)]
636+ ::
637+ ++ node
638+ |= [nod=in-node fn=$-(in-pst out-pst)]
639+ ^- out-node
640+ :- (fn post.nod)
641+ ^- out-internal-graph
642+ ?: ?=(%empty -.children.nod)
643+ [%empty ~]
644+ [%graph (graph p.children.nod fn)]
645+ --
646+ ::
647+ ++ zero-load
648+ :: =* infinitely recurses
649+ =, store=zero
650+ =, orm=orm:zero
651+ =, orm-log=orm-log:zero
652+ |%
653+ ++ change-revision-graph
654+ |= [=graph:store q=(unit mark)]
655+ ^- [graph:store (unit mark)]
656+ |^
657+ :_ q
658+ ?+ q graph
659+ [~ %graph-validator-link] convert-links
660+ [~ %graph-validator-publish] convert-publish
661+ ==
662+ ::
663+ ++ convert-links
664+ %+ gas:orm *graph:store
665+ %+ turn (tap:orm graph)
666+ |= [=atom =node:store]
667+ ^- [^atom node:store]
668+ :: top-level
669+ ::
670+ :+ atom post.node
671+ ?: ?=(%empty -.children.node)
672+ [%empty ~]
673+ :- %graph
674+ %+ gas:orm *graph:store
675+ %+ turn (tap:orm p.children.node)
676+ |= [=^atom =node:store]
677+ ^- [^^atom node:store]
678+ :: existing comments get turned into containers for revisions
679+ ::
680+ :^ atom
681+ post.node(contents ~, hash ~)
682+ %graph
683+ %+ gas:orm *graph:store
684+ :_ ~ :- %0
685+ :_ [%empty ~]
686+ post.node(index (snoc index.post.node atom), hash ~)
687+ ::
688+ ++ convert-publish
689+ %+ gas:orm *graph:store
690+ %+ turn (tap:orm graph)
691+ |= [=atom =node:store]
692+ ^- [^atom node:store]
693+ :: top-level
694+ ::
695+ :+ atom post.node
696+ ?: ?=(%empty -.children.node)
697+ [%empty ~]
698+ :- %graph
699+ %+ gas:orm *graph:store
700+ %+ turn (tap:orm p.children.node)
701+ |= [=^atom =node:store]
702+ ^- [^^atom node:store]
703+ :: existing container for publish note revisions
704+ ::
705+ ?+ atom !!
706+ %1 [atom node]
707+ %2
708+ :+ atom post.node
709+ ?: ?=(%empty -.children.node)
710+ [%empty ~]
711+ :- %graph
712+ %+ gas:orm *graph:store
713+ %+ turn (tap:orm p.children.node)
714+ |= [=^^atom =node:store]
715+ ^- [^^^atom node:store]
716+ :+ atom post.node(contents ~, hash ~)
717+ :- %graph
718+ %+ gas:orm *graph:store
719+ :_ ~ :- %1
720+ :_ [%empty ~]
721+ post.node(index (snoc index.post.node atom), hash ~)
722+ ==
723+ --
724+ ::
725+ ++ maybe-unix-to-da
726+ |= =atom
727+ ^- @
728+ :: (bex 127) is roughly 226AD
729+ ?. (lte atom (bex 127))
730+ atom
731+ (add ~1970.1.1 (div (mul ~s1 atom) 1.000))
732+ ::
733+ ++ convert-unix-timestamped-node
734+ |= =node:store
735+ ^- node:store
736+ =. index.post.node
737+ (convert-unix-timestamped-index index.post.node)
738+ ?. ?=(%graph -.children.node)
739+ node
740+ :+ post.node
741+ %graph
742+ (convert-unix-timestamped-graph p.children.node)
743+ ::
744+ ++ convert-unix-timestamped-index
745+ |= =index:store
746+ (turn index maybe-unix-to-da)
747+ ::
748+ ++ convert-unix-timestamped-graph
749+ |= =graph:store
750+ %+ gas:orm *graph:store
751+ %+ turn
752+ (tap:orm graph)
753+ |= [=atom =node:store]
754+ ^- [^atom node:store]
755+ :- (maybe-unix-to-da atom)
756+ (convert-unix-timestamped-node node)
757+ --
758+ --
759+++ import
760+ |= [arc=* our=ship]
761+ ^- (quip card:agent:gall [%6 network])
762+ |^
763+ =/ sty [%6 (remake-network ;;(tree-network +.arc))]
764+ :_ sty
765+ %+ turn ~(tap by graphs.sty)
766+ |= [rid=resource =marked-graph]
767+ ^- card:agent:gall
768+ ?: =(our entity.rid)
769+ =/ =cage [%push-hook-action !>([%add rid])]
770+ [%pass / %agent [our %graph-push-hook] %poke cage]
771+ (try-rejoin rid 0)
772+ ::
773+ +$ tree-network
774+ $: graphs=tree-graphs
775+ tag-queries=(tree [term (tree uid)])
776+ update-logs=tree-update-logs
777+ archive=tree-graphs
778+ ~
779+ ==
780+ +$ tree-graphs (tree [resource tree-marked-graph])
781+ +$ tree-marked-graph [p=tree-graph q=(unit ^mark)]
782+ +$ tree-graph (tree [atom tree-node])
783+ +$ tree-node [post=tree-maybe-post children=tree-internal-graph]
784+ +$ tree-internal-graph
785+ $~ [%empty ~]
786+ $% [%graph p=tree-graph]
787+ [%empty ~]
788+ ==
789+ +$ tree-update-logs (tree [resource tree-update-log])
790+ +$ tree-update-log (tree [time tree-logged-update])
791+ +$ tree-logged-update
792+ $: p=time
793+ $= q
794+ $% [%add-graph =resource =tree-graph mark=(unit ^mark) ow=?]
795+ [%add-nodes =resource nodes=(tree [index tree-node])]
796+ [%remove-posts =resource indices=(tree index)]
797+ [%add-signatures =uid signatures=tree-signatures]
798+ [%remove-signatures =uid signatures=tree-signatures]
799+ ==
800+ ==
801+ +$ tree-signatures (tree signature)
802+ +$ tree-maybe-post (each tree-post hash)
803+ +$ tree-post
804+ $: author=ship
805+ =index
806+ time-sent=time
807+ contents=(list content)
808+ hash=(unit hash)
809+ signatures=tree-signatures
810+ ==
811+ ::
812+ ++ remake-network
813+ |= t=tree-network
814+ ^- network
815+ :* (remake-graphs graphs.t)
816+ (remake-jug:migrate tag-queries.t)
817+ (remake-update-logs update-logs.t)
818+ (remake-graphs archive.t)
819+ ~
820+ ==
821+ ::
822+ ++ remake-graphs
823+ |= t=tree-graphs
824+ ^- graphs
825+ %- remake-map:migrate
826+ (~(run by t) remake-marked-graph)
827+ ::
828+ ++ remake-marked-graph
829+ |= t=tree-marked-graph
830+ ^- marked-graph
831+ [(remake-graph p.t) q.t]
832+ ::
833+ ++ remake-graph
834+ |= t=tree-graph
835+ ^- graph
836+ %+ gas:orm *graph
837+ %+ turn ~(tap by t)
838+ |= [a=atom tn=tree-node]
839+ ^- [atom node]
840+ [a (remake-node tn)]
841+ ::
842+ ++ remake-internal-graph
843+ |= t=tree-internal-graph
844+ ^- internal-graph
845+ ?: ?=(%empty -.t)
846+ [%empty ~]
847+ [%graph (remake-graph p.t)]
848+ ::
849+ ++ remake-node
850+ |= t=tree-node
851+ ^- node
852+ :- (remake-post post.t)
853+ (remake-internal-graph children.t)
854+ ::
855+ ++ remake-update-logs
856+ |= t=tree-update-logs
857+ ^- update-logs
858+ %- remake-map:migrate
859+ (~(run by t) remake-update-log)
860+ ::
861+ ++ remake-update-log
862+ |= t=tree-update-log
863+ ^- update-log
864+ =/ ulm ((on time logged-update) gth)
865+ %+ gas:ulm *update-log
866+ %+ turn ~(tap by t)
867+ |= [=time tlu=tree-logged-update]
868+ ^- [^time logged-update]
869+ [time (remake-logged-update tlu)]
870+ ::
871+ ++ remake-logged-update
872+ |= t=tree-logged-update
873+ ^- logged-update
874+ :- p.t
875+ ?- -.q.t
876+ %add-graph
877+ :* %add-graph
878+ resource.q.t
879+ (remake-graph tree-graph.q.t)
880+ mark.q.t
881+ ow.q.t
882+ ==
883+ ::
884+ %add-nodes
885+ :- %add-nodes
886+ :- resource.q.t
887+ %- remake-map:migrate
888+ (~(run by nodes.q.t) remake-node)
889+ ::
890+ %remove-posts
891+ [%remove-posts resource.q.t (remake-set:migrate indices.q.t)]
892+ ::
893+ %add-signatures
894+ [%add-signatures uid.q.t (remake-set:migrate signatures.q.t)]
895+ ::
896+ %remove-signatures
897+ [%remove-signatures uid.q.t (remake-set:migrate signatures.q.t)]
898+ ==
899+ ::
900+ ++ remake-post
901+ |= t=tree-maybe-post
902+ ^- maybe-post
903+ ?- -.t
904+ %| t
905+ %& t(signatures.p (remake-set:migrate signatures.p.t))
906+ ==
907+ ::
908+ ++ try-rejoin
909+ |= [rid=resource nack-count=@]
910+ ^- card:agent:gall
911+ =/ res-path (en-path:res rid)
912+ =/ wire [%try-rejoin (scot %ud nack-count) res-path]
913+ =/ =cage
914+ :- %pull-hook-action
915+ !> ^- action:pull-hook
916+ [%add [entity .]:rid]
917+ [%pass wire %agent [our %graph-pull-hook] %poke cage]
918+ --
919+--
zod/seax/lib/migrate.hoonnew file+19
@@ -0,0 +1,19 @@
1+^? |%
2+++ remake-set
3+ |* s=(tree)
4+ (sy ~(tap in s))
5+::
6+++ remake-map
7+ |* m=(tree)
8+ (my ~(tap by m))
9+::
10+++ remake-jug
11+ |* j=(tree [* (tree)])
12+ %- remake-map
13+ (~(run by j) remake-set)
14+::
15+++ remake-map-of-map
16+ |* mm=(tree [* (tree)])
17+ %- remake-map
18+ (~(run by mm) remake-map)
19+--
zod/seax/lib/rank.hoon+2−2
@@ -9,9 +9,9 @@
99 %- zing
1010 %+ turn results
1111 |= [engine=term results=(list search-result)]
12− %+ turn (zip (gulf 1 (lent results)) results)
12+ %+ turn (zip (gulf 0 (lent results)) results)
1313 |= [ord=@u result=search-result]
14− %- malt ~[[url.result [~[engine] ~[ord] result]]]
14+ %- malt ~[[url.result [~[engine] ~[+(ord)] result]]]
1515=/ url-to-engines-map
1616 ^- (map @t [engines=(list term) ords=(list @u) result=search-result])
1717 %+ roll url-to-engine-map
zod/seax/lib/resource.hoonnew file+57
@@ -0,0 +1,57 @@
1+/- sur=resource
2+=< resource
3+|%
4++$ resource resource:sur
5+++ en-path
6+ |= =resource
7+ ^- path
8+ ~[%ship (scot %p entity.resource) name.resource]
9+::
10+++ de-path
11+ |= =path
12+ ^- resource
13+ (need (de-path-soft path))
14+::
15+++ de-path-soft
16+ |= =path
17+ ^- (unit resource)
18+ ?. ?=([%ship @ @ *] path)
19+ ~
20+ =/ ship
21+ (slaw %p i.t.path)
22+ ?~ ship
23+ ~
24+ `[u.ship i.t.t.path]
25+::
26+++ enjs
27+ |= =resource
28+ ^- json
29+ =, enjs:format
30+ %- pairs
31+ :~ ship+(ship entity.resource)
32+ name+s+name.resource
33+ ==
34+::
35+++ enjs-path
36+ |= =resource
37+ %- spat
38+ (en-path resource)
39+::
40+++ dejs-path
41+ %- su:dejs:format
42+ ;~ pfix
43+ (jest '/ship/')
44+ ;~((glue fas) ;~(pfix sig fed:ag) urs:ab)
45+ ==
46+::
47+++ dejs
48+ =, dejs:format
49+ ^- $-(json resource)
50+ |= jon=json
51+ ~| dejs+%resource
52+ %. jon
53+ %- ot
54+ :~ ship+(su ;~(pfix sig fed:ag))
55+ name+so
56+ ==
57+--
zod/seax/lib/strand.hoonnew file+1
@@ -0,0 +1 @@
1+rand
zod/seax/lib/strandio.hoonnew file+812
@@ -0,0 +1,812 @@
1+/- spider
2+/+ libstrand=strand
3+=, strand=strand:libstrand
4+=, strand-fail=strand-fail:libstrand
5+|%
6+++ send-raw-cards
7+ |= cards=(list =card:agent:gall)
8+ =/ m (strand ,~)
9+ ^- form:m
10+ |= strand-input:strand
11+ [cards %done ~]
12+::
13+++ send-raw-card
14+ |= =card:agent:gall
15+ =/ m (strand ,~)
16+ ^- form:m
17+ (send-raw-cards card ~)
18+::
19+++ ignore
20+ |= tin=strand-input:strand
21+ `[%fail %ignore ~]
22+::
23+++ get-bowl
24+ =/ m (strand ,bowl:strand)
25+ ^- form:m
26+ |= tin=strand-input:strand
27+ `[%done bowl.tin]
28+::
29+++ get-beak
30+ =/ m (strand ,beak)
31+ ^- form:m
32+ |= tin=strand-input:strand
33+ `[%done [our q.byk da+now]:bowl.tin]
34+::
35+++ get-time
36+ =/ m (strand ,@da)
37+ ^- form:m
38+ |= tin=strand-input:strand
39+ `[%done now.bowl.tin]
40+::
41+++ get-our
42+ =/ m (strand ,ship)
43+ ^- form:m
44+ |= tin=strand-input:strand
45+ `[%done our.bowl.tin]
46+::
47+++ get-entropy
48+ =/ m (strand ,@uvJ)
49+ ^- form:m
50+ |= tin=strand-input:strand
51+ `[%done eny.bowl.tin]
52+::
53+:: Convert skips to %ignore failures.
54+::
55+:: This tells the main loop to try the next handler.
56+::
57+++ handle
58+ |* a=mold
59+ =/ m (strand ,a)
60+ |= =form:m
61+ ^- form:m
62+ |= tin=strand-input:strand
63+ =/ res (form tin)
64+ =? next.res ?=(%skip -.next.res)
65+ [%fail %ignore ~]
66+ res
67+::
68+:: Wait for a poke with a particular mark
69+::
70+++ take-poke
71+ |= =mark
72+ =/ m (strand ,vase)
73+ ^- form:m
74+ |= tin=strand-input:strand
75+ ?+ in.tin `[%skip ~]
76+ ~
77+ `[%wait ~]
78+ ::
79+ [~ %poke @ *]
80+ ?. =(mark p.cage.u.in.tin)
81+ `[%skip ~]
82+ `[%done q.cage.u.in.tin]
83+ ==
84+::
85+++ take-sign-arvo
86+ =/ m (strand ,[wire sign-arvo])
87+ ^- form:m
88+ |= tin=strand-input:strand
89+ ?+ in.tin `[%skip ~]
90+ ~
91+ `[%wait ~]
92+ ::
93+ [~ %sign *]
94+ `[%done [wire sign-arvo]:u.in.tin]
95+ ==
96+::
97+:: Wait for a subscription update on a wire
98+::
99+++ take-fact-prefix
100+ |= =wire
101+ =/ m (strand ,[path cage])
102+ ^- form:m
103+ |= tin=strand-input:strand
104+ ?+ in.tin `[%skip ~]
105+ ~ `[%wait ~]
106+ [~ %agent * %fact *]
107+ ?. =(watch+wire (scag +((lent wire)) wire.u.in.tin))
108+ `[%skip ~]
109+ `[%done (slag (lent wire) wire.u.in.tin) cage.sign.u.in.tin]
110+ ==
111+::
112+:: Wait for a subscription update on a wire
113+::
114+++ take-fact
115+ |= =wire
116+ =/ m (strand ,cage)
117+ ^- form:m
118+ |= tin=strand-input:strand
119+ ?+ in.tin `[%skip ~]
120+ ~ `[%wait ~]
121+ [~ %agent * %fact *]
122+ ?. =(watch+wire wire.u.in.tin)
123+ `[%skip ~]
124+ `[%done cage.sign.u.in.tin]
125+ ==
126+::
127+:: Wait for a subscription close
128+::
129+++ take-kick
130+ |= =wire
131+ =/ m (strand ,~)
132+ ^- form:m
133+ |= tin=strand-input:strand
134+ ?+ in.tin `[%skip ~]
135+ ~ `[%wait ~]
136+ [~ %agent * %kick *]
137+ ?. =(watch+wire wire.u.in.tin)
138+ `[%skip ~]
139+ `[%done ~]
140+ ==
141+::
142+++ echo
143+ =/ m (strand ,~)
144+ ^- form:m
145+ %- (main-loop ,~)
146+ :~ |= ~
147+ ^- form:m
148+ ;< =vase bind:m ((handle ,vase) (take-poke %echo))
149+ =/ message=tape !<(tape vase)
150+ %- (slog leaf+"{message}..." ~)
151+ ;< ~ bind:m (sleep ~s2)
152+ %- (slog leaf+"{message}.." ~)
153+ (pure:m ~)
154+ ::
155+ |= ~
156+ ^- form:m
157+ ;< =vase bind:m ((handle ,vase) (take-poke %over))
158+ %- (slog leaf+"over..." ~)
159+ (pure:m ~)
160+ ==
161+::
162+++ take-watch
163+ =/ m (strand ,path)
164+ |= tin=strand-input:strand
165+ ?+ in.tin `[%skip ~]
166+ ~ `[%wait ~]
167+ [~ %watch *]
168+ `[%done path.u.in.tin]
169+ ==
170+::
171+++ take-wake
172+ |= until=(unit @da)
173+ =/ m (strand ,~)
174+ ^- form:m
175+ |= tin=strand-input:strand
176+ ?+ in.tin `[%skip ~]
177+ ~ `[%wait ~]
178+ [~ %sign [%wait @ ~] %behn %wake *]
179+ ?. |(?=(~ until) =(`u.until (slaw %da i.t.wire.u.in.tin)))
180+ `[%skip ~]
181+ ?~ error.sign-arvo.u.in.tin
182+ `[%done ~]
183+ `[%fail %timer-error u.error.sign-arvo.u.in.tin]
184+ ==
185+::
186+++ take-tune
187+ |= =wire
188+ =/ m (strand ,[spar:ames (unit roar:ames)])
189+ ^- form:m
190+ |= tin=strand-input:strand
191+ ?+ in.tin `[%skip ~]
192+ ~ `[%wait ~]
193+ ::
194+ [~ %sign * %ames %tune ^ *]
195+ ?. =(wire wire.u.in.tin)
196+ `[%skip ~]
197+ `[%done +>.sign-arvo.u.in.tin]
198+ ==
199+::
200+++ take-poke-ack
201+ |= =wire
202+ =/ m (strand ,~)
203+ ^- form:m
204+ |= tin=strand-input:strand
205+ ?+ in.tin `[%skip ~]
206+ ~ `[%wait ~]
207+ [~ %agent * %poke-ack *]
208+ ?. =(wire wire.u.in.tin)
209+ `[%skip ~]
210+ ?~ p.sign.u.in.tin
211+ `[%done ~]
212+ `[%fail %poke-fail u.p.sign.u.in.tin]
213+ ==
214+::
215+++ take-watch-ack
216+ |= =wire
217+ =/ m (strand ,~)
218+ ^- form:m
219+ |= tin=strand-input:strand
220+ ?+ in.tin `[%skip ~]
221+ ~ `[%wait ~]
222+ [~ %agent * %watch-ack *]
223+ ?. =(watch+wire wire.u.in.tin)
224+ `[%skip ~]
225+ ?~ p.sign.u.in.tin
226+ `[%done ~]
227+ `[%fail %watch-ack-fail u.p.sign.u.in.tin]
228+ ==
229+::
230+++ poke
231+ |= [=dock =cage]
232+ =/ m (strand ,~)
233+ ^- form:m
234+ =/ =card:agent:gall [%pass /poke %agent dock %poke cage]
235+ ;< ~ bind:m (send-raw-card card)
236+ (take-poke-ack /poke)
237+::
238+++ raw-poke
239+ |= [=dock =cage]
240+ =/ m (strand ,~)
241+ ^- form:m
242+ =/ =card:agent:gall [%pass /poke %agent dock %poke cage]
243+ ;< ~ bind:m (send-raw-card card)
244+ =/ m (strand ,~)
245+ ^- form:m
246+ |= tin=strand-input:strand
247+ ?+ in.tin `[%skip ~]
248+ ~
249+ `[%wait ~]
250+ ::
251+ [~ %agent * %poke-ack *]
252+ ?. =(/poke wire.u.in.tin)
253+ `[%skip ~]
254+ `[%done ~]
255+ ==
256+::
257+++ raw-poke-our
258+ |= [app=term =cage]
259+ =/ m (strand ,~)
260+ ^- form:m
261+ ;< =bowl:spider bind:m get-bowl
262+ (raw-poke [our.bowl app] cage)
263+::
264+++ poke-our
265+ |= [=term =cage]
266+ =/ m (strand ,~)
267+ ^- form:m
268+ ;< our=@p bind:m get-our
269+ (poke [our term] cage)
270+::
271+++ watch
272+ |= [=wire =dock =path]
273+ =/ m (strand ,~)
274+ ^- form:m
275+ =/ =card:agent:gall [%pass watch+wire %agent dock %watch path]
276+ ;< ~ bind:m (send-raw-card card)
277+ (take-watch-ack wire)
278+::
279+++ watch-one
280+ |= [=wire =dock =path]
281+ =/ m (strand ,cage)
282+ ^- form:m
283+ ;< ~ bind:m (watch wire dock path)
284+ ;< =cage bind:m (take-fact wire)
285+ ;< ~ bind:m (take-kick wire)
286+ (pure:m cage)
287+::
288+++ watch-our
289+ |= [=wire =term =path]
290+ =/ m (strand ,~)
291+ ^- form:m
292+ ;< our=@p bind:m get-our
293+ (watch wire [our term] path)
294+::
295+++ scry
296+ |* [=mold =path]
297+ =/ m (strand ,mold)
298+ ^- form:m
299+ ?> ?=(^ path)
300+ ?> ?=(^ t.path)
301+ ;< =bowl:spider bind:m get-bowl
302+ %- pure:m
303+ .^(mold i.path (scot %p our.bowl) i.t.path (scot %da now.bowl) t.t.path)
304+::
305+++ leave
306+ |= [=wire =dock]
307+ =/ m (strand ,~)
308+ ^- form:m
309+ =/ =card:agent:gall [%pass watch+wire %agent dock %leave ~]
310+ (send-raw-card card)
311+::
312+++ leave-our
313+ |= [=wire =term]
314+ =/ m (strand ,~)
315+ ^- form:m
316+ ;< our=@p bind:m get-our
317+ (leave wire [our term])
318+::
319+++ rewatch
320+ |= [=wire =dock =path]
321+ =/ m (strand ,~)
322+ ;< ~ bind:m ((handle ,~) (take-kick wire))
323+ ;< ~ bind:m (flog-text "rewatching {<dock>} {<path>}")
324+ ;< ~ bind:m (watch wire dock path)
325+ (pure:m ~)
326+::
327+++ wait
328+ |= until=@da
329+ =/ m (strand ,~)
330+ ^- form:m
331+ ;< ~ bind:m (send-wait until)
332+ (take-wake `until)
333+::
334+++ keen
335+ |= [=wire =spar:ames]
336+ =/ m (strand ,~)
337+ ^- form:m
338+ (send-raw-card %pass wire %arvo %a %keen spar)
339+::
340+++ sleep
341+ |= for=@dr
342+ =/ m (strand ,~)
343+ ^- form:m
344+ ;< now=@da bind:m get-time
345+ (wait (add now for))
346+::
347+++ send-wait
348+ |= until=@da
349+ =/ m (strand ,~)
350+ ^- form:m
351+ =/ =card:agent:gall
352+ [%pass /wait/(scot %da until) %arvo %b %wait until]
353+ (send-raw-card card)
354+::
355+++ map-err
356+ |* computation-result=mold
357+ =/ m (strand ,computation-result)
358+ |= [f=$-([term tang] [term tang]) computation=form:m]
359+ ^- form:m
360+ |= tin=strand-input:strand
361+ =* loop $
362+ =/ c-res (computation tin)
363+ ?: ?=(%cont -.next.c-res)
364+ c-res(self.next ..loop(computation self.next.c-res))
365+ ?. ?=(%fail -.next.c-res)
366+ c-res
367+ c-res(err.next (f err.next.c-res))
368+::
369+++ set-timeout
370+ |* computation-result=mold
371+ =/ m (strand ,computation-result)
372+ |= [time=@dr computation=form:m]
373+ ^- form:m
374+ ;< now=@da bind:m get-time
375+ =/ when (add now time)
376+ =/ =card:agent:gall
377+ [%pass /timeout/(scot %da when) %arvo %b %wait when]
378+ ;< ~ bind:m (send-raw-card card)
379+ |= tin=strand-input:strand
380+ =* loop $
381+ ?: ?& ?=([~ %sign [%timeout @ ~] %behn %wake *] in.tin)
382+ =((scot %da when) i.t.wire.u.in.tin)
383+ ==
384+ `[%fail %timeout ~]
385+ =/ c-res (computation tin)
386+ ?: ?=(%cont -.next.c-res)
387+ c-res(self.next ..loop(computation self.next.c-res))
388+ ?: ?=(%done -.next.c-res)
389+ =/ =card:agent:gall
390+ [%pass /timeout/(scot %da when) %arvo %b %rest when]
391+ c-res(cards [card cards.c-res])
392+ c-res
393+::
394+++ send-request
395+ |= =request:http
396+ =/ m (strand ,~)
397+ ^- form:m
398+ (send-raw-card %pass /request %arvo %i %request request *outbound-config:iris)
399+::
400+++ send-cancel-request
401+ =/ m (strand ,~)
402+ ^- form:m
403+ (send-raw-card %pass /request %arvo %i %cancel-request ~)
404+::
405+++ take-client-response
406+ =/ m (strand ,client-response:iris)
407+ ^- form:m
408+ |= tin=strand-input:strand
409+ ?+ in.tin `[%skip ~]
410+ ~ `[%wait ~]
411+ ::
412+ [~ %sign [%request ~] %iris %http-response %cancel *]
413+ ::NOTE iris does not (yet?) retry after cancel, so it means failure
414+ :- ~
415+ :+ %fail
416+ %http-request-cancelled
417+ ['http request was cancelled by the runtime']~
418+ ::
419+ [~ %sign [%request ~] %iris %http-response %finished *]
420+ `[%done client-response.sign-arvo.u.in.tin]
421+ ==
422+::
423+:: Wait until we get an HTTP response or cancelation and unset contract
424+::
425+++ take-maybe-sigh
426+ =/ m (strand ,(unit httr:eyre))
427+ ^- form:m
428+ ;< rep=(unit client-response:iris) bind:m
429+ take-maybe-response
430+ ?~ rep
431+ (pure:m ~)
432+ :: XX s/b impossible
433+ ::
434+ ?. ?=(%finished -.u.rep)
435+ (pure:m ~)
436+ (pure:m (some (to-httr:iris +.u.rep)))
437+::
438+++ take-maybe-response
439+ =/ m (strand ,(unit client-response:iris))
440+ ^- form:m
441+ |= tin=strand-input:strand
442+ ?+ in.tin `[%skip ~]
443+ ~ `[%wait ~]
444+ [~ %sign [%request ~] %iris %http-response %cancel *]
445+ `[%done ~]
446+ [~ %sign [%request ~] %iris %http-response %finished *]
447+ `[%done `client-response.sign-arvo.u.in.tin]
448+ ==
449+::
450+++ extract-body
451+ |= =client-response:iris
452+ =/ m (strand ,cord)
453+ ^- form:m
454+ ?> ?=(%finished -.client-response)
455+ %- pure:m
456+ ?~ full-file.client-response ''
457+ q.data.u.full-file.client-response
458+::
459+++ fetch-cord
460+ |= url=tape
461+ =/ m (strand ,cord)
462+ ^- form:m
463+ =/ =request:http [%'GET' (crip url) ~ ~]
464+ ;< ~ bind:m (send-request request)
465+ ;< =client-response:iris bind:m take-client-response
466+ (extract-body client-response)
467+::
468+++ fetch-json
469+ |= url=tape
470+ =/ m (strand ,json)
471+ ^- form:m
472+ ;< =cord bind:m (fetch-cord url)
473+ =/ json=(unit json) (de:json:html cord)
474+ ?~ json
475+ (strand-fail %json-parse-error ~)
476+ (pure:m u.json)
477+::
478+++ hiss-request
479+ |= =hiss:eyre
480+ =/ m (strand ,(unit httr:eyre))
481+ ^- form:m
482+ ;< ~ bind:m (send-request (hiss-to-request:html hiss))
483+ take-maybe-sigh
484+::
485+:: +build-file: build the source file at the specified $beam
486+::
487+++ build-file
488+ |= [[=ship =desk =case] =spur]
489+ =* arg +<
490+ =/ m (strand ,(unit vase))
491+ ^- form:m
492+ ;< =riot:clay bind:m
493+ (warp ship desk ~ %sing %a case spur)
494+ ?~ riot
495+ (pure:m ~)
496+ ?> =(%vase p.r.u.riot)
497+ (pure:m (some !<(vase q.r.u.riot)))
498+::
499+++ build-file-hard
500+ |= [[=ship =desk =case] =spur]
501+ =* arg +<
502+ =/ m (strand ,vase)
503+ ^- form:m
504+ ;< =riot:clay
505+ bind:m
506+ (warp ship desk ~ %sing %a case spur)
507+ ?> ?=(^ riot)
508+ ?> ?=(%vase p.r.u.riot)
509+ (pure:m !<(vase q.r.u.riot))
510+:: +build-mark: build a mark definition to a $dais
511+::
512+++ build-mark
513+ |= [[=ship =desk =case] mak=mark]
514+ =* arg +<
515+ =/ m (strand ,dais:clay)
516+ ^- form:m
517+ ;< =riot:clay bind:m
518+ (warp ship desk ~ %sing %b case /[mak])
519+ ?~ riot
520+ (strand-fail %build-mark >arg< ~)
521+ ?> =(%dais p.r.u.riot)
522+ (pure:m !<(dais:clay q.r.u.riot))
523+:: +build-tube: build a mark conversion gate ($tube)
524+::
525+++ build-tube
526+ |= [[=ship =desk =case] =mars:clay]
527+ =* arg +<
528+ =/ m (strand ,tube:clay)
529+ ^- form:m
530+ ;< =riot:clay bind:m
531+ (warp ship desk ~ %sing %c case /[a.mars]/[b.mars])
532+ ?~ riot
533+ (strand-fail %build-tube >arg< ~)
534+ ?> =(%tube p.r.u.riot)
535+ (pure:m !<(tube:clay q.r.u.riot))
536+::
537+:: +build-nave: build a mark definition to a $nave
538+::
539+++ build-nave
540+ |= [[=ship =desk =case] mak=mark]
541+ =* arg +<
542+ =/ m (strand ,vase)
543+ ^- form:m
544+ ;< =riot:clay bind:m
545+ (warp ship desk ~ %sing %e case /[mak])
546+ ?~ riot
547+ (strand-fail %build-nave >arg< ~)
548+ ?> =(%nave p.r.u.riot)
549+ (pure:m q.r.u.riot)
550+:: +build-cast: build a mark conversion gate (static)
551+::
552+++ build-cast
553+ |= [[=ship =desk =case] =mars:clay]
554+ =* arg +<
555+ =/ m (strand ,vase)
556+ ^- form:m
557+ ;< =riot:clay bind:m
558+ (warp ship desk ~ %sing %f case /[a.mars]/[b.mars])
559+ ?~ riot
560+ (strand-fail %build-cast >arg< ~)
561+ ?> =(%cast p.r.u.riot)
562+ (pure:m q.r.u.riot)
563+::
564+:: Read from Clay
565+::
566+++ warp
567+ |= [=ship =riff:clay]
568+ =/ m (strand ,riot:clay)
569+ ;< ~ bind:m (send-raw-card %pass /warp %arvo %c %warp ship riff)
570+ (take-writ /warp)
571+::
572+++ read-file
573+ |= [[=ship =desk =case] =spur]
574+ =* arg +<
575+ =/ m (strand ,cage)
576+ ;< =riot:clay bind:m (warp ship desk ~ %sing %x case spur)
577+ ?~ riot
578+ (strand-fail %read-file >arg< ~)
579+ (pure:m r.u.riot)
580+::
581+++ check-for-file
582+ |= [[=ship =desk =case] =spur]
583+ =/ m (strand ,?)
584+ ;< =riot:clay bind:m (warp ship desk ~ %sing %u case spur)
585+ ?> ?=(^ riot)
586+ (pure:m !<(? q.r.u.riot))
587+::
588+++ list-tree
589+ |= [[=ship =desk =case] =spur]
590+ =* arg +<
591+ =/ m (strand ,(list path))
592+ ;< =riot:clay bind:m (warp ship desk ~ %sing %t case spur)
593+ ?~ riot
594+ (strand-fail %list-tree >arg< ~)
595+ (pure:m !<((list path) q.r.u.riot))
596+::
597+:: Take Clay read result
598+::
599+++ take-writ
600+ |= =wire
601+ =/ m (strand ,riot:clay)
602+ ^- form:m
603+ |= tin=strand-input:strand
604+ ?+ in.tin `[%skip ~]
605+ ~ `[%wait ~]
606+ [~ %sign * ?(%behn %clay) %writ *]
607+ ?. =(wire wire.u.in.tin)
608+ `[%skip ~]
609+ `[%done +>.sign-arvo.u.in.tin]
610+ ==
611+:: +check-online: require that peer respond before timeout
612+::
613+++ check-online
614+ |= [who=ship lag=@dr]
615+ =/ m (strand ,~)
616+ ^- form:m
617+ %+ (map-err ,~) |=(* [%offline *tang])
618+ %+ (set-timeout ,~) lag
619+ ;< ~ bind:m
620+ (poke [who %hood] %helm-hi !>(~))
621+ (pure:m ~)
622+::
623+++ eval-hoon
624+ |= [gen=hoon bez=(list beam)]
625+ =/ m (strand ,vase)
626+ ^- form:m
627+ =/ sut=vase !>(..zuse)
628+ |-
629+ ?~ bez
630+ (pure:m (slap sut gen))
631+ ;< vax=vase bind:m (build-file-hard i.bez)
632+ $(bez t.bez, sut (slop vax sut))
633+::
634+++ send-thread
635+ |= [=bear:khan =shed:khan =wire]
636+ =/ m (strand ,~)
637+ ^- form:m
638+ (send-raw-card %pass wire %arvo %k %lard bear shed)
639+::
640+:: Queue on skip, try next on fail %ignore
641+::
642+++ main-loop
643+ |* a=mold
644+ =/ m (strand ,~)
645+ =/ m-a (strand ,a)
646+ =| queue=(qeu (unit input:strand))
647+ =| active=(unit [in=(unit input:strand) =form:m-a forms=(list $-(a form:m-a))])
648+ =| state=a
649+ |= forms=(lest $-(a form:m-a))
650+ ^- form:m
651+ |= tin=strand-input:strand
652+ =* top `form:m`..$
653+ =. queue (~(put to queue) in.tin)
654+ |^ (continue bowl.tin)
655+ ::
656+ ++ continue
657+ |= =bowl:strand
658+ ^- output:m
659+ ?> =(~ active)
660+ ?: =(~ queue)
661+ `[%cont top]
662+ =^ in=(unit input:strand) queue ~(get to queue)
663+ ^- output:m
664+ =. active `[in (i.forms state) t.forms]
665+ ^- output:m
666+ (run bowl in)
667+ ::
668+ ++ run
669+ ^- form:m
670+ |= tin=strand-input:strand
671+ ^- output:m
672+ ?> ?=(^ active)
673+ =/ res (form.u.active tin)
674+ =/ =output:m
675+ ?- -.next.res
676+ %wait `[%wait ~]
677+ %skip `[%cont ..$(queue (~(put to queue) in.tin))]
678+ %cont `[%cont ..$(active `[in.u.active self.next.res forms.u.active])]
679+ %done (continue(active ~, state value.next.res) bowl.tin)
680+ %fail
681+ ?: &(?=(^ forms.u.active) ?=(%ignore p.err.next.res))
682+ %= $
683+ active `[in.u.active (i.forms.u.active state) t.forms.u.active]
684+ in.tin in.u.active
685+ ==
686+ `[%fail err.next.res]
687+ ==
688+ [(weld cards.res cards.output) next.output]
689+ --
690+::
691+++ retry
692+ |* result=mold
693+ |= [crash-after=(unit @ud) computation=_*form:(strand (unit result))]
694+ =/ m (strand ,result)
695+ =| try=@ud
696+ |- ^- form:m
697+ =* loop $
698+ ?: =(crash-after `try)
699+ (strand-fail %retry-too-many ~)
700+ ;< ~ bind:m (backoff try ~m1)
701+ ;< res=(unit result) bind:m computation
702+ ?^ res
703+ (pure:m u.res)
704+ loop(try +(try))
705+::
706+++ backoff
707+ |= [try=@ud limit=@dr]
708+ =/ m (strand ,~)
709+ ^- form:m
710+ ;< eny=@uvJ bind:m get-entropy
711+ %- sleep
712+ %+ min limit
713+ ?: =(0 try) ~s0
714+ %+ add
715+ (mul ~s1 (bex (dec try)))
716+ (mul ~s0..0001 (~(rad og eny) 1.000))
717+::
718+:: ----
719+::
720+:: Output
721+::
722+++ flog
723+ |= =flog:dill
724+ =/ m (strand ,~)
725+ ^- form:m
726+ (send-raw-card %pass / %arvo %d %flog flog)
727+::
728+++ flog-text
729+ |= =tape
730+ =/ m (strand ,~)
731+ ^- form:m
732+ (flog %text tape)
733+::
734+++ flog-tang
735+ |= =tang
736+ =/ m (strand ,~)
737+ ^- form:m
738+ =/ =wall
739+ (zing (turn (flop tang) (cury wash [0 80])))
740+ |- ^- form:m
741+ =* loop $
742+ ?~ wall
743+ (pure:m ~)
744+ ;< ~ bind:m (flog-text i.wall)
745+ loop(wall t.wall)
746+::
747+++ trace
748+ |= =tang
749+ =/ m (strand ,~)
750+ ^- form:m
751+ (pure:m ((slog tang) ~))
752+::
753+++ app-message
754+ |= [app=term =cord =tang]
755+ =/ m (strand ,~)
756+ ^- form:m
757+ =/ msg=tape :(weld (trip app) ": " (trip cord))
758+ ;< ~ bind:m (flog-text msg)
759+ (flog-tang tang)
760+::
761+:: ----
762+::
763+:: Handle domains
764+::
765+++ install-domain
766+ |= =turf
767+ =/ m (strand ,~)
768+ ^- form:m
769+ (send-raw-card %pass / %arvo %e %rule %turf %put turf)
770+::
771+:: ----
772+::
773+:: Threads
774+::
775+++ start-thread
776+ |= file=term
777+ =/ m (strand ,tid:spider)
778+ ;< =bowl:spider bind:m get-bowl
779+ (start-thread-with-args byk.bowl file *vase)
780+::
781+++ start-thread-with-args
782+ |= [=beak file=term args=vase]
783+ =/ m (strand ,tid:spider)
784+ ^- form:m
785+ ;< =bowl:spider bind:m get-bowl
786+ =/ tid
787+ (scot %ta (cat 3 (cat 3 'strand_' file) (scot %uv (sham file eny.bowl))))
788+ =/ poke-vase !>(`start-args:spider`[`tid.bowl `tid beak file args])
789+ ;< ~ bind:m (poke-our %spider %spider-start poke-vase)
790+ ;< ~ bind:m (sleep ~s0) :: wait for thread to start
791+ (pure:m tid)
792+::
793++$ thread-result
794+ (each vase [term tang])
795+::
796+++ await-thread
797+ |= [file=term args=vase]
798+ =/ m (strand ,thread-result)
799+ ^- form:m
800+ ;< =bowl:spider bind:m get-bowl
801+ =/ tid (scot %ta (cat 3 'strand_' (scot %uv (sham file eny.bowl))))
802+ =/ poke-vase !>(`start-args:spider`[`tid.bowl `tid byk.bowl file args])
803+ ;< ~ bind:m (watch-our /awaiting/[tid] %spider /thread-result/[tid])
804+ ;< ~ bind:m (poke-our %spider %spider-start poke-vase)
805+ ;< ~ bind:m (sleep ~s0) :: wait for thread to start
806+ ;< =cage bind:m (take-fact /awaiting/[tid])
807+ ;< ~ bind:m (take-kick /awaiting/[tid])
808+ ?+ p.cage ~|([%strange-thread-result p.cage file tid] !!)
809+ %thread-done (pure:m %& q.cage)
810+ %thread-fail (pure:m %| ;;([term tang] q.q.cage))
811+ ==
812+--
zod/seax/sur/cite.hoonnew file+57
@@ -0,0 +1,57 @@
1+/- g=groups
2+=< cite
3+|%
4+++ purse
5+ |= =(pole knot)
6+ ^- (unit cite)
7+ ?. =(~.1 -.pole) ~
8+ =. pole +.pole
9+ ?+ pole ~
10+ [%chan agent=@ ship=@ name=@ rest=*]
11+ =/ ship (slaw %p ship.pole)
12+ ?~ ship ~
13+ `[%chan [agent.pole u.ship name.pole] rest.pole]
14+ ::
15+ [%desk ship=@ name=@ rest=*]
16+ =/ ship (slaw %p ship.pole)
17+ ?~ ship ~
18+ `[%desk [u.ship name.pole] rest.pole]
19+ ::
20+ [%group ship=@ name=@ ~]
21+ =/ ship (slaw %p ship.pole)
22+ ?~ ship ~
23+ `[%group u.ship name.pole]
24+ ==
25+++ parse
26+ |= =path
27+ ^- cite
28+ (need (purse path))
29+::
30+++ print
31+ |= c=cite
32+ |^ ^- path
33+ :- (scot %ud 1)
34+ ?- -.c
35+ %chan chan/(welp (nest nest.c) wer.c)
36+ %desk desk/(welp (flag flag.c) wer.c)
37+ %group group/(flag flag.c)
38+ %bait bait/:(welp (flag grp.c) (flag gra.c) wer.c)
39+ ==
40+ ++ flag
41+ |= f=flag:g
42+ ~[(scot %p p.f) q.f]
43+ ++ nest
44+ |= n=nest:g
45+ [p.n (flag q.n)]
46+ --
47+::
48++$ cite
49+ $% [%chan =nest:g wer=path]
50+ [%group =flag:g]
51+ [%desk =flag:g wer=path]
52+ [%bait grp=flag:g gra=flag:g wer=path]
53+ :: scry into groups when you receive a bait for a chat that doesn't exist yet
54+ :: work out what app
55+ ==
56+--
57+
zod/seax/sur/diary-0.hoonnew file+323
@@ -0,0 +1,323 @@
1+/- g=groups, c=cite, graph-store, e=epic
2+/- metadata-store
3+/+ lib-graph=graph-store
4+|%
5+++ okay `epic:e`0
6+++ mar
7+ |%
8+ ++ act `mark`(rap 3 %diary-action '-' (scot %ud okay) ~)
9+ ++ upd `mark`(rap 3 %diary-update '-' (scot %ud okay) ~)
10+ ++ log `mark`(rap 3 %diary-logs '-' (scot %ud okay) ~)
11+ --
12+:: $flag: identifier for a diary channel
13++$ flag (pair ship term)
14+:: $feel: either an emoji identifier like :diff or a URL for custom
15++$ feel @ta
16+:: $view: the persisted display format for a diary
17++$ view ?(%grid %list)
18+:: $sort: the persisted sort type for a diary
19++$ sort ?(%alpha %time %arranged)
20+:: $shelf: my ship's diaries
21++$ shelf (map flag diary)
22+:: $said: used for references
23++$ said (pair flag outline)
24+:: $plan: index into diary state
25+:: p: Note being referred to
26+:: q: Quip being referred to, if any
27+::
28++$ plan
29+ (pair time (unit time))
30+::
31+:: $diary: written longform communication
32+::
33+:: net: an indicator of whether I'm a host or subscriber
34+:: log: the history of all modifications
35+:: perm: holds the diary's permissions
36+:: view: what format to display
37+:: sort: how to order posts
38+:: notes: the actual contents of the diary
39+:: remark: what is the last thing we've read
40+:: banter: comments organized by post
41+::
42++$ diary
43+ $: =net
44+ =log
45+ =perm
46+ =view
47+ =sort
48+ =notes
49+ =remark
50+ ==
51+::
52+:: $notes: a set of time ordered diary posts
53+::
54+++ notes
55+ =< rock
56+ |%
57+ +$ rock
58+ ((mop time note) lte)
59+ ++ on
60+ ((^on time note) lte)
61+ +$ diff
62+ (pair time delta)
63+ +$ delta
64+ $% [%add p=essay]
65+ [%edit p=essay]
66+ [%del ~]
67+ [%quips p=diff:quips]
68+ [%add-feel p=ship q=feel]
69+ [%del-feel p=ship]
70+ ==
71+ --
72+::
73+:: $quips: a set of time ordered note comments
74+::
75+++ quips
76+ =< rock
77+ |%
78+ +$ rock
79+ ((mop time quip) lte)
80+ ++ on
81+ ((^on time quip) lte)
82+ +$ diff
83+ (pair time delta)
84+ +$ delta
85+ $% [%add p=memo]
86+ [%del ~]
87+ [%add-feel p=ship q=feel]
88+ [%del-feel p=ship]
89+ ==
90+ --
91+::
92+:: $outline: abridged $note
93+:: .quips: number of comments
94+::
95++$ outline
96+ [quips=@ud quippers=(set ship) essay]
97+::
98+++ outlines
99+ =< outlines
100+ |%
101+ +$ outlines ((mop time outline) lte)
102+ ++ on ((^on time outline) lte)
103+ --
104+::
105+:: $note: a diary post
106+::
107++$ note [seal essay]
108+:: $quip: a post comment
109+::
110++$ quip [cork memo]
111+::
112+:: $seal: host-side data for a note
113+::
114++$ seal
115+ $: =time
116+ =quips
117+ feels=(map ship feel)
118+ ==
119+::
120+:: $cork: host-side data for a quip
121+::
122++$ cork
123+ $: =time
124+ feels=(map ship feel)
125+ ==
126+:: $essay: the post data itself
127+::
128+:: title: the name of the post
129+:: image: a visual displayed as a header
130+:: content: the body of the post
131+:: author: the ship that wrote the post
132+:: sent: the client-side time the post was made
133+::
134++$ essay
135+ $: title=@t
136+ image=@t
137+ content=(list verse)
138+ author=ship
139+ sent=time
140+ ==
141++$ story (pair (list block) (list inline))
142+:: $memo: the comment data itself
143+::
144+:: content: the body of the comment
145+:: author: the ship that wrote the comment
146+:: sent: the client-side time the comment was made
147+::
148++$ memo
149+ $: content=story
150+ author=ship
151+ sent=time
152+ ==
153+:: $verse: a chunk of post content
154+::
155+:: blocks stand on their own. inlines come in groups and get wrapped
156+:: into a paragraph
157+::
158++$ verse
159+ $% [%block p=block]
160+ [%inline p=(list inline)]
161+ ==
162+:: $listing: recursive type for infinitely nested <ul> or <ol>
163++$ listing
164+ $% [%list p=?(%ordered %unordered) q=(list listing) r=(list inline)]
165+ [%item p=(list inline)]
166+ ==
167+:: $block: post content that sits outside of the normal text
168+::
169+:: %image: a visual, we record dimensions for better rendering
170+:: %cite: an Urbit reference
171+:: %header: a traditional HTML heading, h1-h6
172+:: %listing: a traditional HTML list, ul and ol
173+:: %code: a block of code
174+::
175++$ block
176+ $% [%image src=cord height=@ud width=@ud alt=cord]
177+ [%cite =cite:c]
178+ [%header p=?(%h1 %h2 %h3 %h4 %h5 %h6) q=(list inline)]
179+ [%listing p=listing]
180+ [%rule ~]
181+ [%code code=cord lang=cord]
182+ ==
183+:: $inline: post content that flows within a paragraph
184+::
185+:: @t: plain text
186+:: %italics: italic text
187+:: %bold: bold text
188+:: %strike: strikethrough text
189+:: %inline-code: code formatting for small snippets
190+:: %blockquote: blockquote surrounded content
191+:: %block: link/reference to blocks
192+:: %code: code formatting for large snippets
193+:: %tag: tag gets special signifier
194+:: %link: link to a URL with a face
195+:: %break: line break
196+::
197++$ inline
198+ $@ @t
199+ $% [%italics p=(list inline)]
200+ [%bold p=(list inline)]
201+ [%strike p=(list inline)]
202+ [%blockquote p=(list inline)]
203+ [%inline-code p=cord]
204+ [%ship p=ship]
205+ [%block p=@ud q=cord]
206+ [%code p=cord]
207+ [%tag p=cord]
208+ [%link p=cord q=cord]
209+ [%break ~]
210+ ==
211+:: $log: a time ordered history of modifications to a diary
212+::
213++$ log
214+ ((mop time diff) lte)
215+++ log-on
216+ ((on time diff) lte)
217+::
218+:: $action: the complete set of data required to modify a diary
219+::
220++$ action
221+ (pair flag:g update)
222+::
223+:: $update: a representation in time of a modification to a diary
224+::
225++$ update
226+ (pair time diff)
227+::
228+:: $diff: the full suite of modifications that can be made to a diary
229+::
230++$ diff
231+ $% [%notes p=diff:notes]
232+ ::
233+ [%add-sects p=(set sect:g)]
234+ [%del-sects p=(set sect:g)]
235+ ::
236+ [%create p=perm q=notes]
237+ [%view p=view]
238+ [%sort p=sort]
239+ ::
240+ ==
241+::
242+:: $net: an indicator of whether I'm a host or subscriber
243+::
244+:: %pub: am publisher/host with fresh log
245+:: %sub: subscribed to the ship at saga
246+::
247++$ net
248+ $% [%sub p=ship load=_| =saga:e]
249+ [%pub ~] :: TODO: permissions?
250+ ==
251+::
252+:: $briefs: a map of diary unread information
253+::
254+:: brief: the last time a diary was read, how many posts since,
255+:: and the id of the last read note
256+::
257+++ briefs
258+ =< briefs
259+ |%
260+ +$ briefs
261+ (map flag brief)
262+ +$ brief
263+ [last=time count=@ud read-id=(unit time)]
264+ +$ update
265+ (pair flag brief)
266+ --
267+:: $remark: a marker representing the last note I've read
268+::
269++$ remark
270+ [last-read=time watching=_| ~]
271+::
272++$ remark-action
273+ (pair flag remark-diff)
274+::
275++$ remark-diff
276+ $% [%read ~]
277+ [%read-at p=time]
278+ [?(%watch %unwatch) ~]
279+ ==
280+::
281+:: $perm: represents the permissions for a diary channel and gives a
282+:: pointer back to the group it belongs to.
283+::
284++$ perm
285+ $: writers=(set sect:g)
286+ group=flag:g
287+ ==
288+:: $join: a group + channel flag to join a channel, group required for perms
289+::
290++$ join
291+ $: group=flag:g
292+ chan=flag:g
293+ ==
294+:: $leave: a flag to pass for a channel leave
295+::
296++$ leave flag:g
297+::
298+:: $create: represents a request to create a channel
299+::
300+:: The name will be used as part of the flag which represents the
301+:: channel. $create is consumed by the diary agent first and then
302+:: passed to the groups agent to register the channel with the group.
303+::
304+:: Write permission is stored with the specific agent in the channel,
305+:: read permission is stored with the group's data.
306+::
307++$ create
308+ $: group=flag:g
309+ name=term
310+ title=cord
311+ description=cord
312+ readers=(set sect:g)
313+ writers=(set sect:g)
314+ ==
315++$ import [writers=(set ship) =association:met =update-log:gra =graph:gra]
316+::
317++$ imports (map flag import)
318+::
319+++ gra graph-store
320+++ orm-gra orm:lib-graph
321+++ orm-log-gra orm-log:lib-graph
322+++ met metadata-store
323+--
zod/seax/sur/diary.hoonnew file+335
@@ -0,0 +1,335 @@
1+/- g=groups, c=cite, graph-store, e=epic
2+/- zer=diary-0
3+/- metadata-store
4+/+ lib-graph=graph-store
5+|%
6+++ old
7+ |%
8+ ++ zero zer
9+ --
10+::
11+++ okay `epic:e`2
12+++ mar
13+ |%
14+ ++ act `mark`(rap 3 %diary-action '-' (scot %ud okay) ~)
15+ ++ upd `mark`(rap 3 %diary-update '-' (scot %ud okay) ~)
16+ ++ log `mark`(rap 3 %diary-logs '-' (scot %ud okay) ~)
17+ --
18+:: $flag: identifier for a diary channel
19++$ flag (pair ship term)
20+:: $feel: either an emoji identifier like :diff or a URL for custom
21++$ feel @ta
22+:: $view: the persisted display format for a diary
23++$ view ?(%grid %list)
24+:: $sort: the persisted sort type for a diary
25++$ sort ?(%alpha %time %arranged)
26+:: $arranged-notes: an array of noteIds
27++$ arranged-notes (unit (list time))
28+:: $shelf: my ship's diaries
29++$ shelf (map flag diary)
30+:: $said: used for references
31++$ said (pair flag outline)
32+:: $plan: index into diary state
33+:: p: Note being referred to
34+:: q: Quip being referred to, if any
35+::
36++$ plan
37+ (pair time (unit time))
38+::
39+:: $diary: written longform communication
40+::
41+:: arranged-notes: a list of noteIds, used for manual sorting
42+:: net: an indicator of whether I'm a host or subscriber
43+:: log: the history of all modifications
44+:: perm: holds the diary's permissions
45+:: view: what format to display
46+:: sort: how to order posts
47+:: notes: the actual contents of the diary
48+:: remark: what is the last thing we've read
49+:: banter: comments organized by post
50+::
51++$ diary
52+ $: =arranged-notes
53+ =net
54+ =log
55+ =perm
56+ =view
57+ =sort
58+ =notes
59+ =remark
60+ ==
61+::
62+:: $notes: a set of time ordered diary posts
63+::
64+++ notes
65+ =< rock
66+ |%
67+ +$ rock
68+ ((mop time note) lte)
69+ ++ on
70+ ((^on time note) lte)
71+ +$ diff
72+ (pair time delta)
73+ +$ delta
74+ $% [%add p=essay]
75+ [%edit p=essay]
76+ [%del ~]
77+ [%quips p=diff:quips]
78+ [%add-feel p=ship q=feel]
79+ [%del-feel p=ship]
80+ ==
81+ --
82+::
83+:: $quips: a set of time ordered note comments
84+::
85+++ quips
86+ =< rock
87+ |%
88+ +$ rock
89+ ((mop time quip) lte)
90+ ++ on
91+ ((^on time quip) lte)
92+ +$ diff
93+ (pair time delta)
94+ +$ delta
95+ $% [%add p=memo]
96+ [%del ~]
97+ [%add-feel p=ship q=feel]
98+ [%del-feel p=ship]
99+ ==
100+ --
101+::
102+:: $outline: abridged $note
103+:: .quips: number of comments
104+::
105++$ outline
106+ [quips=@ud quippers=(set ship) essay]
107+::
108+++ outlines
109+ =< outlines
110+ |%
111+ +$ outlines ((mop time outline) lte)
112+ ++ on ((^on time outline) lte)
113+ --
114+::
115+:: $note: a diary post
116+::
117++$ note [seal essay]
118+:: $quip: a post comment
119+::
120++$ quip [cork memo]
121+::
122+:: $seal: host-side data for a note
123+::
124++$ seal
125+ $: =time
126+ =quips
127+ feels=(map ship feel)
128+ ==
129+::
130+:: $cork: host-side data for a quip
131+::
132++$ cork
133+ $: =time
134+ feels=(map ship feel)
135+ ==
136+:: $essay: the post data itself
137+::
138+:: title: the name of the post
139+:: image: a visual displayed as a header
140+:: content: the body of the post
141+:: author: the ship that wrote the post
142+:: sent: the client-side time the post was made
143+::
144++$ essay
145+ $: title=@t
146+ image=@t
147+ content=(list verse)
148+ author=ship
149+ sent=time
150+ ==
151++$ story (pair (list block) (list inline))
152+:: $memo: the comment data itself
153+::
154+:: content: the body of the comment
155+:: author: the ship that wrote the comment
156+:: sent: the client-side time the comment was made
157+::
158++$ memo
159+ $: content=story
160+ author=ship
161+ sent=time
162+ ==
163+:: $verse: a chunk of post content
164+::
165+:: blocks stand on their own. inlines come in groups and get wrapped
166+:: into a paragraph
167+::
168++$ verse
169+ $% [%block p=block]
170+ [%inline p=(list inline)]
171+ ==
172+:: $listing: recursive type for infinitely nested <ul> or <ol>
173++$ listing
174+ $% [%list p=?(%ordered %unordered %tasklist) q=(list listing) r=(list inline)]
175+ [%item p=(list inline)]
176+ ==
177+:: $block: post content that sits outside of the normal text
178+::
179+:: %image: a visual, we record dimensions for better rendering
180+:: %cite: an Urbit reference
181+:: %header: a traditional HTML heading, h1-h6
182+:: %listing: a traditional HTML list, ul and ol
183+:: %code: a block of code
184+::
185++$ block
186+ $% [%image src=cord height=@ud width=@ud alt=cord]
187+ [%cite =cite:c]
188+ [%header p=?(%h1 %h2 %h3 %h4 %h5 %h6) q=(list inline)]
189+ [%listing p=listing]
190+ [%rule ~]
191+ [%code code=cord lang=cord]
192+ ==
193+:: $inline: post content that flows within a paragraph
194+::
195+:: @t: plain text
196+:: %italics: italic text
197+:: %bold: bold text
198+:: %strike: strikethrough text
199+:: %inline-code: code formatting for small snippets
200+:: %blockquote: blockquote surrounded content
201+:: %block: link/reference to blocks
202+:: %code: code formatting for large snippets
203+:: %tag: tag gets special signifier
204+:: %link: link to a URL with a face
205+:: %break: line break
206+::
207++$ inline
208+ $@ @t
209+ $% [%italics p=(list inline)]
210+ [%bold p=(list inline)]
211+ [%strike p=(list inline)]
212+ [%blockquote p=(list inline)]
213+ [%inline-code p=cord]
214+ [%ship p=ship]
215+ [%block p=@ud q=cord]
216+ [%code p=cord]
217+ [%tag p=cord]
218+ [%link p=cord q=cord]
219+ [%task p=?(%.y %.n) q=(list inline)]
220+ [%break ~]
221+ ==
222+:: $log: a time ordered history of modifications to a diary
223+::
224++$ log
225+ ((mop time diff) lte)
226+++ log-on
227+ ((on time diff) lte)
228+::
229+:: $action: the complete set of data required to modify a diary
230+::
231++$ action
232+ (pair flag:g update)
233+::
234+:: $update: a representation in time of a modification to a diary
235+::
236++$ update
237+ (pair time diff)
238+::
239+:: $diff: the full suite of modifications that can be made to a diary
240+::
241++$ diff
242+ $% [%notes p=diff:notes]
243+ ::
244+ [%add-sects p=(set sect:g)]
245+ [%del-sects p=(set sect:g)]
246+ ::
247+ [%create p=perm q=notes]
248+ [%view p=view]
249+ [%sort p=sort]
250+ [%arranged-notes p=arranged-notes]
251+ ::
252+ ==
253+::
254+:: $net: an indicator of whether I'm a host or subscriber
255+::
256+:: %pub: am publisher/host with fresh log
257+:: %sub: subscribed to the ship at saga
258+::
259++$ net
260+ $% [%sub p=ship load=_| =saga:e]
261+ [%pub ~] :: TODO: permissions?
262+ ==
263+::
264+:: $briefs: a map of diary unread information
265+::
266+:: brief: the last time a diary was read, how many posts since,
267+:: and the id of the last read note
268+::
269+++ briefs
270+ =< briefs
271+ |%
272+ +$ briefs
273+ (map flag brief)
274+ +$ brief
275+ [last=time count=@ud read-id=(unit time)]
276+ +$ update
277+ (pair flag brief)
278+ --
279+:: $remark: a marker representing the last note I've read
280+::
281++$ remark
282+ [last-read=time watching=_| ~]
283+::
284++$ remark-action
285+ (pair flag remark-diff)
286+::
287++$ remark-diff
288+ $% [%read ~]
289+ [%read-at p=time]
290+ [?(%watch %unwatch) ~]
291+ ==
292+::
293+:: $perm: represents the permissions for a diary channel and gives a
294+:: pointer back to the group it belongs to.
295+::
296++$ perm
297+ $: writers=(set sect:g)
298+ group=flag:g
299+ ==
300+:: $join: a group + channel flag to join a channel, group required for perms
301+::
302++$ join
303+ $: group=flag:g
304+ chan=flag:g
305+ ==
306+:: $leave: a flag to pass for a channel leave
307+::
308++$ leave flag:g
309+::
310+:: $create: represents a request to create a channel
311+::
312+:: The name will be used as part of the flag which represents the
313+:: channel. $create is consumed by the diary agent first and then
314+:: passed to the groups agent to register the channel with the group.
315+::
316+:: Write permission is stored with the specific agent in the channel,
317+:: read permission is stored with the group's data.
318+::
319++$ create
320+ $: group=flag:g
321+ name=term
322+ title=cord
323+ description=cord
324+ readers=(set sect:g)
325+ writers=(set sect:g)
326+ ==
327++$ import [writers=(set ship) =association:met =update-log:gra =graph:gra]
328+::
329++$ imports (map flag import)
330+::
331+++ gra graph-store
332+++ orm-gra orm:lib-graph
333+++ orm-log-gra orm-log:lib-graph
334+++ met metadata-store
335+--
zod/seax/sur/epic.hoonnew file+15
@@ -0,0 +1,15 @@
1+|%
2+:: $saga: version synchronisation state
3+:: %dex: publisher is ahead
4+:: %lev: we are ahead
5+:: %chi: full sync
6+::
7++$ saga
8+ $% [%dex ver=@ud]
9+ [%lev ~]
10+ [%chi ~]
11+ ==
12+
13++$ epic @ud
14+::
15+--
zod/seax/sur/graph-store.hoonnew file+272
@@ -0,0 +1,272 @@
1+/- *post
2+|%
3++$ graph ((mop atom node) gth)
4++$ marked-graph [p=graph q=(unit mark)]
5+::
6++$ maybe-post (each post hash)
7++$ node [post=maybe-post children=internal-graph]
8++$ graphs (map resource marked-graph)
9+::
10++$ tag-queries (jug term uid)
11+::
12++$ update-log ((mop time logged-update) gth)
13++$ update-logs (map resource update-log)
14+::
15++$ internal-graph
16+ $~ [%empty ~]
17+ $% [%graph p=graph]
18+ [%empty ~]
19+ ==
20+::
21++$ network
22+ $: =graphs
23+ =tag-queries
24+ =update-logs
25+ archive=graphs
26+ ~
27+ ==
28+::
29++$ update [p=time q=action]
30+::
31++$ logged-update [p=time q=logged-action]
32+
33+::
34++$ logged-action
35+ $% [%add-graph =resource =graph mark=(unit mark) overwrite=?]
36+ [%add-nodes =resource nodes=(map index node)]
37+ [%remove-posts =resource indices=(set index)]
38+ [%add-signatures =uid =signatures]
39+ [%remove-signatures =uid =signatures]
40+ ==
41+::
42++$ action
43+ $% logged-action
44+ [%remove-graph =resource]
45+ ::
46+ [%add-tag =term =uid]
47+ [%remove-tag =term =uid]
48+ ::
49+ [%archive-graph =resource]
50+ [%unarchive-graph =resource]
51+ [%run-updates =resource =update-log]
52+ ::
53+ :: NOTE: cannot be sent as pokes
54+ ::
55+ [%keys =resources]
56+ [%tags tags=(set term)]
57+ [%tag-queries =tag-queries]
58+ ==
59+::
60++$ permissions
61+ [admin=permission-level writer=permission-level reader=permission-level]
62+::
63+:: $permission-level: levels of permissions in increasing order
64+::
65+:: %no: May not add/remove node
66+:: %self: May only nodes beneath nodes that were added by
67+:: the same pilot, may remove nodes that the pilot 'owns'
68+:: %yes: May add a node or remove node
69++$ permission-level
70+ ?(%no %self %yes)
71+::
72+:: %graph-store types version 2
73+::
74+++ two
75+ =< [. post-one]
76+ =, post-one
77+ |%
78+ +$ maybe-post (each post hash)
79+ ++ orm ((on atom node) gth)
80+ ++ orm-log ((on time logged-update) gth)
81+ ::
82+ +$ graph ((mop atom node) gth)
83+ +$ marked-graph [p=graph q=(unit mark)]
84+ ::
85+ +$ node [post=maybe-post children=internal-graph]
86+ +$ graphs (map resource marked-graph)
87+ ::
88+ +$ tag-queries (jug term resource)
89+ ::
90+ +$ update-log ((mop time logged-update) gth)
91+ +$ update-logs (map resource update-log)
92+ ::
93+ +$ internal-graph
94+ $~ [%empty ~]
95+ $% [%graph p=graph]
96+ [%empty ~]
97+ ==
98+ ::
99+ +$ network
100+ $: =graphs
101+ =tag-queries
102+ =update-logs
103+ archive=graphs
104+ validators=(set mark)
105+ ==
106+ ::
107+ +$ update [p=time q=action]
108+ ::
109+ +$ logged-update [p=time q=logged-action]
110+ ::
111+ +$ logged-action
112+ $% [%add-graph =resource =graph mark=(unit mark) overwrite=?]
113+ [%add-nodes =resource nodes=(map index node)]
114+ [%remove-nodes =resource indices=(set index)]
115+ [%add-signatures =uid =signatures]
116+ [%remove-signatures =uid =signatures]
117+ ==
118+ ::
119+ +$ action
120+ $% logged-action
121+ [%remove-graph =resource]
122+ ::
123+ [%add-tag =term =resource]
124+ [%remove-tag =term =resource]
125+ ::
126+ [%archive-graph =resource]
127+ [%unarchive-graph =resource]
128+ [%run-updates =resource =update-log]
129+ ::
130+ :: NOTE: cannot be sent as pokes
131+ ::
132+ [%keys =resources]
133+ [%tags tags=(set term)]
134+ [%tag-queries =tag-queries]
135+ ==
136+ --
137+::
138+:: %graph-store types version 1
139+::
140+++ one
141+ =< [. post-one]
142+ =, post-one
143+ |%
144+ ++ orm ((on atom node) gth)
145+ ++ orm-log ((on time logged-update) gth)
146+ ::
147+ +$ graph ((mop atom node) gth)
148+ +$ marked-graph [p=graph q=(unit mark)]
149+ ::
150+ +$ node [=post children=internal-graph]
151+ +$ graphs (map resource marked-graph)
152+ ::
153+ +$ tag-queries (jug term resource)
154+ ::
155+ +$ update-log ((mop time logged-update) gth)
156+ +$ update-logs (map resource update-log)
157+ ::
158+ +$ internal-graph
159+ $~ [%empty ~]
160+ $% [%graph p=graph]
161+ [%empty ~]
162+ ==
163+ ::
164+ +$ network
165+ $: =graphs
166+ =tag-queries
167+ =update-logs
168+ archive=graphs
169+ validators=(set mark)
170+ ==
171+ ::
172+ +$ update [p=time q=action]
173+ ::
174+ +$ logged-update [p=time q=logged-action]
175+ ::
176+ +$ logged-action
177+ $% [%add-graph =resource =graph mark=(unit mark) overwrite=?]
178+ [%add-nodes =resource nodes=(map index node)]
179+ [%remove-nodes =resource indices=(set index)]
180+ [%add-signatures =uid =signatures]
181+ [%remove-signatures =uid =signatures]
182+ ==
183+ ::
184+ +$ action
185+ $% logged-action
186+ [%remove-graph =resource]
187+ ::
188+ [%add-tag =term =resource]
189+ [%remove-tag =term =resource]
190+ ::
191+ [%archive-graph =resource]
192+ [%unarchive-graph =resource]
193+ [%run-updates =resource =update-log]
194+ ::
195+ :: NOTE: cannot be sent as pokes
196+ ::
197+ [%keys =resources]
198+ [%tags tags=(set term)]
199+ [%tag-queries =tag-queries]
200+ ==
201+ --
202+::
203+:: %graph-store types version 0
204+::
205+++ zero
206+ =< [. post-zero]
207+ =, post-zero
208+ |%
209+ ++ orm ((ordered-map atom node) gth)
210+ ++ orm-log ((ordered-map time logged-update) gth)
211+ ::
212+ +$ graph ((mop atom node) gth)
213+ +$ marked-graph [p=graph q=(unit mark)]
214+ ::
215+ +$ node [=post children=internal-graph]
216+ +$ graphs (map resource marked-graph)
217+ ::
218+ +$ tag-queries (jug term resource)
219+ ::
220+ +$ update-log ((mop time logged-update) gth)
221+ +$ update-logs (map resource update-log)
222+ ::
223+ ::
224+ +$ internal-graph
225+ $~ [%empty ~]
226+ $% [%graph p=graph]
227+ [%empty ~]
228+ ==
229+ ::
230+ +$ network
231+ $: =graphs
232+ =tag-queries
233+ =update-logs
234+ archive=graphs
235+ validators=(set mark)
236+ ==
237+ ::
238+ +$ update
239+ $% [%0 p=time q=update-0]
240+ ==
241+ ::
242+ +$ logged-update
243+ $% [%0 p=time q=logged-update-0]
244+ ==
245+ ::
246+ +$ logged-update-0
247+ $% [%add-graph =resource =graph mark=(unit mark) overwrite=?]
248+ [%add-nodes =resource nodes=(map index node)]
249+ [%remove-nodes =resource indices=(set index)]
250+ [%add-signatures =uid =signatures]
251+ [%remove-signatures =uid =signatures]
252+ ==
253+ ::
254+ +$ update-0
255+ $% logged-update-0
256+ [%remove-graph =resource]
257+ ::
258+ [%add-tag =term =resource]
259+ [%remove-tag =term =resource]
260+ ::
261+ [%archive-graph =resource]
262+ [%unarchive-graph =resource]
263+ [%run-updates =resource =update-log]
264+ ::
265+ :: NOTE: cannot be sent as pokes
266+ ::
267+ [%keys =resources]
268+ [%tags tags=(set term)]
269+ [%tag-queries =tag-queries]
270+ ==
271+ --
272+--
zod/seax/sur/group-store.hoonnew file+39
@@ -0,0 +1,39 @@
1+/- *group, *resource
2+^?
3+|%
4+::
5+:: $action: request to change group-store state
6+::
7+:: %add-group: add a group
8+:: %add-members: add members to a group
9+:: %remove-members: remove members from a group
10+:: %add-tag: add a tag to a set of ships
11+:: %remove-tag: remove a tag from a set of ships
12+:: %change-policy: change a group's policy
13+:: %remove-group: remove a group from the store
14+:: %expose: unset .hidden flag
15+::
16++$ action
17+ $% [%add-group =resource =policy hidden=?]
18+ [%add-members =resource ships=(set ship)]
19+ [%remove-members =resource ships=(set ship)]
20+ [%add-tag =resource =tag ships=(set ship)]
21+ [%remove-tag =resource =tag ships=(set ship)]
22+ [%change-policy =resource =diff:policy]
23+ [%remove-group =resource ~]
24+ [%expose =resource ~]
25+ ==
26+:: $update: a description of a processed state change
27+::
28+:: %initial: describe groups upon new subscription
29+::
30++$ update
31+ $% initial
32+ action
33+ ==
34++$ initial
35+ $% [%initial-group =resource =group]
36+ [%initial =groups]
37+ ==
38+--
39+
zod/seax/sur/group.hoonnew file+109
@@ -0,0 +1,109 @@
1+/- *resource
2+::
3+^?
4+|%
5+::
6+++ groups-state-one
7+ |%
8+ +$ groups (map resource group)
9+ ::
10+ +$ tag $@(group-tag [app=term tag=term])
11+ ::
12+ +$ tags (jug tag ship)
13+ ::
14+ +$ group
15+ $: members=(set ship)
16+ =tags
17+ =policy
18+ hidden=?
19+ ==
20+ --
21+:: $groups: a mapping from group-ids to groups
22+::
23++$ groups (map resource group)
24+:: $group-tag: an identifier used by groups
25+::
26+:: These tags should have precise semantics, as they are shared across all
27+:: apps.
28+::
29++$ group-tag ?(role-tag)
30+:: $tag: an identifier used to identify a subset of members
31+::
32+:: Tags may be used and recognised differently across apps.
33+:: for example, you could use tags like `%author`, `%bot`, `%flagged`...
34+::
35++$ tag $@(group-tag [app=term =resource tag=term])
36+:: $role-tag: a kind of $group-tag that identifies a privileged user
37+::
38+:: These roles are
39+:: %admin: Administrator, can do everything except delete the group
40+:: %moderator: Moderator, can add/remove/ban users
41+:: %janitor: Has no special meaning inside group-store,
42+:: but may be given additional privileges in other apps.
43+::
44++$ role-tag
45+ ?(%admin %moderator %janitor)
46+:: $tags: a mapping from a $tag to the members it identifies
47+::
48++$ tags (jug tag ship)
49+:: $group: description of a group of users
50+::
51+:: .members: members of the group
52+:: .tag-queries: a map of tags to subsets of members
53+:: .policy: permissions for the group
54+:: .hidden: is group unmanaged
55++$ group
56+ $: members=(set ship)
57+ =tags
58+ =policy
59+ hidden=?
60+ ==
61+:: $policy: access control for a group
62+::
63+++ policy
64+ =< policy
65+ |%
66+ ::
67+ +$ policy
68+ $% invite
69+ open
70+ ==
71+ :: $diff: change group policy
72+ +$ diff
73+ $% [%invite diff:invite]
74+ [%open diff:open]
75+ [%replace =policy]
76+ ==
77+ :: $invite: allow only invited ships
78+ ++ invite
79+ =< invite-policy
80+ |%
81+ ::
82+ +$ invite-policy
83+ [%invite pending=(set ship)]
84+ :: $diff: add or remove invites
85+ ::
86+ +$ diff
87+ $% [%add-invites invitees=(set ship)]
88+ [%remove-invites invitees=(set ship)]
89+ ==
90+ --
91+ :: $open: allow all unbanned ships of approriate rank
92+ ::
93+ ++ open
94+ =< open-policy
95+ |%
96+ ::
97+ +$ open-policy
98+ [%open ban-ranks=(set rank:title) banned=(set ship)]
99+ :: $diff: ban or allow ranks and ships
100+ ::
101+ +$ diff
102+ $% [%allow-ranks ranks=(set rank:title)]
103+ [%ban-ranks ranks=(set rank:title)]
104+ [%ban-ships ships=(set ship)]
105+ [%allow-ships ships=(set ship)]
106+ ==
107+ --
108+ --
109+--
zod/seax/sur/groups.hoonnew file+364
@@ -0,0 +1,364 @@
1+/- meta, e=epic
2+/- old=group
3+/- grp=group-store
4+/- metadata-store
5+|%
6+++ okay `epic:e`2
7+++ mar
8+ |%
9+ ++ act `mark`(rap 3 %group-action '-' (scot %ud okay) ~)
10+ ++ upd `mark`(rap 3 %group-update '-' (scot %ud okay) ~)
11+ ++ log `mark`(rap 3 %group-log '-' (scot %ud okay) ~)
12+ ++ int `mark`(rap 3 %group-init '-' (scot %ud okay) ~)
13+ --
14+:: $flag: ID for a group
15+::
16++$ flag (pair ship term)
17+::
18+:: $nest: ID for a channel, {app}/{ship}/{name}
19+::
20++$ nest (pair dude:gall flag)
21+::
22+:: $sect: ID for cabal, similar to a role
23+::
24++$ sect term
25+::
26+:: $zone: channel grouping
27+::
28+:: includes its own metadata for display and keeps the order of
29+:: channels within.
30+::
31+:: zone: the term that represents the ID of a zone
32+:: realm: the metadata representing the zone and the order of channels
33+:: delta: the set of actions that can be taken on a zone
34+:: %add: create a zone
35+:: %del: delete the zone
36+:: %edit: modify the zone metadata
37+:: %mov: reorders the zone in the group
38+:: %mov-nest: reorders a channel within the zone
39+::
40+++ zone
41+ =< zone
42+ |%
43+ +$ zone @tas
44+ +$ realm
45+ $: met=data:meta
46+ ord=(list nest)
47+ ==
48+ +$ diff (pair zone delta)
49+ +$ delta
50+ $% [%add meta=data:meta]
51+ [%del ~]
52+ [%edit meta=data:meta]
53+ [%mov idx=@ud]
54+ [%mov-nest =nest idx=@ud]
55+ ==
56+ --
57+::
58+:: $fleet: group members and their associated metadata
59+::
60+:: vessel: a user's set of sects or roles and the time that they joined
61+:: @da default represents an admin added member that has yet to join
62+::
63+++ fleet
64+ =< fleet
65+ |%
66+ +$ fleet (map ship vessel)
67+ +$ vessel
68+ $: sects=(set sect)
69+ joined=time
70+ ==
71+ +$ diff
72+ $% [%add ~]
73+ [%del ~]
74+ [%add-sects sects=(set sect)]
75+ [%del-sects sects=(set sect)]
76+ ==
77+ --
78+::
79+:: $channel: a medium for interaction
80+::
81+++ channel
82+ =< channel
83+ |%
84+ +$ preview
85+ $: =nest
86+ meta=data:meta
87+ group=^preview
88+ ==
89+ ::
90+ +$ channels (map nest channel)
91+ ::
92+ :: $channel: a collection of metadata about a specific agent integration
93+ ::
94+ :: meta: title, description, image, cover
95+ :: added: when the channel was created
96+ :: zone: what zone or section to bucket in
97+ :: join: should the channel be joined by new members
98+ :: readers: what sects can see the channel, empty means anyone
99+ ::
100+ +$ channel
101+ $: meta=data:meta
102+ added=time
103+ =zone
104+ join=?
105+ readers=(set sect)
106+ ==
107+ ::
108+ :: $diff: represents the set of actions you can take on a channel
109+ ::
110+ :: add: create a channel
111+ :: edit: edit a channel
112+ :: del: delete a channel
113+ :: add-sects: add sects to readers
114+ :: del-sects: delete sects from readers
115+ :: zone: change the zone of the channel
116+ :: join: toggle default join
117+ ::
118+ +$ diff
119+ $% [%add =channel]
120+ [%edit =channel]
121+ [%del ~]
122+ ::
123+ [%add-sects sects=(set sect)]
124+ [%del-sects sects=(set sect)]
125+ ::
126+ [%zone =zone]
127+ ::
128+ [%join join=_|]
129+ ==
130+ --
131+::
132+:: $group: collection of people and the pathways in which they interact
133+::
134+:: group holds all data around members, permissions, channel
135+:: organization, and its own metadata to represent the group
136+::
137++$ group
138+ $: =fleet
139+ cabals=(map sect cabal)
140+ zones=(map zone realm:zone)
141+ zone-ord=(list zone)
142+ =bloc
143+ =channels:channel
144+ imported=(set nest)
145+ =cordon
146+ secret=?
147+ meta=data:meta
148+ ==
149+::
150++$ group-ui [group saga=(unit saga:e)]
151+:: $cabal: metadata representing a $sect or role
152+::
153+++ cabal
154+ =< cabal
155+ |%
156+ ::
157+ +$ cabal
158+ [meta=data:meta ~]
159+ ::
160+ +$ diff
161+ $% [%add meta=data:meta]
162+ [%edit meta=data:meta]
163+ [%del ~]
164+ ==
165+ --
166+::
167+:: $cordon: group entry and visibility permissions
168+::
169+++ cordon
170+ =< cordon
171+ |%
172+ ::
173+ :: $open: a group with open entry, only bans are barred entry
174+ ::
175+ ++ open
176+ |%
177+ :: $ban: set of ships and ranks/classes that are not allowed entry
178+ ::
179+ :: bans can either be done at the individual ship level or by the
180+ :: rank level (comet/moon/etc.)
181+ ::
182+ +$ ban [ships=(set ship) ranks=(set rank:title)]
183+ +$ diff
184+ $% [%add-ships p=(set ship)]
185+ [%del-ships p=(set ship)]
186+ ::
187+ [%add-ranks p=(set rank:title)]
188+ [%del-ranks p=(set rank:title)]
189+ ==
190+ --
191+ ::
192+ :: $shut: a group with closed entry, everyone barred entry
193+ ::
194+ :: a shut cordon means that the group is closed, but still visible.
195+ :: people may request entry and either be accepted or denied or
196+ :: they may be invited directly
197+ ::
198+ :: ask: represents those requesting entry
199+ :: pending: represents those who've been invited
200+ ::
201+ ++ shut
202+ |%
203+ +$ state [pend=(set ship) ask=(set ship)]
204+ +$ kind ?(%ask %pending)
205+ +$ diff
206+ $% [%add-ships p=kind q=(set ship)]
207+ [%del-ships p=kind q=(set ship)]
208+ ==
209+ --
210+ ::
211+ :: $cordon: a set of metadata to represent the entry policy for a group
212+ ::
213+ :: open: a group with open entry, only bans barred entry
214+ :: shut: a group with closed entry, everyone barred entry
215+ :: afar: a custom entry policy defined by another agent
216+ ::
217+ +$ cordon
218+ $% [%shut state:shut]
219+ [%afar =flag =path desc=@t]
220+ [%open =ban:open]
221+ ==
222+ ::
223+ :: $diff: the actions you can take on a cordon
224+ ::
225+ +$ diff
226+ $% [%shut p=diff:shut]
227+ [%open p=diff:open]
228+ [%swap p=cordon]
229+ ==
230+ --
231+::
232+:: $bloc: superuser sects
233+::
234+:: sects in the bloc set are allowed to make modifications to the group
235+:: and its various metadata and permissions
236+::
237+++ bloc
238+ =< bloc
239+ |%
240+ +$ bloc (set sect)
241+ +$ diff
242+ $% [%add p=(set sect)]
243+ [%del p=(set sect)]
244+ ==
245+ --
246+::
247+:: $diff: the general set of changes that can be made to a group
248+::
249++$ diff
250+ $% [%fleet p=(set ship) q=diff:fleet]
251+ [%cabal p=sect q=diff:cabal]
252+ [%channel p=nest q=diff:channel]
253+ [%bloc p=diff:bloc]
254+ [%cordon p=diff:cordon]
255+ [%zone p=diff:zone]
256+ [%meta p=data:meta]
257+ [%secret p=?]
258+ [%create p=group]
259+ [%del ~]
260+ ==
261+::
262+:: $action: the complete set of data required to edit a group
263+::
264++$ action
265+ (pair flag update)
266+::
267+:: $update: a representation in time of a modification of a group
268+::
269++$ update
270+ (pair time diff)
271+::
272+:: $create: a request to make a group
273+::
274++$ create
275+ $: name=term
276+ title=cord
277+ description=cord
278+ image=cord
279+ cover=cord
280+ =cordon
281+ members=(jug ship sect)
282+ secret=?
283+ ==
284+::
285++$ init [=time =group]
286+::
287+:: $groups-ui: map for frontend to display groups
288++$ groups-ui
289+ (map flag group-ui)
290++$ groups
291+ (map flag group)
292++$ net-groups
293+ (map flag [net group])
294+::
295+:: $log: a time ordered map of all modifications to groups
296+::
297++$ log
298+ ((mop time diff) lte)
299+::
300+++ log-on
301+ ((on time diff) lte)
302+::
303+:: $net: an indicator of whether I'm a host or subscriber
304+::
305++$ net
306+ $~ [%pub ~]
307+ $% [%pub p=log]
308+ [%sub p=time load=_| =saga:e]
309+ ==
310+::
311+:: $join: a join request, can elect to join all channels
312+::
313++$ join
314+ $: =flag
315+ join-all=?
316+ ==
317+::
318+:: $knock: a request to enter a closed group
319+::
320++$ knock flag
321+::
322+:: $progress: the state of a group join
323+::
324++$ progress
325+ ?(%knocking %adding %watching %done %error)
326+::
327+:: $claim: a mark for gangs to represent a join in progress
328+::
329++$ claim
330+ $: join-all=?
331+ =progress
332+ ==
333+::
334+:: $preview: the metadata and entry policy for a group
335+::
336++$ preview
337+ $: =flag
338+ meta=data:meta
339+ =cordon
340+ =time
341+ secret=?
342+ ==
343+::
344++$ previews (map flag preview)
345+::
346+:: $invite: a marker to show you've been invited to a group
347+::
348++$ invite (pair flag ship)
349+::
350+:: $gang: view of foreign group
351+::
352++$ gang
353+ $: cam=(unit claim)
354+ pev=(unit preview)
355+ vit=(unit invite)
356+ ==
357+::
358++$ gangs (map flag gang)
359+++ met metadata-store
360+::
361++$ import [self=association:met chan=(map flag =association:met) roles=(set flag) =group:old]
362+::
363++$ imports (map flag import)
364+--
zod/seax/sur/hark-store.hoonnew file+159
@@ -0,0 +1,159 @@
1+^?
2+::
3+:: %hark-store: Notification, unreads store
4+::
5+:: Timeboxing & binning:
6+::
7+:: Unread notifications accumulate in $unreads. They are grouped by
8+:: their $bin. A notification may become read by either:
9+:: a) being read by a %read-count or %read-each or %read-note
10+:: b) being read by a %seen
11+::
12+:: If a) then we insert the corresponding bin into $reads at the
13+:: current timestamp
14+:: If b) then we empty $unreads and move all bins to $reads at the
15+:: current timestamp
16+::
17+:: Unread tracking:
18+:: Unread tracking has two 'modes' which may be used concurrently,
19+:: if necessary.
20+::
21+:: count:
22+:: This stores the unreads as a simple atom, describing the number
23+:: of unread items. May be increased with %unread-count and
24+:: set to zero with %read-count. Ideal for high-frequency linear
25+:: datastructures, e.g. chat
26+:: each:
27+:: This stores the unreads as a set of paths, describing the set of
28+:: unread items. Unreads may be added to the set with %unread-each
29+:: and removed with %read-each. Ideal for non-linear, low-frequency
30+:: datastructures, e.g. blogs
31+::
32+|%
33+:: $place: A location, under which landscape stores stats
34+::
35+:: .desk must match q.byk.bowl
36+:: Examples:
37+:: A chat:
38+:: [%landscape /~dopzod/urbit-help]
39+:: A note in a notebook:
40+:: [%landscape /~darrux-landes/feature-requests/12374893234232]
41+:: A group:
42+:: [%hark-group-hook /~bitbet-bolbel/urbit-community]
43+:: Comments on a link
44+:: [%landscape /~dabben-larbet/urbit-in-the-news/17014118450499614194868/2]
45+::
46++$ place [=desk =path]
47+::
48+:: $bin: Identifier for grouping notifications
49+::
50+:: Examples
51+:: A mention in a chat:
52+:: [/mention %landscape /~dopzod/urbit-help]
53+:: New messages in a chat
54+:: [/message %landscape /~dopzod/urbit-help]
55+:: A new comment in a notebook:
56+:: [/comment %landscape /~darrux-landes/feature-requests/12374893234232/2]
57+::
58++$ bin [=path =place]
59+::
60+:: $lid: Reference to a timebox
61+::
62++$ lid
63+ $% [%archive =time]
64+ [%seen ~]
65+ [%unseen ~]
66+ ==
67+:: $content: Notification content
68++$ content
69+ $% [%ship =ship]
70+ [%text =cord]
71+ ==
72+::
73+:: $body: A notification body
74+::
75++$ body
76+ $: title=(list content)
77+ content=(list content)
78+ =time
79+ binned=path
80+ link=path
81+ ==
82+::
83++$ notification
84+ [date=@da =bin body=(list body)]
85+:: $timebox: Group of notificatons
86++$ timebox
87+ (map bin notification)
88+:: $archive: Archived notifications, ordered by time
89++$ archive
90+ ((mop @da timebox) gth)
91+::
92++$ action
93+ $% :: hook actions
94+ ::
95+ :: %add-note: add a notification
96+ [%add-note =bin =body]
97+ ::
98+ :: %del-place: Underlying resource disappeared, remove all
99+ :: associated notifications
100+ [%del-place =place]
101+ :: %unread-count: Change unread count by .count
102+ [%unread-count =place inc=? count=@ud]
103+ :: %unread-each: Add .path to list of unreads for .place
104+ [%unread-each =place =path]
105+ :: %saw-place: Update last-updated for .place to now.bowl
106+ [%saw-place =place time=(unit time)]
107+ :: store actions
108+ ::
109+ :: %archive: archive single notification
110+ :: if .time is ~, then archiving unread notification
111+ :: else, archiving read notification
112+ [%archive =lid =bin]
113+ :: %read-count: set unread count to zero
114+ [%read-count =place]
115+ :: %read-each: remove path from unreads for .place
116+ [%read-each =place =path]
117+ :: %read-note: Read note at .bin
118+ [%read-note =bin]
119+ :: %archive-all: Archive all notifications
120+ [%archive-all ~]
121+ :: %opened: User opened notifications, reset timeboxing logic.
122+ ::
123+ [%opened ~]
124+ ::
125+ :: XX: previously in hark-store, now deprecated
126+ :: the hooks responsible for creating notifications may offer pokes
127+ :: similar to this
128+ :: [%read-graph =resource]
129+ :: [%read-group =resource]
130+ :: [%remove-graph =resource]
131+ ::
132+ ==
133+:: .stats: Statistics for a .place
134+::
135++$ stats
136+ $: count=@ud
137+ each=(set path)
138+ last=@da
139+ timebox=(unit @da)
140+ ==
141+::
142++$ update
143+ $% action
144+ :: %more: more updates
145+ [%archived =time =lid =notification]
146+ [%more more=(list update)]
147+ :: %note-read: note has been read with timestamp
148+ [%note-read =time =bin]
149+ [%added =notification]
150+ :: %timebox: description of timebox.
151+ ::
152+ [%timebox =lid =(list notification)]
153+ :: %place-stats: description of .stats for a .place
154+ [%place-stats =place =stats]
155+ :: %place-stats: stats for all .places
156+ [%all-stats places=(map place stats)]
157+ ==
158+--
159+
zod/seax/sur/meta.hoonnew file+21
@@ -0,0 +1,21 @@
1+|%
2+:: $data: generic metadata for various entities
3+::
4+:: title: the pretty text representing what something is called
5+:: description: a longer text entry giving a detailed summary
6+:: image: an image URL or color string used as an icon/avatar
7+:: cover: an image URL or color string, used as a header
8+::
9++$ data
10+ $: title=cord
11+ description=cord
12+ image=cord
13+ cover=cord
14+ ==
15++$ diff
16+ $% [%title =cord]
17+ [%description =cord]
18+ [%image =cord]
19+ [%cover =cord]
20+ ==
21+--
zod/seax/sur/metadata-store.hoonnew file+138
@@ -0,0 +1,138 @@
1+/- *resource
2+^?
3+|%
4+::
5++$ app-name term
6++$ md-resource [=app-name =resource]
7++$ association [group=resource =metadatum]
8++$ associations (map md-resource association)
9++$ group-preview
10+ $: group=resource
11+ channels=associations
12+ members=@ud
13+ channel-count=@ud
14+ =metadatum
15+ ==
16+::
17++$ color @ux
18++$ url @t
19+::
20+:: $vip-metadata: variation in permissions
21+::
22+:: This will be passed to the graph-permissions mark
23+:: conversion to allow for custom permissions.
24+::
25+:: %reader-comments: Allow readers to comment, regardless
26+:: of whether they can write. (notebook, collections)
27+:: %member-metadata: Allow members to add channels (groups)
28+:: %host-feed: Only host can post to group feed
29+:: %admin-feed: Only admins and host can post to group feed
30+:: %$: No variation
31+::
32++$ vip-metadata
33+ $? %reader-comments
34+ %member-metadata
35+ %host-feed
36+ %admin-feed
37+ %$
38+ ==
39+::
40++$ md-config
41+ $~ [%empty ~]
42+ $% [%group feed=(unit (unit md-resource))]
43+ [%graph module=term]
44+ [%empty ~]
45+ ==
46+::
47++$ edit-field
48+ $% [%title title=cord]
49+ [%description description=cord]
50+ [%color color=@ux]
51+ [%picture =url]
52+ [%preview preview=?]
53+ [%hidden hidden=?]
54+ [%vip vip=vip-metadata]
55+ ==
56+::
57++$ metadatum
58+ $: title=cord
59+ description=cord
60+ =color
61+ date-created=time
62+ creator=ship
63+ config=md-config
64+ picture=url
65+ preview=?
66+ hidden=?
67+ vip=vip-metadata
68+ ==
69+::
70++$ action
71+ $% [%add group=resource resource=md-resource =metadatum]
72+ [%remove group=resource resource=md-resource]
73+ [%edit group=resource resource=md-resource =edit-field]
74+ [%initial-group group=resource =associations]
75+ ==
76+::
77++$ hook-update
78+ $% [%req-preview group=resource]
79+ [%preview group-preview]
80+ ==
81+::
82++$ update
83+ $% action
84+ [%associations =associations]
85+ $: %updated-metadata
86+ group=resource
87+ resource=md-resource
88+ before=metadatum
89+ =metadatum
90+ ==
91+ ==
92+:: historical
93+++ one
94+ |%
95+ ::
96+ +$ action
97+ $~ [%remove *resource *md-resource]
98+ $< %edit ^action
99+ ::
100+ +$ update
101+ $~ [%remove *resource *md-resource]
102+ $< %edit ^update
103+ ::
104+ --
105+++ zero
106+ |%
107+ ::
108+ +$ association [group=resource =metadatum]
109+ ::
110+ +$ associations (map md-resource association)
111+ ::
112+ +$ metadatum
113+ $: title=cord
114+ description=cord
115+ =color
116+ date-created=time
117+ creator=ship
118+ module=term
119+ picture=url
120+ preview=?
121+ vip=vip-metadata
122+ ==
123+ ::
124+ +$ update
125+ $% [%add group=resource resource=md-resource =metadatum]
126+ [%remove group=resource resource=md-resource]
127+ [%initial-group group=resource =associations]
128+ [%associations =associations]
129+ $: %updated-metadata
130+ group=resource
131+ resource=md-resource
132+ before=metadatum
133+ =metadatum
134+ ==
135+ ==
136+ ::
137+ --
138+--
zod/seax/sur/notes.hoonnew file+74
@@ -0,0 +1,74 @@
1+|%
2++$ diary
3+ $: *
4+ *
5+ *
6+ *
7+ *
8+ =notes
9+ *
10+ ==
11++$ seal
12+ $: =time
13+ * :: =quips
14+ * :: feels=(map ship feel)
15+ ==
16++$ note [seal essay]
17++$ verse
18+ $% [%block p=block]
19+ [%inline p=(list inline)]
20+ ==
21++$ listing
22+ $% [%list p=?(%ordered %unordered) q=(list listing) r=(list inline)]
23+ [%item p=(list inline)]
24+ ==
25++$ block
26+ $% [%image src=cord height=@ud width=@ud alt=cord]
27+ [%cite *] :: =cite:c]
28+ [%header p=?(%h1 %h2 %h3 %h4 %h5 %h6) q=(list inline)]
29+ [%listing p=listing]
30+ [%rule ~]
31+ [%code code=cord lang=cord]
32+ ==
33++$ inline
34+ $@ @t
35+ $% [%italics p=(list inline)]
36+ [%bold p=(list inline)]
37+ [%strike p=(list inline)]
38+ [%blockquote p=(list inline)]
39+ [%inline-code p=cord]
40+ [%ship p=ship]
41+ [%block p=@ud q=cord]
42+ [%code p=cord]
43+ [%tag p=cord]
44+ [%link p=cord q=cord]
45+ [%break ~]
46+ ==
47++$ essay
48+ $: title=@t
49+ image=@t
50+ content=(list verse)
51+ author=ship
52+ sent=time
53+ ==
54+++ notes
55+ =< rock
56+ |%
57+ +$ rock
58+ ((mop time note) lte)
59+ ++ on
60+ ((^on time note) lte)
61+ +$ diff
62+ (pair time delta)
63+ +$ delta
64+ $% [%add p=essay]
65+ [%edit p=essay]
66+ [%del ~]
67+ [%quips *] :: p=diff:quips]
68+ [%add-feel p=ship *] :: q=feel]
69+ [%del-feel p=ship]
70+ ==
71+ --
72++$ shelf (map flag diary)
73++$ flag (pair ship term)
74+--
zod/seax/sur/post.hoonnew file+91
@@ -0,0 +1,91 @@
1+/- *resource
2+|%
3++$ index (list atom)
4++$ uid [=resource =index]
5+::
6+:: +sham (half sha-256) hash of +validated-portion
7++$ hash @ux
8+::
9++$ signature [p=@ux q=ship r=life]
10++$ signatures (set signature)
11++$ post
12+ $: author=ship
13+ =index
14+ time-sent=time
15+ contents=(list content)
16+ hash=(unit hash)
17+ =signatures
18+ ==
19+::
20++$ indexed-post [a=atom p=post]
21+::
22++$ validated-portion
23+ $: parent-hash=(unit hash)
24+ author=ship
25+ time-sent=time
26+ contents=(list content)
27+ ==
28+::
29++$ reference
30+ $% [%graph group=resource =uid]
31+ [%group group=resource]
32+ [%app =ship =desk =path]
33+ ==
34+::
35++$ content
36+ $% [%text text=cord]
37+ [%mention =ship]
38+ [%url url=cord]
39+ [%code expression=cord output=(list tank)]
40+ [%reference =reference]
41+ ==
42+::
43+++ post-one
44+ |%
45+ ::
46+ +$ indexed-post [a=atom p=post]
47+ ::
48+ +$ post
49+ $: author=ship
50+ =index
51+ time-sent=time
52+ contents=(list content)
53+ hash=(unit hash)
54+ =signatures
55+ ==
56+ ::
57+ +$ content
58+ $% [%text text=cord]
59+ [%mention =ship]
60+ [%url url=cord]
61+ [%code expression=cord output=(list tank)]
62+ [%reference =reference]
63+ ==
64+ ::
65+ +$ reference
66+ $% [%graph group=resource =uid]
67+ [%group group=resource]
68+ ==
69+ --
70+::
71+++ post-zero
72+ |%
73+ ::
74+ +$ content
75+ $% [%text text=cord]
76+ [%mention =ship]
77+ [%url url=cord]
78+ [%code expression=cord output=(list tank)]
79+ [%reference =uid]
80+ ==
81+ ::
82+ +$ post
83+ $: author=ship
84+ =index
85+ time-sent=time
86+ contents=(list content)
87+ hash=(unit hash)
88+ =signatures
89+ ==
90+ --
91+--
zod/seax/sur/pull-hook.hoonnew file+11
@@ -0,0 +1,11 @@
1+/- *resource
2+|%
3++$ action
4+ $% [%add =ship =resource]
5+ [%remove =resource]
6+ ==
7+::
8++$ update
9+ $% [%tracking tracking=(map resource ship)]
10+ ==
11+--
zod/seax/sur/resource.hoonnew file+10
@@ -0,0 +1,10 @@
1+^?
2+|%
3++$ resource [=entity name=term]
4++$ resources (set resource)
5+::
6++$ entity
7+ $@ ship
8+ $% !!
9+ ==
10+--
zod/seax/sur/spider.hoonnew file+27
@@ -0,0 +1,27 @@
1+/+ libstrand=strand
2+=, strand=strand:libstrand
3+|%
4++$ thread $-(vase shed:khan)
5++$ input [=tid =cage]
6++$ tid tid:strand
7++$ bowl bowl:strand
8++$ http-error
9+ $? %bad-request :: 400
10+ %forbidden :: 403
11+ %nonexistent :: 404
12+ %offline :: 504
13+ ==
14++$ start-args
15+ $: parent=(unit tid)
16+ use=(unit tid)
17+ =beak
18+ file=term
19+ =vase
20+ ==
21++$ inline-args
22+ $: parent=(unit tid)
23+ use=(unit tid)
24+ =beak
25+ =shed:khan
26+ ==
27+--