mirror of
https://github.com/urbit/shrub.git
synced 2024-12-14 01:08:54 +03:00
Merge branch 'master' of https://github.com/urbit/urbit
This commit is contained in:
commit
a06b2cb956
@ -1,75 +0,0 @@
|
||||
::
|
||||
::
|
||||
::::
|
||||
::
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
;html
|
||||
;head
|
||||
;title: Urbit: Personal Cloud Computing
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div(class "page documentation")
|
||||
;h1(class "page-title"): Documentation
|
||||
;p ; If you want to build a deep understanding of how Urbit works,
|
||||
; start with Nock. If you would prefer to just try stuff
|
||||
; out, start with Arvo.
|
||||
==
|
||||
;p ; This documentation is a work in progress. Feedback and corrections
|
||||
; are welcome. Pull requests are encouraged. The repo for this site
|
||||
; lives ;{a(href "https://github.com/urbit/urbit.github.io") "here"}.
|
||||
; We would love your help in making this reference more useful.
|
||||
==
|
||||
;p ; Arvo is still actively being changed and updated.
|
||||
; As Arvo development cools, more documentation will emerge.
|
||||
==
|
||||
;ul
|
||||
;li
|
||||
;p:(h2:"Tutorial")
|
||||
;strong: Nock
|
||||
;ol
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/nock1":"Intro to Nock"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/nock2":"Nock is Easy"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/nock3":"Using Nock"))
|
||||
==
|
||||
;strong: Hoon
|
||||
;ol
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon1":"Intro to Hoon"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon2":"Types"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon3":"Hoon Computes"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon4":"Gates"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon5":"Tiles"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon6":"Type Inference"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon7":"Odds, Ends, Quirks"))
|
||||
==
|
||||
;strong: Arvo
|
||||
;ol
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/arvo1":"Basic Arvo"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/arvo2":"More Basic Arvo"))
|
||||
==
|
||||
==
|
||||
;li
|
||||
;p:(h2:"Reference")
|
||||
;ul
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/ref/foreword":";{strong "Foreword"}: Nock"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/ref/preface":";{strong "Preface"}: Hoon Abstract"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/ref/vol0":";{strong "Volume 0"}: Version Stub"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/ref/vol1":";{strong "Volume 1"}: Hoon Structures"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/ref/vol2":";{strong "Volume 2"}: Hoon Compiler"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/ref/vol3":";{strong "Volume 3"}: Arvo Core"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/ref/vol4":";{strong "Volume 4"}: Arvo Vanes"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/ref/postface":";{strong "Postface"}"))
|
||||
==
|
||||
==
|
||||
==
|
||||
==
|
||||
==
|
||||
==
|
||||
==
|
@ -1,26 +1,67 @@
|
||||
:: Top level of the Urbit documentation.
|
||||
::
|
||||
:::: /hook/site/src/pub
|
||||
::
|
||||
::::
|
||||
::
|
||||
/= bod /^ manx /: /===/pub/src/doc/intro /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/intro /psal/
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
;html
|
||||
;head
|
||||
;title: Urbit
|
||||
;title: Urbit: Personal Cloud Computing
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;div(class "page documentation")
|
||||
;+ bod
|
||||
;h1(class "page-title"): Documentation
|
||||
;p ; This documentation is a work in progress. Feedback and corrections
|
||||
; are welcome. Pull requests are encouraged. The repo for this site
|
||||
; lives ;{a(href "https://github.com/urbit/urbit.github.io") "here"}.
|
||||
==
|
||||
;ul
|
||||
;li
|
||||
;p:(h2:"Tutorial")
|
||||
;p:(a/"/gen/main/pub/fab/site/tut/setup":"Setup")
|
||||
;strong: Nock
|
||||
;ol
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/nock1":"Intro to Nock"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/nock2":"Nock is Easy"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/nock3":"Using Nock"))
|
||||
==
|
||||
;strong: Hoon
|
||||
;ol
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon1":"Intro to Hoon"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon2":"Types"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon3":"Hoon Computes"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon4":"Gates"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon5":"Tiles"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon6":"Type Inference"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/hoon7":"Odds, Ends, Quirks"))
|
||||
==
|
||||
;strong: Arvo
|
||||
;ol
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/arvo1":"Basic Arvo"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/arvo2":"More Basic Arvo"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/arvo3":"Apps"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/arvo4":"Functional Publishing I"))
|
||||
;li:(p:(a/"/gen/main/pub/fab/site/tut/arvo5":"Functional Publishing II"))
|
||||
==
|
||||
==
|
||||
;li
|
||||
;p:(h2:"Reference")
|
||||
;p:(a/"/gen/main/pub/fab/site/ref/foreword":";{strong "Foreword"}: Nock")
|
||||
;p:(a/"/gen/main/pub/fab/site/ref/preface":";{strong "Preface"}: Hoon Abstract")
|
||||
;p:(a/"/gen/main/pub/fab/site/ref/vol0":";{strong "Volume 0"}: Version Stub")
|
||||
;p:(a/"/gen/main/pub/fab/site/ref/vol1":";{strong "Volume 1"}: Hoon Structures")
|
||||
;p:(a/"/gen/main/pub/fab/site/ref/vol2":";{strong "Volume 2"}: Hoon Compiler")
|
||||
;p:(a/"/gen/main/pub/fab/site/ref/vol3":";{strong "Volume 3"}: Arvo Core")
|
||||
;p:(a/"/gen/main/pub/fab/site/ref/vol4":";{strong "Volume 4"}: Arvo Vanes")
|
||||
==
|
||||
==
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
==
|
||||
|
@ -1,8 +1,6 @@
|
||||
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/ref/nock /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -12,12 +10,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= bod /^ manx /: /===/pub/src/doc/ref/vol0 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/ref/vol1 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/ref/vol2 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= bod /^ manx /: /===/pub/src/doc/ref/vol0 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/ref/vol3 /psal/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= bod /^ manx /: /===/pub/src/doc/ref/vol0 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/ref/vol4 /psal/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/arvo/1 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/arvo/2 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
18
main/pub/fab/site/tut/arvo3/hymn.hook
Normal file
18
main/pub/fab/site/tut/arvo3/hymn.hook
Normal file
@ -0,0 +1,18 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/arvo/app /psal/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
;html
|
||||
;head
|
||||
;title: Urbit: Personal Cloud Computing
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
==
|
||||
==
|
18
main/pub/fab/site/tut/arvo4/hymn.hook
Normal file
18
main/pub/fab/site/tut/arvo4/hymn.hook
Normal file
@ -0,0 +1,18 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/arvo/pub2 /psal/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
;html
|
||||
;head
|
||||
;title: Urbit: Personal Cloud Computing
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
==
|
||||
==
|
18
main/pub/fab/site/tut/arvo5/hymn.hook
Normal file
18
main/pub/fab/site/tut/arvo5/hymn.hook
Normal file
@ -0,0 +1,18 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/arvo/pub3 /psal/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
;html
|
||||
;head
|
||||
;title: Urbit: Personal Cloud Computing
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
==
|
||||
==
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/hoon/1 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/hoon/2 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/hoon/3 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/hoon/4 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/hoon/5 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/hoon/6 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/hoon/7 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/nock/1 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/nock/2 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
@ -1,7 +1,5 @@
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/nock/3 /psal/
|
||||
/= sid /^ manx /: /===/pub/src/site/res/sidebar /hymn/
|
||||
/= fot /^ manx /: /===/pub/src/site/res/footer /hymn/
|
||||
/= sty /^ @t /: /===/pub/src/site/res/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
@ -11,12 +9,10 @@
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;+ sid
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
;+ fot
|
||||
==
|
||||
==
|
||||
|
18
main/pub/fab/site/tut/setup/hymn.hook
Normal file
18
main/pub/fab/site/tut/setup/hymn.hook
Normal file
@ -0,0 +1,18 @@
|
||||
/= bod /^ manx /: /===/pub/src/doc/say/setup /psal/
|
||||
/= sty /^ @t /: /===/pub/fab/site/styles /css/
|
||||
::
|
||||
:::: ~tomsyt-balsen
|
||||
::
|
||||
;html
|
||||
;head
|
||||
;title: Urbit: Personal Cloud Computing
|
||||
;style:"{(trip sty)}"
|
||||
==
|
||||
;body
|
||||
;div(class "content container")
|
||||
;div.subpage
|
||||
;+ bod
|
||||
==
|
||||
==
|
||||
==
|
||||
==
|
@ -1,55 +0,0 @@
|
||||
#What is Urbit?
|
||||
|
||||
We got tired of system software from the 1970s. So we wrote our own. From scratch.
|
||||
|
||||
##Nock, a minimal virtual machine
|
||||
|
||||
[Nock](https://github.com/urbit/urbit/blob/master/urb/zod/spec/nock/5.txt) is a homoiconic combinator algebra, not much fancier than SKI combinators. The spec fits on a T-shirt and gzips to 340 bytes. Nock's data model is simple: a noun is an atom or a cell. An atom is any natural number. A cell is an ordered pair of any two nouns.
|
||||
|
||||
Nock cannot create cycles and needs no GC. Its only arithmetic operator is increment, so it is not inherently efficient; an efficient Nock interpreter works by recognizing standard Nock formulas and matching them to pre-written manual optimizations. We never extend Nock or call out to Unix from it.
|
||||
|
||||
##Hoon, a typed functional language
|
||||
|
||||
Hoon is a strict, typed, functional language that compiles itself to Nock. The Hoon compiler is 4000 lines of Hoon. Adding standard libraries, the self-compiling kernel is 8000 lines.
|
||||
|
||||
Hoon has no particular familial relationship to other languages you may know. It uses its own type inference algorithm and is as different from Haskell as from Lisp. Hoon syntax is also completely unfamiliar. Hoon has the same relationship to Nock that C has to assembly; as thin a layer as possible. It is possible to learn Hoon without Nock, but it's probably not a good idea.
|
||||
|
||||
As a functional systems language, Hoon is especially good at metaprogramming, self-virtualization, hotpatching; marshalling and validating untyped data; decoding and encoding binary message formats. Hoon is designed for event programming, so there is no concurrency model.
|
||||
|
||||
##Arvo, a functional operating system
|
||||
|
||||
Arvo is an event-driven server OS built on the same event library as node.js (libuv). Unlike node.js, Arvo is written in Hoon, isolated from Unix and a persistent single-level store. Arvo can update itself and its data and programs indefinitely from its own state. After the image is created, it lives indefinitely and is never modified externally.
|
||||
|
||||
Arvo is modular. Present modules provide a network messaging protocol, a REPL and task manager, a revision-controlled filesystem, a text console, and an HTTP server. The Arvo codebase is about 6500 lines, which is probably too big.
|
||||
|
||||
##Clay, a global immutable namespace
|
||||
|
||||
Clay is a feature of Arvo: a secure, referentially transparent and decentralized filesystem. The root of the namespace is a global PKI. Each identity serves its own filesystem tree. Files are nouns, not atoms, with arbitrary tree structure.
|
||||
|
||||
Identities, which are also routable addresses, are either key fingerprints or hierarchically assigned short numbers. All numbers are mapped to phonemic strings for memorability. Identities are transferrable and irrevocable; ownership is established by key pinning. The system has a superficial resemblance to Bitcoin, but works more like land than money. It does not use mining or a blockchain.
|
||||
|
||||
Since Clay is immutable, all paths contain a revision, which is either a change number, a date, or a label. A request is a special case of a subscription, so syndication is straightforward. Clay also has a synthesis mode which computes a functional namespace on the client side.
|
||||
|
||||
##What is Urbit good for?
|
||||
|
||||
Urbit is good for everything, of course! It is a new general-purpose computing layer. We look forward to a future where the current Internet exists only as an underground series of tubes which transports you to your Urbit.
|
||||
|
||||
More specifically, Urbit is a personal cloud computer. Right now, the cloud computers we use run OSes designed for minicomputers in the '70s. An ordinary user can no more drive a Linux box in the cloud than fly an A320. So she has to sit in coach class as a row in someone else's database. It's definitely air travel. It's not exactly flying.
|
||||
|
||||
The user of the future will fly her own computer. She will own and control her own identity and her own data. She will even host her own apps. She will not be part of someone else's Big Data. She will be her own Little Data. Unless she's a really severe geek, she will pay some service to store and execute her Urbit ship - but she can move it anywhere else, anytime, for the cost of the bandwidth.
|
||||
|
||||
A user can't manage a general-purpose computer unless she basically understands what it's doing. She may not be a programmer, but she needs at least a rough mental model of her computer's state.
|
||||
|
||||
A personal computer has to be a *simple* computer. This is why we built a new system software stack from scratch, with the goal of bringing it in under 10,000 lines of code. Urbit is about 50% over this complexity budget, but nobody's perfect.
|
||||
|
||||
##What can it do now?
|
||||
|
||||
Urbit at present is not good for anything but screwing around. For screwing around, it answers all your needs and is happy to consume any amount of unwanted time.
|
||||
|
||||
It does basically work as described above, though. Urbit at present propagates all its updates through its own filesystem, runs its own chat server over its own network protocol, etc. As of early 2014, it is an interesting prototype, not a useful device.
|
||||
|
||||
##How can I join the revolution?
|
||||
|
||||
Just wait. If you're cool enough, someone will send you an invitation.
|
||||
|
||||
Psych! No, actually, you can go here.
|
File diff suppressed because it is too large
Load Diff
@ -1,90 +1,90 @@
|
||||
volume 3, Arvo models and skeleton
|
||||
#volume 3, Arvo models and skeleton
|
||||
|
||||
++ arch
|
||||
++ bead
|
||||
++ care
|
||||
++ case
|
||||
++ desk
|
||||
++ cage
|
||||
++ chop
|
||||
++ curd
|
||||
++ disk
|
||||
++ duct
|
||||
++ gene
|
||||
++ glob
|
||||
++ herd
|
||||
++ hilt
|
||||
++ hypo
|
||||
++ khan
|
||||
++ lens
|
||||
++ v
|
||||
++ w
|
||||
++ x
|
||||
++ y
|
||||
++ z
|
||||
++ logo
|
||||
++ lode
|
||||
++ mark
|
||||
++ mill
|
||||
++ milt
|
||||
++ monk
|
||||
++ mold
|
||||
++ muse
|
||||
++ mosh
|
||||
++ move
|
||||
++ ovum
|
||||
++ pane
|
||||
++ pone
|
||||
++ ship
|
||||
++ sled
|
||||
++ slut
|
||||
++ vile
|
||||
++ wire
|
||||
++ slod
|
||||
++ slub
|
||||
++ arch
|
||||
++ bead
|
||||
++ care
|
||||
++ case
|
||||
++ desk
|
||||
++ cage
|
||||
++ chop
|
||||
++ curd
|
||||
++ disk
|
||||
++ duct
|
||||
++ gene
|
||||
++ glob
|
||||
++ herd
|
||||
++ hilt
|
||||
++ hypo
|
||||
++ khan
|
||||
++ lens
|
||||
++ v
|
||||
++ w
|
||||
++ x
|
||||
++ y
|
||||
++ z
|
||||
++ logo
|
||||
++ lode
|
||||
++ mark
|
||||
++ mill
|
||||
++ milt
|
||||
++ monk
|
||||
++ mold
|
||||
++ muse
|
||||
++ mosh
|
||||
++ move
|
||||
++ ovum
|
||||
++ pane
|
||||
++ pone
|
||||
++ ship
|
||||
++ sled
|
||||
++ slut
|
||||
++ vile
|
||||
++ wire
|
||||
++ slod
|
||||
++ slub
|
||||
|
||||
section 3bE, Arvo core
|
||||
##section 3bE, Arvo core
|
||||
|
||||
++ vent
|
||||
++ ruck
|
||||
++ wink
|
||||
++ doze
|
||||
++ sike
|
||||
++ souk
|
||||
++ sunk
|
||||
++ song
|
||||
++ spuc
|
||||
++ sump
|
||||
++ said
|
||||
++ scry
|
||||
++ soar
|
||||
++ swim
|
||||
++ vint
|
||||
++ viol
|
||||
++ is
|
||||
++ beck
|
||||
++ dink
|
||||
++ dint
|
||||
++ doos
|
||||
++ hurl
|
||||
++ race
|
||||
++ fire
|
||||
++ jack
|
||||
++ kick
|
||||
++ vent
|
||||
++ ruck
|
||||
++ wink
|
||||
++ doze
|
||||
++ sike
|
||||
++ souk
|
||||
++ sunk
|
||||
++ song
|
||||
++ spuc
|
||||
++ sump
|
||||
++ said
|
||||
++ scry
|
||||
++ soar
|
||||
++ swim
|
||||
++ vint
|
||||
++ viol
|
||||
++ is
|
||||
++ beck
|
||||
++ dink
|
||||
++ dint
|
||||
++ doos
|
||||
++ hurl
|
||||
++ race
|
||||
++ fire
|
||||
++ jack
|
||||
++ kick
|
||||
|
||||
Postface
|
||||
##Postface
|
||||
|
||||
++ come
|
||||
++ keep
|
||||
++ load
|
||||
++ peek
|
||||
++ poke
|
||||
++ wish
|
||||
++ come
|
||||
++ keep
|
||||
++ load
|
||||
++ peek
|
||||
++ poke
|
||||
++ vega
|
||||
++ veer
|
||||
++ wish
|
||||
++ come
|
||||
++ keep
|
||||
++ load
|
||||
++ peek
|
||||
++ poke
|
||||
++ wish
|
||||
++ come
|
||||
++ keep
|
||||
++ load
|
||||
++ peek
|
||||
++ poke
|
||||
++ vega
|
||||
++ veer
|
||||
++ wish
|
||||
|
987
main/pub/src/doc/ref/vol4.md
Normal file
987
main/pub/src/doc/ref/vol4.md
Normal file
@ -0,0 +1,987 @@
|
||||
Ames
|
||||
====
|
||||
|
||||
Ames is our networking protocol.
|
||||
|
||||
data models
|
||||
-----------
|
||||
|
||||
###`++fort`, formal state
|
||||
|
||||
```
|
||||
++ fort :: formal state
|
||||
$: %0 :: version
|
||||
gad=duct :: client interface
|
||||
hop=@da :: network boot date
|
||||
ton=town :: security
|
||||
zac=(map ship corn) :: flows by server
|
||||
== ::
|
||||
```
|
||||
|
||||
This is the state of our vane. Anything that must be remembered between
|
||||
calls to ames must be stored in this state.
|
||||
|
||||
`%0` is the version of the ames state model itself. If the data model `++fort`
|
||||
changes, then this number needs to be incremented, and an adapter must be
|
||||
written to upgrade the old state into the new state. Note that this is the
|
||||
version number of the model itself, not the contents. When the data changes,
|
||||
there is of course no need to change this.
|
||||
|
||||
`gad` is a `duct` over which we send `%send` cards to unix. This card is
|
||||
initialized when unix sends a `%barn` card as vere starts up. Vere treats this
|
||||
duct specially -- don't send anything weird over it.
|
||||
|
||||
`hop` is the network boot date. This is set when the `%kick` card is sent by
|
||||
vere on start up.
|
||||
|
||||
`ton` is a `++town`, where we store all of our security/encryption state. Note
|
||||
that this is shared across all ships on a pier.
|
||||
|
||||
`zac` is a map of ships to `++corn`. This stores all the per-ship state. The
|
||||
keys to this map are the ships on the current pier.
|
||||
|
||||
###`++town`, all security state
|
||||
|
||||
```
|
||||
++ town :: all security state
|
||||
$: lit=@ud :: imperial modulus
|
||||
any=@ :: entropy
|
||||
urb=(map ship sufi) :: all keys and routes
|
||||
fak=? ::
|
||||
== ::
|
||||
```
|
||||
|
||||
This is the security state of our pier.
|
||||
|
||||
`lit` is unused.
|
||||
|
||||
`any` is 256 bits of entropy. This entropy is used and updated in exactly two
|
||||
places: when we send a `%junk` card, and when we generate a new symmetric key
|
||||
in `++griz:lax:as:go`. When it is updated, it is updated by a SHA-256 hash of
|
||||
the current time and the old value of the entropy.
|
||||
|
||||
`urb` is a map of ships to `++sufi`. This is where we store all the per-ship
|
||||
state for the pier. The keys to this map are the ships on the current pier.
|
||||
|
||||
`fak` is true if we are on a fake network. This disables certain security
|
||||
checks so that anyone may run a fake `~zod`. This is used only for development.
|
||||
To use, run vere with the `-F` option (and the `-I ~zod` option for a fake
|
||||
`~zod`).
|
||||
|
||||
###`++sufi`, domestic host
|
||||
|
||||
```
|
||||
++ sufi :: domestic host
|
||||
$: hoy=(list ship) :: hierarchy
|
||||
val=wund :: private keys
|
||||
law=will :: server will
|
||||
seh=(map hand ,[p=ship q=@da]) :: key cache
|
||||
hoc=(map ship dore) :: neighborhood
|
||||
== ::
|
||||
```
|
||||
|
||||
This is the security state of a domestic server.
|
||||
|
||||
`hoy` is a list of the ships directly above us in the hierarchy of ships. For
|
||||
example, for `~hoclur-bicrel`, this would be `~tasruc` and `~tug`. See
|
||||
`++sein`.
|
||||
|
||||
`val` is a list of our private keys.
|
||||
|
||||
`law` is our certificate, which is a list of the XXX
|
||||
|
||||
`seh`
|
||||
|
||||
`hoc` is a map of ships to `++dore`. The stores all the security informatoin
|
||||
about foreign ships. The keys to this map are the neighbors (ships we have
|
||||
been in contact with) of this domestic server.
|
||||
|
||||
###`++wund`, private keys
|
||||
|
||||
```
|
||||
++ wund (list ,[p=life q=ring r=acru]) :: mace in action
|
||||
```
|
||||
|
||||
This is a list of our own private keys, indexed by life. The key itself is
|
||||
the `++ring`, and the `++acru` is the encryption engine. We generate the
|
||||
`++acru` from the private key by calling `++weur`. Thus, we can at any time
|
||||
regenerate our `++wund` from a `++mace`. The current crypto is at the head of
|
||||
the list and can be accessed with
|
||||
`++sen:as:go`.
|
||||
|
||||
###`++ring`, private key
|
||||
|
||||
```
|
||||
++ ring ,@ :: private key
|
||||
```
|
||||
|
||||
This is a private key. The first byte is reserved to identify the type of
|
||||
cryptography. Lower-case means public key, upper-case means public key, and
|
||||
the letter identifies which `++acru` to use.
|
||||
|
||||
###`++pass`, public key
|
||||
|
||||
```
|
||||
++ pass ,@ :: public key
|
||||
```
|
||||
|
||||
This is a public key. The first byte is reserved to identify the type of
|
||||
cryptography. Lower-case means public key, upper-case means public key, and
|
||||
the letter identifies which `++acru` to use.
|
||||
|
||||
###`++mace`, private secrets
|
||||
|
||||
```
|
||||
++ mace (list ,[p=life q=ring]) :: private secrets
|
||||
```
|
||||
|
||||
This is a list of the our private keys, indexed by life. From this we can
|
||||
generate a `++wund` for actual use.
|
||||
|
||||
###`++skin`, encoding stem
|
||||
|
||||
```
|
||||
++ skin ?(%none %open %fast %full) :: encoding stem
|
||||
```
|
||||
|
||||
This defines the type of encryption used for each message. `%none` refers
|
||||
to messages sent in the clear, `%open` refers to signed messages, `%full`
|
||||
refers to sealed messages, and `%fast` refers to symmetrically encrypted
|
||||
messages. See `++acru` for details.
|
||||
|
||||
###`++acru`, asymmetric cryptosuite
|
||||
|
||||
```
|
||||
++ acru :: asym cryptosuite
|
||||
$_ ^? |% :: opaque object
|
||||
++ as ^? :: asym ops
|
||||
|% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a
|
||||
++ sign |=([a=@ b=@] _@) :: certify as us
|
||||
++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us
|
||||
++ tear |= [a=pass b=@] :: accept from a
|
||||
*(unit ,[p=@ q=@]) ::
|
||||
-- ::
|
||||
++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft
|
||||
++ dy |+([a=@ b=@] _@) :: symmetric de, hard
|
||||
++ en |+([a=@ b=@] _@) :: symmetric en
|
||||
++ ex ^? :: export
|
||||
|% ++ fig _@uvH :: fingerprint
|
||||
++ pac _@uvG :: default passcode
|
||||
++ pub *pass :: public key
|
||||
++ sec *ring :: private key
|
||||
--
|
||||
++ nu ^? :: reconstructors
|
||||
|% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed]
|
||||
++ nol |=(a=@ ^?(..nu)) :: from naked ring
|
||||
++ com |=(a=@ ^?(..nu)) :: from naked pass
|
||||
--
|
||||
--
|
||||
```
|
||||
|
||||
This is an opaque interface for a general asymmetric cryptosuite. Any form
|
||||
of asymmetric cryptography can be dropped in to be used instead of the default.
|
||||
Right now, there are two cryptosuites, `++crua`, which is your standard RSA,
|
||||
and `++crub`, which is elliptic curve crypto but is mostly stubbed out at the
|
||||
moment.
|
||||
|
||||
####`++as:acru`, asymmetric operations
|
||||
|
||||
```
|
||||
++ as ^? :: asym ops
|
||||
|% ++ seal |=([a=pass b=@ c=@] _@) :: encrypt to a
|
||||
++ sign |=([a=@ b=@] _@) :: certify as us
|
||||
++ sure |=([a=@ b=@] *(unit ,@)) :: authenticate from us
|
||||
++ tear |= [a=pass b=@] :: accept from a
|
||||
*(unit ,[p=@ q=@]) ::
|
||||
-- ::
|
||||
```
|
||||
|
||||
This is the core that defines the standard asymmetric cryptography
|
||||
operations.
|
||||
|
||||
`++seal:as:acru` allows us to send a message encrypted with someone's public
|
||||
key so that only they may read it. If Alice seals a message with Bob's public
|
||||
key, then she can be sure that Bob is the only one who can read it. This is
|
||||
associated with the `++skin` `%full`.
|
||||
|
||||
`++sign:as:acru` allows us to sign a message with our private key so that
|
||||
others can verify that we sent the message. If Alice signs a message with her
|
||||
private key, then Bob can verify with her public key that it was indeed Alice
|
||||
who sent it. This is associated with the `++skin` `%open`.
|
||||
|
||||
`++sure:as:acru` is the dual to `++sign:as:acru`. It allows us to verify that
|
||||
a message we have received is indeed from the claimed sender. If Alice sends a
|
||||
message with her private key, then Bob can use this arm to verify that it was
|
||||
indeed Alice who sent it. This is associated with the `++skin` `%open`.
|
||||
|
||||
`++tear:as:acru` is the dual to `++seal:as:acru`. It allows us to read a
|
||||
message that we can be sure is only read by us. If Alice seals a message with
|
||||
Bob's public key, then Bob can use this arm to read it. This is associated
|
||||
with the `++skin` `%full`.
|
||||
|
||||
####`++de:acru`, `++dy:acru`, and `++en:acru`, symmetric encryption/decryption
|
||||
|
||||
```
|
||||
++ de |+([a=@ b=@] *(unit ,@)) :: symmetric de, soft
|
||||
++ dy |+([a=@ b=@] _@) :: symmetric de, hard
|
||||
++ en |+([a=@ b=@] _@) :: symmetric en
|
||||
```
|
||||
|
||||
Symmetric encryption is associated with the `++skin` `%fast`.
|
||||
|
||||
`++de:acru` decrypts a message with a symmetric key, returning `~` on failure
|
||||
and `[~ u=data]` on success.
|
||||
|
||||
`++dy:acru` decrypts a message with a symmetric key, crashing on failure. This
|
||||
should almost always be defined as, and should always be semantically
|
||||
equivalent to, `(need (de a b))`.
|
||||
|
||||
`++en:acru` encrypts a message with a symmetric key.
|
||||
|
||||
####`++ex:acru`, exporting data
|
||||
|
||||
```
|
||||
++ ex ^? :: export
|
||||
|% ++ fig _@uvH :: fingerprint
|
||||
++ pac _@uvG :: default passcode
|
||||
++ pub *pass :: public key
|
||||
++ sec *ring :: private key
|
||||
--
|
||||
```
|
||||
|
||||
`++fig:ex:acru` is our fingerprint, usually a hash of our public key. This is
|
||||
used, for example, in `++zeno`, where every carrier owner's fingerprint is
|
||||
stored so that we can ensure that carriers are indeed owned by their owners
|
||||
|
||||
`++pac:ex:acru` is our default passcode, which is unused at present.
|
||||
|
||||
`++pub:ex:acru` is the `++pass` form of our public key.
|
||||
|
||||
`++sec:ex:acru` is the `++ring` form of our private key.
|
||||
|
||||
####`++nu:acru`, reconstructors
|
||||
|
||||
```
|
||||
++ nu ^? :: reconstructors
|
||||
|% ++ pit |=([a=@ b=@] ^?(..nu)) :: from [width seed]
|
||||
++ nol |=(a=@ ^?(..nu)) :: from naked ring
|
||||
++ com |=(a=@ ^?(..nu)) :: from naked pass
|
||||
--
|
||||
```
|
||||
|
||||
These arms allow us to reconstruct a `++acru` from basic data.
|
||||
|
||||
`++pit:nu:acru` constructs a `++acru` from the width of our intended key and
|
||||
seed entropy. This is usually used in the initial construction of the
|
||||
`++acru`.
|
||||
|
||||
`++nol:nu:acru` constructs a `++acru` from a "naked ring", meaning a `++ring`
|
||||
without the initial byte identifying the type of crypto. There is often a
|
||||
helper arm that that wraps this; see `++weur` for `++crua` and `++wear` for
|
||||
`++crub`.
|
||||
|
||||
`++com:nu:acru` constructs a `++acru` from a "naked pass", meaning a `++ring`
|
||||
without the initial byte identifying the type of crypto. There is often a
|
||||
helper arm that that wraps this; see `++haul` for `++crua` and `++hail` for
|
||||
`++crub`.
|
||||
|
||||
###`++will`, certificate
|
||||
|
||||
```
|
||||
++ will (list deed) :: certificate
|
||||
```
|
||||
|
||||
This is a list of deeds associated with the current ship. There should be
|
||||
an item in this list for every ship from this point up in the hierarchy times
|
||||
the number of lives that each ship has had. For example, ~hoclur-bicrel may
|
||||
have a will with three items: one for itself, one for ~tasruc (who issued
|
||||
~hoclur-bicrel's deed) and one for ~tug (who issued ~tasruc's deed).
|
||||
|
||||
###`++deed`, identity
|
||||
|
||||
```
|
||||
++ deed ,[p=@ q=step r=?] :: sig, stage, fake?
|
||||
```
|
||||
|
||||
`p` is the signature of a particular deed, which is a signed copy of `q`.
|
||||
|
||||
`q` is the stage in the identity.
|
||||
|
||||
`r` is true if we're working on a fake network, where we don't check that the
|
||||
carrier fingerprints are correct. This allows us to create fake networks for
|
||||
development without interfering with the real network.
|
||||
|
||||
###`++step`, identity stage
|
||||
|
||||
```
|
||||
++ step ,[p=bray q=gens r=pass] :: identity stage
|
||||
```
|
||||
|
||||
This is a single stage in our identity. Thus, this is specific to a single
|
||||
life in a single ship. Everything in here may change between lives.
|
||||
|
||||
`p`
|
||||
|
||||
`q`
|
||||
|
||||
`r` is the public key for this stage in the identity.
|
||||
|
||||
###`++bray`
|
||||
|
||||
```
|
||||
++ bray ,[p=life q=(unit life) r=ship s=@da] :: our parent us now
|
||||
```
|
||||
|
||||
XXX
|
||||
|
||||
###`++gens`, general identity
|
||||
|
||||
```
|
||||
++ gens ,[p=lang q=gcos] :: general identity
|
||||
```
|
||||
|
||||
`p` is the IETF language code for the preferred language of this identity.
|
||||
This is unused at the moment, but in the future text should be localized based
|
||||
on this.
|
||||
|
||||
`q` is the description of the ship.
|
||||
|
||||
###`++gcos`, identity description
|
||||
|
||||
```
|
||||
++ gcos :: id description
|
||||
$% [%czar ~] :: 8-bit ship
|
||||
[%duke p=what] :: 32-bit ship
|
||||
[%earl p=@t] :: 64-bit ship
|
||||
[%king p=@t] :: 16-bit ship
|
||||
[%pawn p=(unit ,@t)] :: 128-bit ship
|
||||
== ::
|
||||
```
|
||||
|
||||
This is the description of the identity of a ship. Most types of identity have
|
||||
a `@t` field, which is their human-readable name. The identity of a `%duke` is
|
||||
more involved.
|
||||
|
||||
A `%czar`, a carrier, is a ship with an 8-bit address. Thus, there are only
|
||||
256 carriers. These are at the top of the namespace hierarchy, and the
|
||||
fingerprint of each carrier is stored in `++zeno`. These are the "senators" of
|
||||
Urbit.
|
||||
|
||||
A `%king`, a cruiser, is a ship with a 16-bit address. Thus, there are 65,536
|
||||
cruisers. Each carrier may issue 256 cruisers. These are the infrastructure
|
||||
of Urbit.
|
||||
|
||||
A `%duke`, a destroyer, is a ship with a 32-bit address. Thus, there are
|
||||
4,294,967,296 destroyers. Each cruiser may issue 65,536 cruisers. These are
|
||||
the individuals of Urbit.
|
||||
|
||||
A `%earl`, a yacht, is a ship with a 64-bit address. Thus, there are
|
||||
18,446,744,073,709,551,616 yachts. Each destroyer may issue 4,294,967,296
|
||||
yachts. These are the devices of Urbit.
|
||||
|
||||
A `%pawn`, a submarine, is a ship with a 128-bit address. Thus, there are a
|
||||
lot of submarines. The chance of random name collision is negligible, so
|
||||
submarines are not issued by any ship. They must simply assert their presence,
|
||||
and they are all considered children of ~zod. This is the underworld of Urbit,
|
||||
where anonymity reigns supreme.
|
||||
|
||||
###`++what`, logical destroyer identity
|
||||
|
||||
```
|
||||
++ what :: logical identity
|
||||
$% [%anon ~] :: anonymous
|
||||
[%lady p=whom] :: female person ()
|
||||
[%lord p=whom] :: male person []
|
||||
[%punk p=sect q=@t] :: opaque handle ""
|
||||
== ::
|
||||
```
|
||||
|
||||
This is the logical identity of a destroyer.
|
||||
|
||||
A `%anon` is a completely anonymous destroyer. The difference between this and
|
||||
a submarine is that a submarine is ephemeral while a `%anon` destroyer is not.
|
||||
Thus, we may not know who ~hoclur-bicrel is, but we do know that it's always
|
||||
the same person.
|
||||
|
||||
A `%lady` is a female person. The name used here should be a real name.
|
||||
|
||||
A `%lord` is a male person. The name used here should be a real name.
|
||||
|
||||
A `%punk` is a person who is identified only by a handle.
|
||||
|
||||
###`++whom`, real person
|
||||
|
||||
```
|
||||
++ whom ,[p=@ud q=govt r=sect s=name] :: year/govt/id
|
||||
```
|
||||
|
||||
Ths is the information associated with a real person. It is mostly information
|
||||
that could be observed with the briefest of interactions.
|
||||
|
||||
`p` is the birth year.
|
||||
|
||||
`q` is the location of a user, usually of the form "country/zip".
|
||||
|
||||
`r` is the sect of the user.
|
||||
|
||||
`s` is the real name of the person.
|
||||
|
||||
|
||||
###`++govt`
|
||||
|
||||
```
|
||||
++ govt path :: country/postcode
|
||||
```
|
||||
|
||||
This is the location of the user, usually of the form "country/zip".
|
||||
|
||||
###`++sect`
|
||||
|
||||
```
|
||||
++ sect ?(%black %blue %red %orange %white) :: banner
|
||||
```
|
||||
|
||||
XXX
|
||||
|
||||
###`++name`
|
||||
|
||||
```
|
||||
++ name ,[p=@t q=(unit ,@t) r=(unit ,@t) s=@t] :: first mid/nick last
|
||||
```
|
||||
|
||||
This is the given name, possible middle name/initial, possible nickname, and
|
||||
surname of a user.
|
||||
|
||||
packet format
|
||||
-------------
|
||||
|
||||
`++go`, PKI engine
|
||||
------------------
|
||||
|
||||
###`++as`, per server
|
||||
|
||||
####`++born`, register user
|
||||
|
||||
#####`++lax`, per client
|
||||
|
||||
`++pu`, packet pump
|
||||
-------------------
|
||||
|
||||
`++am`, protocol engine
|
||||
-----------------------
|
||||
|
||||
###`++um`, per server
|
||||
|
||||
####`++ho`, per friend
|
||||
|
||||
#####`++la`, per packet
|
||||
|
||||
protocol vane
|
||||
-------------
|
||||
|
||||
#Batz
|
||||
|
||||
Coming soon
|
||||
|
||||
#Dill
|
||||
|
||||
Coming soon
|
||||
|
||||
#Clay
|
||||
|
||||
Clay
|
||||
====
|
||||
|
||||
Clay is our filesystem.
|
||||
|
||||
data models
|
||||
-----------
|
||||
|
||||
###`++raft`, formal state
|
||||
|
||||
```
|
||||
++ raft :: filesystem
|
||||
$: fat=(map ship room) :: domestic
|
||||
hoy=(map ship rung) :: foreign
|
||||
ran=rang :: hashes
|
||||
== ::
|
||||
```
|
||||
|
||||
This is the state of our vane. Anything that must be remembered between calls
|
||||
to clay must be stored in this state.
|
||||
|
||||
`fat` is the set of domestic servers. This stores all the information that is
|
||||
specfic to a particular ship on this pier. The keys to this map are the ships
|
||||
on the current pier.
|
||||
|
||||
`hoy` is the set of foreign servers that we know anything about. This stores
|
||||
all the information that is specific to a particular foreign ship. The keys to
|
||||
this map are all the ships whose filesystems we have attempted to access
|
||||
through clay.
|
||||
|
||||
`ran` is the store of all commits and deltas, keyed by hash. The is where all
|
||||
the "real" data we know is stored; the rest is "just bookkeeping".
|
||||
|
||||
###`++room`, filesystem per domestic ship
|
||||
|
||||
```
|
||||
++ room :: fs per ship
|
||||
$: hun=duct :: terminal duct
|
||||
hez=(unit duct) :: sync duch
|
||||
dos=(map desk dojo) :: native desk
|
||||
== ::
|
||||
```
|
||||
|
||||
This is the representation of the filesystem of a ship on our pier.
|
||||
|
||||
`hun` is the duct that we use to send messages to dill to display notifications
|
||||
of filesystem changes. Only `%note` gifts should be produced along this duct.
|
||||
This is set by the `%init` kiss.
|
||||
|
||||
`hez`, if present, is the duct we use to send sync messages to unix so that
|
||||
they end up in the pier unix directory. Only `%ergo` gifts should be producd
|
||||
along this duct. This is set by `%into` and `%invo` gifts.
|
||||
|
||||
`dos` is a well-known operating system released in 1981. It is also the set of
|
||||
desks on this ship, mapped to their data.
|
||||
|
||||
###`++desk`, filesystem branch
|
||||
|
||||
```
|
||||
++ desk ,@tas :: ship desk case spur
|
||||
```
|
||||
|
||||
This is the name of a branch of the filesystem. The default desks are "arvo",
|
||||
"main", and "try". More may be created by simply referencing them. Desks have
|
||||
independent histories and states, and they may be merged into each other.
|
||||
|
||||
###`++dojo`, domestic desk state
|
||||
|
||||
```
|
||||
++ dojo ,[p=cult q=dome] :: domestic desk state
|
||||
```
|
||||
|
||||
This is the all the data that is specific to a particular desk on a domestic
|
||||
ship. `p` is the set of subscribers to this desk and `q` is the data in the
|
||||
desk.
|
||||
|
||||
###`++cult`, subscriptions
|
||||
|
||||
```
|
||||
++ cult (map duct rave) :: subscriptions
|
||||
```
|
||||
|
||||
This is the set of subscriptions to a particular desk. The keys are the ducts
|
||||
from where the subscriptions requests came. The results will be produced along
|
||||
these ducts. The values are a description of the requested information.
|
||||
|
||||
###`++rave`, general subscription request
|
||||
|
||||
```
|
||||
++ rave :: general request
|
||||
$% [& p=mood] :: single request
|
||||
[| p=moat] :: change range
|
||||
== ::
|
||||
```
|
||||
|
||||
This represents a subscription request for a desk. The request can be for
|
||||
either a single item in the desk or else for a range of changes on the desk.
|
||||
|
||||
###`++mood`, single subscription request
|
||||
|
||||
```
|
||||
++ mood ,[p=care q=case r=path] :: request in desk
|
||||
```
|
||||
|
||||
This represents a request for the state of the desk at a particular commit,
|
||||
specfied by `q`. `p` specifies what kind of information is desired, and `r`
|
||||
specifies the path we are requesting.
|
||||
|
||||
###`++moat`, range subscription request
|
||||
|
||||
```
|
||||
++ moat ,[p=case q=case] :: change range
|
||||
```
|
||||
|
||||
This represents a request for all changes between `p` and `q`. Note that there
|
||||
is currently no way to request to be notified only on changes to particular
|
||||
paths in the filesystem. You must subscribe to the entire desk.
|
||||
|
||||
###`++care`, clay submode
|
||||
|
||||
```
|
||||
++ care ?(%u %v %w %x %y %z) :: clay submode
|
||||
```
|
||||
|
||||
This specifies what type of information is requested in a subscription or a
|
||||
scry.
|
||||
|
||||
`%u` requests the `++rang` at the current moment. Because this information is
|
||||
not stored for any moment other than the present, we crash if the `++case` is
|
||||
not a `%da` for now.
|
||||
|
||||
`%v` requests the `++dome` at the specified commit.
|
||||
|
||||
`%w` requests the current revsion number of the desk.
|
||||
|
||||
`%x` requests the file at a specified path at the specified commit. If there
|
||||
is no node at that path or if the node has no contents (that is, if `q:ankh` is
|
||||
null), then this produces null.
|
||||
|
||||
`%y` requests a `++arch` of the specfied commit at the specified path.
|
||||
|
||||
`%z` requests the `++ankh` of the specified commit at the specfied path.
|
||||
|
||||
###`++arch`, shallow filesystem node
|
||||
|
||||
```
|
||||
++ arch ,[p=@uvI q=(unit ,@uvI) r=(map ,@ta ,~)] :: fundamental node
|
||||
```
|
||||
|
||||
This is analogous to `++ankh` except that the we have neither our contents nor
|
||||
the ankhs of our children. The other fields are exactly the same, so `p` is a
|
||||
hash of the associated ankh, `u.q`, if it exists, is a hash of the contents of
|
||||
this node, and the keys of `r` are the names of our children. `r` is a map to
|
||||
null rather than a set so that the ordering of the map will be equivalent to
|
||||
that of `r:ankh`, allowing efficient conversion.
|
||||
|
||||
###`++case`, specifying a commit
|
||||
|
||||
```
|
||||
++ case :: ship desk case spur
|
||||
$% [%da p=@da] :: date
|
||||
[%tas p=@tas] :: label
|
||||
[%ud p=@ud] :: number
|
||||
== ::
|
||||
```
|
||||
|
||||
A commit can be referred to in three ways: `%da` refers to the commit that was
|
||||
at the head on date `p`, `%tas` refers to the commit labeled `p`, and `%ud`
|
||||
refers to the commit numbered `p`. Note that since these all can be reduced
|
||||
down to a `%ud`, only numbered commits may be referenced with a `++case`.
|
||||
|
||||
###`++dome`, desk data
|
||||
|
||||
```
|
||||
++ dome :: project state
|
||||
$: ang=agon :: pedigree
|
||||
ank=ankh :: state
|
||||
let=@ud :: top id
|
||||
hit=(map ,@ud tako) :: changes by id
|
||||
lab=(map ,@tas ,@ud) :: labels
|
||||
== ::
|
||||
```
|
||||
|
||||
This is the data that is actually stored in a desk.
|
||||
|
||||
`ang` is unused and should be removed.
|
||||
|
||||
`ank` is the current state of the desk. Thus, it is the state of the
|
||||
filesystem at revison `let`. The head of a desk is always a numbered commit.
|
||||
|
||||
`let` is the number of the most recently numbered commit. This is also the
|
||||
total number of numbered commits.
|
||||
|
||||
`hit` is a map of numerical ids to hashes of commits. These hashes are mapped
|
||||
into their associated commits in `hut:rang`. In general, the keys of this map
|
||||
are exactly the numbers from 1 to `let`, with no gaps. Of course, when there
|
||||
are no numbered commits, `let` is 0, so `hit` is null. Additionally, each of
|
||||
the commits is an ancestor of every commit numbered greater than this one.
|
||||
Thus, each is a descendant of every commit numbered less than this one. Since
|
||||
it is true that the date in each commit (`t:yaki`) is no earlier than that of
|
||||
each of its parents, the numbered commits are totally ordered in the same way
|
||||
by both pedigree and date. Of course, not every commit is numbered. If that
|
||||
sounds too complicated to you, don't worry about it. It basically behaves
|
||||
exactly as you would expect.
|
||||
|
||||
`lab` is a map of textual labels to numbered commits. Note that labels can
|
||||
only be applied to numbered commits. Labels must be unique across a desk.
|
||||
|
||||
###`++ankh`, filesystem node
|
||||
|
||||
```
|
||||
++ ankh :: fs node (new)
|
||||
$: p=cash :: recursive hash
|
||||
q=(unit ,[p=cash q=*]) :: file
|
||||
r=(map ,@ta ankh) :: folders
|
||||
== ::
|
||||
```
|
||||
|
||||
This is a single node in the filesystem. This may be file or a directory or
|
||||
both. In earth filesystems, a node is a file xor a directory. On mars, we're
|
||||
inclusive, so a node is a file ior a directory.
|
||||
|
||||
`p` is a recursive hash that depends on the contents of the this file or
|
||||
directory and on any children.
|
||||
|
||||
`q` is the contents of this file, if any. `p.q` is a hash of the contents
|
||||
while `q.q` is the data itself.
|
||||
|
||||
`r` is the set of children of this node. In the case of a pure file, this is
|
||||
empty. The keys are the names of the children and the values are, recursively,
|
||||
the nodes themselves.
|
||||
|
||||
###`++cash`, ankh hash
|
||||
|
||||
```
|
||||
++ cash ,@uvH :: ankh hash
|
||||
```
|
||||
|
||||
This is a 128-bit hash of an ankh. These are mostly stored within ankhs
|
||||
themselves, and they are used to check for changes in possibly-deep
|
||||
hierarchies.
|
||||
|
||||
###`++rung`, filesystem per neighbor ship
|
||||
|
||||
```
|
||||
++ rung $: rus=(map desk rede) :: neighbor desks
|
||||
== ::
|
||||
```
|
||||
|
||||
This is the filesystem of a neighbor ship. The keys to this map are all the
|
||||
desks we know about on their ship.
|
||||
|
||||
###`++rede`, desk state
|
||||
|
||||
```
|
||||
++ rede :: universal project
|
||||
$: lim=@da :: complete to
|
||||
qyx=cult :: subscribers
|
||||
ref=(unit rind) :: outgoing requests
|
||||
dom=dome :: revision state
|
||||
== ::
|
||||
```
|
||||
|
||||
This is our knowledge of the state of a desk, either foreign or domestic.
|
||||
|
||||
`lim` is the date of the last full update. We only respond to requests for
|
||||
stuff before this time.
|
||||
|
||||
`qyx` is the list of subscribers to this desk. For domestic desks, this is
|
||||
simply `p:dojo`, all subscribers to the desk, while in foreign desks this is
|
||||
all the subscribers from our ship to the foreign desk.
|
||||
|
||||
`ref` is the request manager for the desk.
|
||||
|
||||
`dom` is the actual data in the desk.
|
||||
|
||||
###`++rind`, request manager
|
||||
|
||||
```
|
||||
++ rind :: request manager
|
||||
$: nix=@ud :: request index
|
||||
bom=(map ,@ud ,[p=duct q=rave]) :: outstanding
|
||||
fod=(map duct ,@ud) :: current requests
|
||||
haw=(map mood (unit)) :: simple cache
|
||||
== ::
|
||||
```
|
||||
|
||||
This is the request manager for a desk.
|
||||
|
||||
`nix` is one more than the index of the most recent request. Thus, it is the
|
||||
next available request number.
|
||||
|
||||
`bom` is the set of outstanding requests. The keys of this map are some subset
|
||||
of the numbers between 0 and one less than `nix`. The members of the map are
|
||||
exactly those requests that have not yet been fully satisfied.
|
||||
|
||||
`fod` is the same set as `bom`, but from a different perspective. In
|
||||
particular, the values of `fod` are the same as the values of `bom`, and the
|
||||
`p` out of the values of `bom` are the same as the keys of `fod`. Thus, we can
|
||||
map ducts to their associated request number and `++rave`, and we can map
|
||||
numbers to their associated duct and `++rave`.
|
||||
|
||||
`haw` is a map from simple requests to their values. This acts as a cache for
|
||||
requests that have already been made. Thus, the second request for a
|
||||
particular `++mood` is nearly instantaneous.
|
||||
|
||||
###`++rang`, data store
|
||||
|
||||
```
|
||||
++ rang $: hut=(map tako yaki) ::
|
||||
lat=(map lobe blob) ::
|
||||
== ::
|
||||
```
|
||||
|
||||
This is a set of data keyed by hash. Thus, this is where the "real" data is
|
||||
stored, but it is only meaningful if we know the hash of what we're looking
|
||||
for.
|
||||
|
||||
`hut` is a map from hashes to commits. We often get the hashes from
|
||||
`hit:dome`, which keys them by logical id. Not every commit has an id.
|
||||
|
||||
`lat` is a map from hashes to the actual data. We often get the hashes from a
|
||||
`++yaki`, a commit, which references this map to get the data. There is no
|
||||
`++blob` in any `++yaki`. They are only accessible through this map.
|
||||
|
||||
###`++tako`, commit reference
|
||||
|
||||
```
|
||||
++ tako ,@ :: yaki ref
|
||||
```
|
||||
|
||||
This is a hash of a `++yaki`, a commit. These are most notably used as the
|
||||
keys in `hut:rang`, where they are associated with the actual `++yaki`, and as
|
||||
the values in `hit:dome`, where sequential ids are associated with these.
|
||||
|
||||
###`++yaki`, commit
|
||||
|
||||
```
|
||||
++ yaki ,[p=(list tako) q=(map path lobe) r=tako t=@da] :: commit
|
||||
```
|
||||
|
||||
This is a single commit.
|
||||
|
||||
`p` is a list of the hashes of the parents of this commit. In most cases, this
|
||||
will be a single commit, but in a merge there may be more parents. In theory,
|
||||
there may be an arbitrary number of parents, but in practice merges have
|
||||
exactly two parents. This may change in the future. For commit 1, there is no
|
||||
parent.
|
||||
|
||||
`q` is a map of the paths on a desk to the data at that location. If you
|
||||
understand what a `++lobe` and a `++blob` is, then the type signature here
|
||||
tells the whole story.
|
||||
|
||||
`r` is the hash associated with this commit.
|
||||
|
||||
`t` is the date at which this commit was made.
|
||||
|
||||
###`++lobe`, data reference
|
||||
|
||||
```
|
||||
++ lobe ,@ :: blob ref
|
||||
```
|
||||
|
||||
This is a hash of a `++blob`. These are most notably used in `lat:rang`, where
|
||||
they are associated with the actual `++blob`, and as the values in `q:yaki`,
|
||||
where paths are associated with their data in a commit.
|
||||
|
||||
###`++blob`, data
|
||||
|
||||
```
|
||||
++ blob $% [%delta p=lobe q=lobe r=udon] :: delta on q
|
||||
[%direct p=lobe q=* r=umph] ::
|
||||
[%indirect p=lobe q=* r=udon s=lobe] ::
|
||||
== ::
|
||||
```
|
||||
|
||||
This is a node of data. In every case, `p` is the hash of the blob.
|
||||
|
||||
`%delta` is the case where we define the data by a delta on other data. In
|
||||
practice, the other data is always the previous commit, but nothing depends on
|
||||
this. `q` is the hash of the parent blob, and `r` is the delta.
|
||||
|
||||
`%direct` is the case where we simply have the data directly. `q` is the data
|
||||
itself, and `r` is any preprocessing instructions. These almost always come
|
||||
from the creation of a file.
|
||||
|
||||
`%indirect` is both of the preceding cases at once. `q` is the direct data,
|
||||
`r` is the delta, and `s` is the parent blob. It should always be the case
|
||||
that applying `r` to `s` gives the same data as `q` directly (with the
|
||||
prepreprocessor instructions in `p.r`). This exists purely for performance
|
||||
reasons. This is unused, at the moment, but in general these should be created
|
||||
when there are a long line of changes so that we do not have to traverse the
|
||||
delta chain back to the creation of the file.
|
||||
|
||||
###`++udon`, abstract delta
|
||||
|
||||
```
|
||||
++ udon :: abstract delta
|
||||
$: p=umph :: preprocessor
|
||||
$= q :: patch
|
||||
$% [%a p=* q=*] :: trivial replace
|
||||
[%b p=udal] :: atomic indel
|
||||
[%c p=(urge)] :: list indel
|
||||
[%d p=upas q=upas] :: tree edit
|
||||
== ::
|
||||
== ::
|
||||
```
|
||||
|
||||
This is an abstract change to a file. This is a superset of what would
|
||||
normally be called diffs. Diffs usually refer to changes in lines of text
|
||||
while we have the ability to do more interesting deltas on arbitrary data
|
||||
structures.
|
||||
|
||||
`p` is any preprocessor instructions.
|
||||
|
||||
`%a` refers to the trival delta of a complete replace of old data with new
|
||||
data.
|
||||
|
||||
`%b` refers to changes in an opaque atom on the block level. This has very
|
||||
limited usefulness, and is not used at the moment.
|
||||
|
||||
`%c` refers to changes in a list of data. This is often lines of text, which
|
||||
is your classic diff. We, however, will work on any list of data.
|
||||
|
||||
`%d` refers to changes in a tree of data. This is general enough to describe
|
||||
changes to any hoon noun, but often more special-purpose delta should be
|
||||
created for different content types. This is not used at the moment, and may
|
||||
in fact be unimplemented.
|
||||
|
||||
###`++urge`, list change
|
||||
|
||||
```
|
||||
++ urge |*(a=_,* (list (unce a))) :: list change
|
||||
```
|
||||
|
||||
This is a parametrized type for list changes. For example, `(urge ,@t)` is a
|
||||
list change for lines of text.
|
||||
|
||||
###`++unce`, change part of a list.
|
||||
|
||||
```
|
||||
++ unce |* a=_,* :: change part
|
||||
$% [%& p=@ud] :: skip[copy]
|
||||
[%| p=(list a) q=(list a)] :: p -> q[chunk]
|
||||
== ::
|
||||
```
|
||||
|
||||
This is a single change in a list of elements of type `a`. For example, `(unce ,@t)` is
|
||||
a single change in a lines of text.
|
||||
|
||||
`%&` means the next `p` lines are unchanged.
|
||||
|
||||
`%|` means the lines `p` have changed to `q`.
|
||||
|
||||
###`++umph`, preprocessing information
|
||||
|
||||
```
|
||||
++ umph :: change filter
|
||||
$| $? %a :: no filter
|
||||
%b :: jamfile
|
||||
%c :: LF text
|
||||
== ::
|
||||
$% [%d p=@ud] :: blocklist
|
||||
== ::
|
||||
```
|
||||
|
||||
This space intentionally left undocumented. This stuff will change once we get
|
||||
a well-typed clay.
|
||||
|
||||
|
||||
###`++upas`, tree change
|
||||
|
||||
```
|
||||
++ upas :: tree change (%d)
|
||||
$& [p=upas q=upas] :: cell
|
||||
$% [%0 p=axis] :: copy old
|
||||
[%1 p=*] :: insert new
|
||||
[%2 p=axis q=udon] :: mutate!
|
||||
== ::
|
||||
```
|
||||
|
||||
This space intentionally left undocumented. This stuff is not known to work,
|
||||
and will likely change when we get a well-typed clay. Also, this is not a
|
||||
complicated type; it is not difficult to work out the meaning.
|
||||
|
||||
#Eyre
|
||||
|
||||
Coming soon
|
||||
|
||||
#Ford
|
||||
|
||||
Coming soon
|
||||
|
||||
#Gall
|
||||
|
||||
Coming soon
|
@ -1,391 +0,0 @@
|
||||
---
|
||||
layout: post
|
||||
category: blog
|
||||
author: cgy
|
||||
title: Welcome to Urbit
|
||||
date: 2013-9-24 15:00
|
||||
---
|
||||
But wait - what the hell is Urbit?
|
||||
|
||||
One of Urbit's problems is that we don't exactly have a word for
|
||||
what Urbit is. If there is such a word, it somehow means both
|
||||
"operating system" and "network protocol," while somehow also
|
||||
implying "functional" and "deterministic."
|
||||
|
||||
Not only is there no such word, it's not even clear there
|
||||
_should_ be one. And if there was, could we even hear it?
|
||||
As Wittgenstein said: if a lion could talk, we would not
|
||||
understand him. But heck, let's try anyway.
|
||||
|
||||
As a network protocol, we could call Urbit a "seven-layer
|
||||
protocol" - that is, a protocol that specifies the complete
|
||||
semantics of the general-purpose computer that processes it. As
|
||||
any decent IETF ninja will tell you, this is a very bad idea for
|
||||
all sorts of extremely obvious reasons.
|
||||
|
||||
And from the OS perspective, Urbit is yet another slice of
|
||||
userspace crap with the temerity to call itself an "operating
|
||||
system." Urbit is not actually an OS in the bare-metal sense.
|
||||
It's a VM that runs on Linux or OS X. Someday it might be so
|
||||
daring as to descend to Xen. Urbit has no interest at all in
|
||||
drivers, peripherals, etc. It is just a UDP transceiver in the
|
||||
cloud. Worst of all - Urbit is not even preemptive. A poser!
|
||||
(Actually all the real work, as in node, is done by libuv.)
|
||||
|
||||
Moreover, this VM is formally isolated from your actual OS. And
|
||||
everything that uses it. Nothing in Urbit can request system
|
||||
services or call existing libraries. So Urbit is not only badly
|
||||
designed and fraudulently hyped. It's also profoundly useless.
|
||||
|
||||
Well... your browser has been reasonably successful with this
|
||||
restriction. But your browser was never designed to be any kind
|
||||
of OS. To the extent that it's sort of become an OS, it is
|
||||
specialized for the very undemanding job of being a client. A
|
||||
general-purpose client, which is neat. But not a general-purpose
|
||||
server - which is a much harder problem.
|
||||
|
||||
A general-purpose server is a slab of code that feels totally
|
||||
confident when faced with the problem of storing _all your
|
||||
personal and/or corporate data_, across _arbitrary functional
|
||||
upgrades_, for _all time forever_, while efficiently executing
|
||||
and managing _any useful program or programs, transient or
|
||||
persistent_. Yeah, that's a server OS.
|
||||
|
||||
So, conventionally, this industrial strength slab of code is
|
||||
written with conventional OS techniques involving (a) bare metal
|
||||
and (b) like, semaphores and shit. The kernel alone is like 12
|
||||
million lines of code. Not that a browser is any much smaller.
|
||||
|
||||
And so, 20th-century network computing is the world's most
|
||||
beautiful wire, between two dumpsters of shit spaghetti. Two
|
||||
_completely different_ dumpsters. It turns out that with a big
|
||||
enough dumpster of shit spaghetti, you can feed the world. And
|
||||
why not two? Incompatibility creates jobs, you know.
|
||||
|
||||
Oh, and you can have a client without an identity. But you can't
|
||||
have a _server_ without an identity. So Urbit has to solve _that_
|
||||
problem. Unless it's just going to be a Web server. (Urbit is
|
||||
actually a perfectly decent Web server.) Unless it has an actual
|
||||
identity model, your general-purpose server - presumably a
|
||||
_network_ server - has no network effect. No identity, no
|
||||
network. No network, who the hell cares?
|
||||
|
||||
And unlike your ordinary, common or garden Web application
|
||||
server, Urbit does need that network effect. You see, it's not
|
||||
even our own work. It's something we found. On an unmarked USB
|
||||
stick by the side of the road three kilometers from Area 51.
|
||||
|
||||
We think it's probably still human engineering. First of all,
|
||||
there are no aliens. Second, Urbit uses Unicode. Do the aliens
|
||||
have Unicode? Or SHA-256? _Where did Unicode come from,
|
||||
anyway?_ And at the I/O level, we see UDP, HTTP, etc. The
|
||||
command line does Emacs keys. At the very least, someone on
|
||||
Earth (or at least _from_ Earth) has done some porting.
|
||||
|
||||
But other than these cosmetic details, there's not much sign of a
|
||||
connection to ordinary Earth computing. For instance, Urbit
|
||||
isn't written in any of our Earth languages. It is written in
|
||||
something called Hoon, which is a strict, higher-order, typed
|
||||
functional language - but has nothing in else in common with
|
||||
other Earth languages, functional or not. Hoon does not even
|
||||
use standard PL theory. And its syntax is just as alien, although
|
||||
at least it confines itself to the ASCII plane. (And you
|
||||
probably thought the "A" in "ASCII" stood for "American.")
|
||||
|
||||
Worse yet, Hoon is not written in anything normal. It's written
|
||||
in Hoon. To be precise - the Hoon compiler compiles itself to a
|
||||
much simpler automaton, Nock. Besides machine language itself,
|
||||
and its various bytecode homages, there are three simple formal
|
||||
models of computing - Turing machines, lambda calculus, and Chuck
|
||||
Moore. There is also a fourth which no one has ever found useful
|
||||
for anything: combinators. Nock is a combinator automaton.
|
||||
|
||||
While nowhere near the simplest such automaton known, and
|
||||
certainly not of any _theoretical_ interest, Nock is so stupid
|
||||
that if you gzip the spec, it's only 374 bytes. Nock's only
|
||||
arithmetic operation is increment. So decrement is an `O(n)`,
|
||||
operation; add is `O(m*n)`...
|
||||
|
||||
Clearly not a practical system. Even if this... _thing_... that
|
||||
sits on top of it was in any way, shape or form remotely sane.
|
||||
|
||||
So why not try it? Heck, why not at least check it out? Strange
|
||||
and foolish dreamers may hie themselves to teh github:
|
||||
|
||||
[https://github.com/urbit](https://github.com/urbit)
|
||||
|
||||
Various people have built and run Urbit on Ubuntu, Homebrew and
|
||||
MacPorts. It's possible that all these people were stone cold
|
||||
ninjas. Urbit is a pretty cool toy, I think, if you're a ninja.
|
||||
Unfortunately it is not really ready for ordinary rice farmers.
|
||||
If you can't resolve build dependencies by hand, we're sorry.
|
||||
Urbit is probably not yet ready for you.
|
||||
|
||||
Where should you run Urbit? Ideally, in the cloud. Urbit can
|
||||
punch a decent NAT hole. It doesn't like to, though - what does?
|
||||
Bear in mind that your Urbit instance is a single-level store -
|
||||
your state is saved as a log and a checkpoint (as in Redis -
|
||||
except that Redis is both fast and reliable). This will work
|
||||
much better on server hardware. That said, there are plenty of
|
||||
good reasons to keep your servers in the closet with the plants.
|
||||
|
||||
Next, you need a ticket. Or not. You at least need to decide
|
||||
whether you want a ticket or not. Actually, the answer is
|
||||
simple. You do want one. But you don't need one - not yet.
|
||||
|
||||
Because Urbit, the OS, never depends on Earth semantics, it needs
|
||||
its own network protocol - Ames. Ames is a P2P protocol with its
|
||||
own public-key infrastructure. (Ames is encrypted, but the
|
||||
current cryptosuite, suite A, is worthless snakeoil. Don't trust
|
||||
it with your Trader Joe receipts.) Ames runs over UDP, and pays
|
||||
as little attention to IP routing as possible. Needless to say,
|
||||
Urbit does not use the DNS at all.
|
||||
|
||||
To sling packets on Ames, you need an identity. Needless to say,
|
||||
there are a lot of ways to do distributed cryptographic identity,
|
||||
all of them bad.
|
||||
|
||||
The general reason all PKIs suck is called "Zooko's Triangle."
|
||||
Your identities can be distributed, secure, or human-meaningful -
|
||||
pick any two. There is no way to solve Zooko's Triangle. The
|
||||
only way to attack it is to compromise on at least one vertex.
|
||||
|
||||
To see how Urbit works, let's start with a standard solution. An
|
||||
Urbit identity is called a "ship." You can launch your own ship
|
||||
by generating a 2048-bit RSA key and hashing it to a 128-bit
|
||||
fingerprint, which is your identity. This trivial design is the
|
||||
basis of all distributed, secure PKIs.
|
||||
|
||||
Unfortunately, an identity should be above all a _name_. A
|
||||
128-bit fingerprint looks like this:
|
||||
|
||||
316.931.986.049.624.498.975.974.005.376.666.572.699
|
||||
|
||||
which isn't a name. For no better reason than the fact that,
|
||||
unless you're an autistic savant, you are basically a monkey with
|
||||
an overgrown monkey brain. A name is something that fits in a
|
||||
register. Your monkey brain doesn't have 128-bit registers.
|
||||
|
||||
Suppose we could use 64-bit fingerprints? At first this seems
|
||||
even less promising. First of all, your monkey brain doesn't
|
||||
have 64-bit registers, either. Second, at 64 bits, collisions
|
||||
are already a real problem.
|
||||
|
||||
But we can solve both these problems. Your monkey brain doesn't
|
||||
have 64-bit registers. But anything that lets us do 64-bit
|
||||
identities might stretch down to 32 bits. And at 64 or 32 bits,
|
||||
we can't assign identities by random hash. So we'll have to find
|
||||
another way of distributing them.
|
||||
|
||||
A 32-bit identity - or even a 16-bit identity - will still never
|
||||
be human-meaningful. Perhaps we can make it human-memorable.
|
||||
Meaningful addresses are a nice feature in a social network, but
|
||||
memorable addresses are essential. And if we have memorable
|
||||
addresses, perhaps we can build meaningful names on top.
|
||||
|
||||
The classic example of a memorable address is a street address.
|
||||
Your street address identifies you precisely, using a name. You
|
||||
have this great brain hardware for remembering names. But what
|
||||
does the name of your street _mean_? Nothing at all, usually.
|
||||
And even if it does mean something, by accident or design, that
|
||||
meaning has nothing at all to do with you. (One of us grew up in
|
||||
Columbia, Maryland, which has street names like "Greek Boy
|
||||
Place.")
|
||||
|
||||
So all we need is a simple, tasteful, memorable way to remember
|
||||
32 bits - and we're on our way to approximating the Triangle.
|
||||
|
||||
Decimal notation is the worst way of remembering a 32-bit number.
|
||||
IP notation is a little better. Urbit has a typically crude
|
||||
approach: we map every byte to a CVC phoneme, making names like:
|
||||
|
||||
~tasfyn-partyv
|
||||
~sivbud-barnel
|
||||
~tomsyt-balsen
|
||||
|
||||
These strings, while quite meaningless, are no less memorable
|
||||
than real human names in many a language. Moreover, they form a
|
||||
language of their own, and become more memorable as you use them.
|
||||
And there are 4 billion of them, which (as we'll see) is almost
|
||||
exactly the right number.
|
||||
|
||||
But how do we distribute them? One obvious solution is a proof
|
||||
of work scheme, as in Bitcoin. Coordinating a global
|
||||
proof-of-work scheme is quite nontrivial, however. Also, there
|
||||
is a second reason to compromise 100% decentralization: packet
|
||||
routing. It might be possible to use a blockchain as a global
|
||||
routing table. It would take some thinking about.
|
||||
|
||||
Furthermore, there's a clue here that the Bitcoin approach just
|
||||
isn't getting. The limited subspace of short names, within the
|
||||
general space of 128-bit names, is essentially _real estate_.
|
||||
There is absolutely no reason, moral or practical, to give this
|
||||
real estate away for free to people whose only contribution is
|
||||
generating CO2 on their GPUs. Mining is not in any way a
|
||||
productive activity.
|
||||
|
||||
Rather, initially, this real estate belongs to Urbit itself. If
|
||||
Urbit has value, its real estate has value. If Urbit has no
|
||||
value, its so-called real estate is a bunch of worthless bits.
|
||||
Therefore, any value in the real estate can, should, and will be
|
||||
used to bootstrap the system from an economic perspective. Ie,
|
||||
it belongs to and will be captured by Urbit's developers and/or
|
||||
early adopters. If you find this morally wrong, sorry. You're
|
||||
probably some kind of a communist.
|
||||
|
||||
But because Urbit is a free republican society - not (ahem) a
|
||||
fascist corporate dictatorship like Google, Facebook or Twitter -
|
||||
a crucial aspect of launching or transferring a ship is that the
|
||||
decision is irreversible.
|
||||
|
||||
As the master of an Urbit ship, your informal title is
|
||||
cryptographic and _allodial_ - no one, not the government and
|
||||
certainly not us, can challenge it. Unless the attacker can
|
||||
steal your secrets. In which case, of course, she might as well
|
||||
be you. That's like Bitcoin too.
|
||||
|
||||
If Bitcoin is money, Urbit is land. (Floating land is still
|
||||
land, if there's a limited amount of it.) You own both in the
|
||||
same way, by proving you can keep a secret. A Bitcoin is not
|
||||
useful for anything, except selling to a greater fool. (We're
|
||||
just kidding - we're huge Bitcoin fans.) But an Urbit ship is
|
||||
directly useful, so long as Urbit itself is useful.
|
||||
|
||||
You fill your Bitcoin wallet either by creating new coins, or
|
||||
buying old ones from Satoshi and his cronies. You build your
|
||||
Urbit fleet by buying ships from us and our cronies. (Don't ask
|
||||
what we had to do to get them from the aliens. Those aliens are
|
||||
into a lot of strange shit, man.) Ships are transferable, but
|
||||
Urbit is not designed to be a digital currency. Transaction
|
||||
overhead is artificially high. Again, as in real estate.
|
||||
|
||||
Urbit at present is empty and worthless. So 32-bit ships -
|
||||
destroyers - are $0. Launch a 128-bit ship (a submarine) and
|
||||
ask me, ~tasfyn-partyv, for one. We'll send you one, two, or a
|
||||
dozen. You can be as anonymous as you want, if you're polite.
|
||||
But, if the network lives, a destroyer price will develop. It
|
||||
will be very low at first, but not zero. Urbit is designed to be
|
||||
free as in speech. It's not designed to be free as in beer.
|
||||
|
||||
How, cryptographically, are cloud ships distributed? And how are
|
||||
packets routed? The answer is the same - the prefix hierarchy.
|
||||
|
||||
In Urbit's naval terminology, ships above 64 bits are
|
||||
"submarines." 64-bit ships are "yachts." 32-bit, "destroyers."
|
||||
16-bit, "cruisers." 8-bit, "carriers." This also resembles a
|
||||
feudal hierarchy, so it comes with a feudal terminology. There
|
||||
are 256 imperial carriers, 65.280 royal cruisers, 4.294.901.760
|
||||
rebel destroyers, uncounted scads of private yachts, and more or
|
||||
less infinitely many rogue submarines.
|
||||
|
||||
Every ship but a submarine has a "will," or certificate chain - a
|
||||
linked list of "deeds." The first deed in this list is signed by
|
||||
the ship's hierarchical prefix, or "flagship." Mere submarine are
|
||||
independent; carriers create cruisers; cruisers create
|
||||
destroyers; destroyers create yachts.
|
||||
|
||||
A submarine is the fingerprint of its own public key; a carrier's
|
||||
fingerprint is predefined in the kernel. Anyone can create any
|
||||
number of 128-bit submarines, whose free and independent
|
||||
society the 64-bit naval hierarchy cannot interfere with. And
|
||||
of course, since Urbit is (a) in the public domain and (b) not
|
||||
patented, anyone can fork Urbit and change the carrier
|
||||
fingerprints. Anyone can also create his own independent and
|
||||
incompatible DNS, but efforts in this direction have not been
|
||||
crowned with great success. In general, the easier it is
|
||||
technically to fork open-source code or an open standard, the
|
||||
less likely a fork is to actually happen.
|
||||
|
||||
An independent ship is an independent reputation. Your flagship
|
||||
hierarchy, though it created your ship, has no control over it -
|
||||
so your reputations are and should be separate. But there are
|
||||
not 2^64 independent reputations in Urbit, only 2^32. Cruisers
|
||||
have no control over the destroyers they create, but yachts have
|
||||
no independence from the destroyers that created them.
|
||||
|
||||
The reason for this is simple - a destroyer corresponds not to a
|
||||
person, but to any institution with its own independent
|
||||
reputation. Yachts are for users, bots, or other sub-identities
|
||||
of this institution. Each destroyer has 2^32 of them, which is,
|
||||
of course, a lot.
|
||||
|
||||
How does independence work in practice? By pinning/TOFU. For
|
||||
any deed number, or "life," the first instance is accepted. Thus
|
||||
when changing secrets, perhaps to transfer a ship, the donor
|
||||
signs a new deed created by the recipient. Once any ship sees
|
||||
this deed, it will never accept another signed by the old owner.
|
||||
Thus, a cruiser cannot sell the same new destroyer twice.
|
||||
Similarly, deed 7 of ~tasfyn-partyv signs deed 8; but no ship
|
||||
which has a deed 8 for ~tasfyn-partyv will either accept deed 7,
|
||||
or any other purported deed 8 which deed 7 later signs.
|
||||
|
||||
Preventing a "double spend" thus depends on propagating the
|
||||
latest deed. For this purpose, the ocean is divided into two
|
||||
kinds of ships: friends and non-friends of the ship being
|
||||
transferred. The ship has a list of its cryptographic partners,
|
||||
or "neighbors," for which it holds a symmetric key and a routing
|
||||
(IP) address.
|
||||
|
||||
The new owner sends the new deed to all the neighbors, thus
|
||||
locking the old owner out of them. Future new friends will get
|
||||
the new owner's will the same way they get the new owner's IP
|
||||
address - by a lookup through the flagship hierarchy. Thus if we
|
||||
update both neighbors and flagship, the old owner is locked out
|
||||
and the new owner is locked in.
|
||||
|
||||
Technically, this is very much an imperfect procedure. It relies
|
||||
on social trust to make it effective. For example, a malicious
|
||||
seller could edit his neighbor list before delivering the ship.
|
||||
You probably don't want to buy a used destroyer from someone you
|
||||
distrust. Of course, the same is true of cars.
|
||||
|
||||
And more broadly, the naval hierarchy can and should provide
|
||||
general administrative support. For one thing, the big ships
|
||||
route your packets, at least when establishing contact with your
|
||||
fellow destroyers.
|
||||
|
||||
So - do you want an Urbit destroyer? You know you do. Moreover,
|
||||
they're free. Of course, if you are satisfied with a name that
|
||||
looks like
|
||||
|
||||
~machec-binnev-dordeb-sogduc--dosmul-sarrum-faplec-nidted
|
||||
|
||||
you can keep swimming around Urbit in your submarine.
|
||||
|
||||
For a while, anyway. Because, besides memorability, there is
|
||||
another reason for short names.
|
||||
|
||||
What's neat about short names is that there's a finite number of
|
||||
them. This is not a bug, but a feature. Essentially, to borrow
|
||||
the thinking of political scientist James Scott, a finite space
|
||||
is _governable_. An infinite space is ungovernable.
|
||||
|
||||
If there are an infinite number of identities, there is no way
|
||||
for anyone to distinguish between a new user and a banned user.
|
||||
A reputation can be punished by destroying it, but anyone can
|
||||
start again at zero. A parasite whose only reason to use the
|
||||
network is to abuse it can keep coming back for more. An email
|
||||
spammer will never run out of addresses to spam from.
|
||||
|
||||
IPv4 is a limited space, which almost but doesn't cure spam. The
|
||||
problem is that IPv4 addresses are neither personal nor property,
|
||||
so there is generally no easy way to punish a spammer as he
|
||||
deserves through IP blacklisting. He is very unlikely to be in
|
||||
any sense the owner of the IP address on his packets.
|
||||
|
||||
But if the email address and the IP address were the same thing,
|
||||
and the present fuzzy economic relationship between the user of
|
||||
an IP address were clear and simple, killing spam would become
|
||||
easy. You spam from a destroyer; you go on a list of spammers;
|
||||
no one will accept your unsolicited messages, ever.
|
||||
|
||||
You can get around this. You can buy a new destroyer. But the
|
||||
thing is - it costs you *money*. You're not spamming for the
|
||||
fun of it. If a destroyer costs a mere $1, the spam you send
|
||||
from it needs to earn you $1.
|
||||
|
||||
This does not make it trivial for the forces of light to hunt you
|
||||
down and render you into processed meat clippings. But it sure
|
||||
as heck evens the game. Who will win? I guess we'll see.
|
||||
|
||||
So do you want an Urbit destroyer? Read the [documentation](/2013/11/18/urbit-is-easy-ch1.html) for instructions. Come on, they're free...
|
@ -1,10 +1,4 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-arvo
|
||||
categories: tut
|
||||
sort: 1
|
||||
title: I - Basic Arvo
|
||||
---
|
||||
#Basic Arvo
|
||||
|
||||
These sections assume you've gotten Arvo up and running; if
|
||||
not, [do so](/setup) first.
|
||||
|
@ -1,11 +1,6 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-arvo
|
||||
categories: tut
|
||||
sort: 1
|
||||
title: II - More Basic Arvo
|
||||
---
|
||||
#Local revision control
|
||||
#More Basic Arvo
|
||||
|
||||
##Local revision control
|
||||
|
||||
Now you're ready to see the full power of this fully armed
|
||||
and operational revision-controlled filesystem.
|
||||
@ -146,7 +141,7 @@ But one could argue that it's just a party trick. But once your
|
||||
revision control system and your scheduler are jammed into one
|
||||
phone booth... why not jam networking in there too?
|
||||
|
||||
#Network revision control#
|
||||
##Network revision control#
|
||||
|
||||
Arvo is the OS. Urbit is the network. In theory you could write
|
||||
an Urbit client that wasn't Arvo, though it's hard to see why.
|
||||
|
1379
main/pub/src/doc/say/arvo/app.md
Normal file
1379
main/pub/src/doc/say/arvo/app.md
Normal file
File diff suppressed because it is too large
Load Diff
522
main/pub/src/doc/say/arvo/pub2.md
Normal file
522
main/pub/src/doc/say/arvo/pub2.md
Normal file
@ -0,0 +1,522 @@
|
||||
# Urbit is a global functional filesystem.
|
||||
|
||||
The whole idea of a filesystem is that a file is a function of a
|
||||
path. If it's an *immutable* filesystem like Urbit, the function
|
||||
(though partial), once bound never changes.
|
||||
|
||||
This is kind of neat. What'd be really neat, though, is if the
|
||||
namespace operator, rather than just returning one static file,
|
||||
produced an immutable function on your whole filesystem. Or
|
||||
better yet, on *all visible data in the world*.
|
||||
|
||||
It would also be ideal if the product of this function was not
|
||||
just a binary blob, but a *typed data structure*. Even better -
|
||||
the product might not be data, but code, or a mix of data and
|
||||
code - a function, an object, a library, even an application.
|
||||
|
||||
What's basically irritating about the Web is that it's almost
|
||||
this, but it's not this. The Web is almost a web-of-data, but
|
||||
it's not a web-of-data. So it does not scale as a substrate for
|
||||
complex higher-level communication patterns, and even for simple
|
||||
use cases breaks frequently in production.
|
||||
|
||||
The road to a real *global functional filesystem* is perfectly
|
||||
straightforward in principle. If a function of one path is
|
||||
immutable, so is a function of two, or n. More generally, any
|
||||
immutable function of a filename is a referentially transparent
|
||||
name - a concept familiar in many functional languages.
|
||||
|
||||
We already put source files in immutable filesystems, which we
|
||||
call "revision-control systems." To convert this design into a
|
||||
functional filesystem, all we have to do is define a precise
|
||||
functional semantics for these source files, including in that
|
||||
semantics the power to read back into the namespace.
|
||||
|
||||
In principle this is quite straightforward. We need exactly two
|
||||
components for our functional filesystem: an immutable filesystem
|
||||
and a functional language. Neither are particularly exotic bits
|
||||
of system software kit.
|
||||
|
||||
But they should be made to fit each other. Could you strap
|
||||
github to Haskell and make a global functional filesystem? Well,
|
||||
sort of. Certainly in principle. You could also strap a car
|
||||
engine to a mountain bike, and make a motorcycle. It wouldn't be
|
||||
a very good motorcycle.
|
||||
|
||||
Urbit is not actually a very good motorcycle. Not yet, anyway.
|
||||
It is a motorcycle, though. Let's take it for a spin.
|
||||
|
||||
|
||||
# Get your urbit.
|
||||
|
||||
First, grab yourself a "destroyer" at urbit.org. You'll come
|
||||
away with an phonemic urbit name, or "ship" - mine is
|
||||
`~tasfyn-partyv`. Let's say `~lacser-dovlet` is yours.
|
||||
|
||||
As the length of the string suggests, here are only 2^32
|
||||
destroyers, so we have to ration them. You can skip this step,
|
||||
but only at the expense of urbiting from a mere "submarine," a
|
||||
self-generated 128-bit ship - like:
|
||||
|
||||
~bacbyl-dabdyr-marfel-palnep--tompex-nibnym-sidpet-ticfus
|
||||
|
||||
In theory a submarine can do anything a destroyer can. In
|
||||
practice, if you have any interest in networking with other
|
||||
ships - don't be surprised if they assume you're a bot.
|
||||
|
||||
Obviously, your ship is the root of your own personal namespace.
|
||||
`~lacser-dovlet` is your "me function." Urbit, as a global
|
||||
functional filesystem, is the union of everyone's me function.
|
||||
|
||||
(Urbit should not be confused with distributed storage systems,
|
||||
like Freenet or IPFS. In Urbit all your data is on your own
|
||||
computer, though it may be a virtual computer in the cloud.)
|
||||
|
||||
|
||||
# The shape of urbitspace.
|
||||
|
||||
But wait. How, exactly, are these shorter names allocated?
|
||||
|
||||
As Samuel L. Jackson once put it: for money, bitch! But you're
|
||||
an early adopter and we love you. So free ships for you, your
|
||||
friends, and everyone.
|
||||
|
||||
Seriously - it will be a *long* time, if ever, before you have
|
||||
any trouble getting a free Urbit destroyer, from us or anyone.
|
||||
The main thing we want to make sure is that we're giving them
|
||||
out mostly to unique humans. In the long run, this is quite hard
|
||||
on the Internets. We're still small so no abuser gives a hoot.
|
||||
|
||||
And we (the evil Tlon Corporation, to be exact) are *not* the
|
||||
only people who *can* give away destroyers, just the only people
|
||||
doing it right now. Actually, some of the people who hold this
|
||||
right are kind of our enemies - or at least, disgruntled former
|
||||
employees (of the evil Tlon Corporation). They obviously can't
|
||||
be trusted to collude in our evil schemes! So if you fear us,
|
||||
you're probably safe with them.
|
||||
|
||||
Moreover, more importantly: once you own a destroyer (or more
|
||||
realistically, once you sail it away from our harbor), it's
|
||||
cryptographically yours and we (the evil Tlon Corporation) have
|
||||
no practical way to steal it back, spy on you, etc. No, Urbit
|
||||
isn't just another way of selling yourself into digital serfdom.
|
||||
|
||||
It's also important not to confuse Urbit with a cryptocurrency.
|
||||
Urbitspace is digital land, not digital money. It is more like
|
||||
the DNS than like Bitcoin. As in real estate, Urbit transactions
|
||||
are unusual and have high frictional cost.
|
||||
|
||||
Making Urbit a bad currency is a feature, not a bug. Urbit is
|
||||
designed to be neither particularly easy for governments to
|
||||
control, nor particularly useful for criminals to abuse. Both
|
||||
are difficult goals to hit, but they go well together. Any
|
||||
system that attracts criminals will inherently also attract their
|
||||
natural predator.
|
||||
|
||||
Also, as with land, the price of urbitspace is driven by direct
|
||||
utility, not just collective speculation. And the only way land
|
||||
is ever given away for free is as a homestead. Your free urbit
|
||||
is for use, not for investment. Urbitspace will be worth
|
||||
something if and only if it's useful to someone.
|
||||
|
||||
|
||||
# More namespace design digressions.
|
||||
|
||||
Feel free to skip these if you really couldn't care less why.
|
||||
|
||||
Why are ship names synthetic strings, not user-chosen strings?
|
||||
The simplest way to assign handles is with a central authority,
|
||||
like Facebook. If you like being a digital serf, please, you
|
||||
already know where to go. But even if you issue handles with a
|
||||
proof-of-work scheme (like Namecoin), you still have a name rush.
|
||||
And a decentralized system can have no way of negotiating with
|
||||
real-world name owners whose existing claims conflict.
|
||||
|
||||
Also, there are concrete social benefits to a completely
|
||||
impersonal address. An Urbit name is like a street name. It
|
||||
doesn't mean anything and is not intended to. Even if it
|
||||
accidentally means something, everyone ignores the accident -
|
||||
when we get directions to a Bush Street or a Clinton Road, we
|
||||
rarely even think of thinking of the politicians. Worse, handles
|
||||
in real life tend to be just lame.
|
||||
|
||||
Why use short names at all, not just hashes? Why destroyers?
|
||||
Why doesn't everyone just sail the Urbit seas in a submarine?
|
||||
|
||||
Two very important reasons. One, with only 2^32 names, an Urbit
|
||||
name can be as memorable as a natural human name, or at least a
|
||||
name in a foreign language. Two, when we have a limited supply
|
||||
of names, network abusers don't find it so easy to disappear and
|
||||
reappear under a new name.
|
||||
|
||||
(In fact we're very confident that it will be possible to keep
|
||||
Urbit spam-free in practice. This would be harder if synthetic
|
||||
short names were distributed as coins in a proof-of-work scheme.
|
||||
Since Urbit treats namespace as property from day one, with no
|
||||
"airdrop" to unproductive miners, there are no anonymous original
|
||||
owners of Urbitspace. Everyone who owns a block has an incentive
|
||||
to distributed it only to well-qualified individual users: as
|
||||
with both IP addresses and actual real estate, Urbit blocks can
|
||||
easily develop a collective bad (or good) reputation.)
|
||||
|
||||
It is of course possible to use Urbit anonymously, of course.
|
||||
But only in one way: somewhere along the decentralization chain
|
||||
from the (well-identified) developers to the user, someone has to
|
||||
transfer urbitspace and be trusted to forget the recipient. It
|
||||
is to be expected that, in order to provide this useful service,
|
||||
the intermediary will demand some trust from the upstream users -
|
||||
presumably, at least, evidence of humanity.
|
||||
|
||||
Point is: these are not the droids you're looking for. You are
|
||||
not selling yourself into digital serfdom. You are escaping from
|
||||
digital serfdom. You are not selling yourself into digital
|
||||
serfdom. You are escaping from digital serfdom. Freedom is
|
||||
slavery. Urbit is freedom. Now, please raise your right hand
|
||||
and continue with the installation process.
|
||||
|
||||
# Install the SDK.
|
||||
|
||||
(Instructions here.)
|
||||
|
||||
If you got a destroyer, this will set up a local "yacht" on your
|
||||
own computer. (Otherwise, just work out of your local
|
||||
submarine.) Your destroyer lives in the cloud, where computing
|
||||
is actually reliable. Leave it there. (You can sail it home, or
|
||||
to some other harbor, any time you like.)
|
||||
|
||||
Suppose your destroyer is `~lacser-dovlet`, and your yacht is
|
||||
`~sidpet-lacser-dovlet`. Urbit will make the directory
|
||||
`~/urb/sidpet-lacser-dovlet/`, and symlink it, for convenience,
|
||||
to `~/urb/lacser-dovlet/`.
|
||||
|
||||
This is a hotsync directory. When you edit, add or delete files
|
||||
under the *pier* directory, `~/urb/sidpet-lacser-dovlet/`, it
|
||||
syncs them automatically with your yacht, then syncs the yacht
|
||||
with `~lacser-dovlet` in the sky. Sort of like Dropbox. Except
|
||||
that (a) Dropbox is a hard disk and Urbit is a computer, and (b)
|
||||
your Urbit computer is actually, in some sense, like, yours.
|
||||
(Urbit is freedom. Repeat. Urbit is freedom.)
|
||||
|
||||
|
||||
# Post and edit a webpage.
|
||||
|
||||
Start vere:
|
||||
|
||||
$ vere ~lacser-dovlet
|
||||
|
||||
Run vim on `~/urb/lacser-dovlet/main/pub/fab/fun/one.md`, and type:
|
||||
|
||||
This is a *fun experiment* in markdown.
|
||||
|
||||
Save the file. Then point a browser at
|
||||
|
||||
https://lacser-dovlet.urbit.org/pub/fab/fun/one
|
||||
|
||||
You'll see the rendered markdown. Then, change the file to read
|
||||
|
||||
This is a *different fun experiment* in markdown.
|
||||
|
||||
Save it. Then look at your browser. Did you have to hit reload?
|
||||
*How exactly did that file get from your editor to your browser?*
|
||||
|
||||
|
||||
# Urbit filesystem basics.
|
||||
|
||||
It's difficult when looking at this system superficially to
|
||||
separate the web server from the namespace. Your namespace is
|
||||
your namespace - the web server is just a legacy translation
|
||||
layer from HTTP's rather non-functional namespace.
|
||||
|
||||
(In some senses it might make more sense to compute functionally
|
||||
from Urbit's own command line. But your browser is a much better
|
||||
renderer than anything in Urbit, and you're better at using it.)
|
||||
|
||||
We have seen two kinds of filenames go into Urbit: Unix filenames
|
||||
and URLs. Obviously, neither of these is referentially
|
||||
transparent. And neither is the same thing as an Urbit path, or
|
||||
*beam*.
|
||||
|
||||
An Urbit beam has mostly the same syntax as a Unix path. The
|
||||
beam always begins with the same three spans, `/ship/desk/case/`.
|
||||
|
||||
A ship is your computer, of course; a desk is a branch, project,
|
||||
repository, etc; a case is a version. Versions are labels,
|
||||
change numbers, or dates.
|
||||
|
||||
Besides the fact that revision control is part of the filesystem,
|
||||
the only other weird thing about Urbit is that files and
|
||||
directory are orthogonal. In Unix, you can't have one file
|
||||
`/one/two/three` and another file `/one/two/three/four`, because
|
||||
the `three` inode would have to be both a file and a directory.
|
||||
|
||||
Urbit uses different APIs for data and metadata requests, and
|
||||
directories are implicit. The directory `/one/two/three` exists if
|
||||
and only if there are files with that path as a prefix. There is
|
||||
no `mkdir`, etc.
|
||||
|
||||
Without clunky stateful directories, our normal convention is to
|
||||
use the last span of the path as the file type. So where Unix
|
||||
has `/one/two/three/four.html`, Urbit has `/one/two/three/four/html`.
|
||||
|
||||
|
||||
# Functional transformations.
|
||||
|
||||
In the test above, we started with a Unix filename, synced it
|
||||
against an Urbit beam, and served it up as a URL. Ie, we went
|
||||
from the Unix filename
|
||||
|
||||
~/urb/lacser-dovlet/main/pub/fab/fun/one.md
|
||||
|
||||
to the Urbit beam
|
||||
|
||||
/~lacser-dovlet/main/~2014.7.30/pub/fab/fun/one/md
|
||||
|
||||
to the URL
|
||||
|
||||
https://lacser-dovlet.urbit.org/pub/fab/fun/one
|
||||
|
||||
What happened internally? Without getting into too much
|
||||
detail, the clean URL above was defaulted to
|
||||
|
||||
https://lacser-dovlet.urbit.org/pub/fab/fun/one.html
|
||||
|
||||
which then made Urbit try to serve the file
|
||||
|
||||
/~lacser-dovlet/main/~2014.7.30/pub/fab/fun/one/html
|
||||
|
||||
which did not exist, but we found your markdown source
|
||||
|
||||
/~lacser-dovlet/main/~2014.7.30/pub/fab/fun/one/md
|
||||
|
||||
and parsed it into the markdown tree
|
||||
|
||||
/~lacser-dovlet/main/~2014.7.30/pub/fab/fun/one/down
|
||||
|
||||
which was converted into the HTML tree
|
||||
|
||||
/~lacser-dovlet/main/~2014.7.30/pub/fab/fun/one/hymn
|
||||
|
||||
printed out into the HTML text file
|
||||
|
||||
/~lacser-dovlet/main/~2014.7.30/pub/fab/fun/one/html
|
||||
|
||||
and finally, wrapped up as the MIME object
|
||||
|
||||
/~lacser-dovlet/main/~2014.7.30/pub/fab/fun/one/mime
|
||||
|
||||
to ship back to you with a 200. Then, when you saved `one.md`
|
||||
again, we did all this again and showed you the new document.
|
||||
(We'll again delay on how *this* happened.)
|
||||
|
||||
|
||||
# Functional construction.
|
||||
|
||||
This kind of format translation is a relatively straightforward
|
||||
use of functional FS techniques. It's definitely handy but
|
||||
doesn't really rise to the level of cool.
|
||||
|
||||
Here's something cool. Again with `vim`, edit
|
||||
|
||||
~/urb/lacser-dovlet/pub/fab/fun/two/down.hook
|
||||
|
||||
to be
|
||||
|
||||
:~ :- %par
|
||||
:~ tex/"This is a "
|
||||
emp/bent/~[tex/"fun experiment "]
|
||||
tex/"in markdown."
|
||||
== ==
|
||||
|
||||
Now, point your browser at
|
||||
|
||||
https://lacser-dovlet.urbit.org/pub/fab/fun/two
|
||||
|
||||
What did we do here? Instead of a static file containing
|
||||
markdown text, we wrote a program in Hoon that generated
|
||||
a markdown value. How did we find this? We went from
|
||||
|
||||
https://lacser-dovlet.urbit.org/pub/fab/fun/two.html
|
||||
|
||||
to the file you created,
|
||||
|
||||
/~lacser-dovlet/main/~2014.7.30/pub/fab/fun/two/down/hook
|
||||
|
||||
Then we followed a simple rule: you can make the file
|
||||
`/one/two/three` by compiling and running the source file
|
||||
`/one/two/three/hook`.
|
||||
|
||||
/~lacser-dovlet/main/~2014.7.30/pub/fab/fun/two/down
|
||||
|
||||
and then proceeded as above. You can test that this is really a
|
||||
program, and still autoloads and stuff, by doing something funky
|
||||
- like:
|
||||
|
||||
:~ :- %par
|
||||
:~ tex/"This is a "
|
||||
emp/bent/~[tex/"fun experiment "]
|
||||
tex/"in markdown; 2 + 2 is {<(add 2 2)>}."
|
||||
== ==
|
||||
|
||||
|
||||
# Computing an actual function.
|
||||
|
||||
While these files are functions in a sort of abstract sense, they
|
||||
are not actually functions in the normal sense of the word. A
|
||||
function needs arguments, after all.
|
||||
|
||||
Since we're talking to our function through the Web, it makes
|
||||
sense to try to send arguments as query strings. Also, though
|
||||
we've had some fun generating markdown nouns (with totally
|
||||
generic Hoon), it seems more appropriate since we're writing
|
||||
webpages and stuff to generate HTML.
|
||||
|
||||
Let's edit
|
||||
|
||||
~/urb/lacser-dovlet/main/pub/fab/fun/three/hymn.hook
|
||||
|
||||
and put in
|
||||
|
||||
;html
|
||||
;head ;title: Fun Experiment Three
|
||||
==
|
||||
;body
|
||||
;p: This is an ;{i "HTML file."}
|
||||
==
|
||||
==
|
||||
|
||||
and view it at
|
||||
|
||||
https://lacser-dovlet.urbit.org/pub/fab/fun/three
|
||||
|
||||
We saw above how a `%hymn` turns into an `%html`, so we don't
|
||||
need to repeat it. But again, this source file is best seen
|
||||
as a program which produces an HTML tree. Sorta like the DOM.
|
||||
|
||||
(This syntax is also totally generic Hoon. In a sense - Hoon is
|
||||
customized without apology for building XML nouns. In fact, it
|
||||
has special cases for `<script`> and `<style>`, so it's even
|
||||
slightly specific to HTML. This is not the most elegant language
|
||||
design decision in the world, but it seemed preferable to making
|
||||
people use a separate template language. Hoon is not the world's
|
||||
best template language, but it's not just a template language.)
|
||||
|
||||
But what would be nicer would be -
|
||||
|
||||
=+ fib=|=(x=@ ?:((lth x 2) 1 (add $(x (dec x)) $(x (sub x 2)))))
|
||||
;html
|
||||
;head ;title: Fun Experiment Three
|
||||
==
|
||||
;body
|
||||
;p ; This is an ;{i "HTML file"} which
|
||||
; computes the Fibonacci number
|
||||
; of 12: {<(fib 12)>}.
|
||||
==
|
||||
==
|
||||
==
|
||||
|
||||
There's clearly a *function* here. But it's not *of* anything...
|
||||
|
||||
|
||||
# An actual function, query string edition.
|
||||
|
||||
Okay, so we want an actual function. In
|
||||
|
||||
~/urb/lacser-dovlet/pub/fab/fun/four/hymn.hook
|
||||
|
||||
put
|
||||
|
||||
/= gas /$ fuel
|
||||
::
|
||||
=+ arg=(biff (~(get by qix.gas) %number) (slat %ud))
|
||||
=+ fib=|=(x=@ ~+(?:((lth x 2) 1 (add $(x (dec x)) $(x (sub x 2))))))
|
||||
::
|
||||
;html
|
||||
;head
|
||||
;title: Fun Experiment Four
|
||||
==
|
||||
;body
|
||||
;p: Welcome, {<cip.ced.gas>}!
|
||||
;+ ?~ arg
|
||||
;p: Usage: ?number=x
|
||||
;p ; This is an ;{i "HTML file"} which
|
||||
; computes the Fibonacci number
|
||||
; of {<u.arg>}: {<(fib u.arg)>}.
|
||||
==
|
||||
==
|
||||
==
|
||||
|
||||
Try it:
|
||||
|
||||
https://lacser-dovlet.urbit.org/pub/fab/fun/four?number=14
|
||||
https://lacser-dovlet.urbit.org/pub/fab/fun/four?number=144
|
||||
https://lacser-dovlet.urbit.org/pub/fab/fun/four
|
||||
|
||||
This page does appear to be a function of the query string - and
|
||||
some other stuff. For one thing, Urbit is now tracking your
|
||||
behavior. Or at least your IP address.
|
||||
|
||||
Actually, at the Web level, the page broadly speaking is a
|
||||
function of the query string and the session state. The usual
|
||||
Web cruft, basically.
|
||||
|
||||
However, the page is not computed at the chaotic Web level - it's
|
||||
computed at the functional publishing level. Functional
|
||||
publishing does not know the Web exists. We can reveal the true
|
||||
and complete input to the page function with a sneaky trick.
|
||||
|
||||
In
|
||||
|
||||
~/urb/lacser-dovlet/pub/fab/fun/five/hymn.hook
|
||||
|
||||
put
|
||||
|
||||
/= ctx /$ |=([p=beam q=path] +<)
|
||||
::
|
||||
;html
|
||||
;head
|
||||
;title: Fun Experiment Five
|
||||
==
|
||||
;body
|
||||
;p: This page was built at {<(tope p.ctx)>}.
|
||||
;br;
|
||||
;p: The remainder path was {<q.ctx>}.
|
||||
==
|
||||
==
|
||||
|
||||
Try it:
|
||||
|
||||
https://lacser-dovlet.urbit.org/pub/fab/fun/five
|
||||
|
||||
What you'll see is that `q.ctx`, which we used to be passing to
|
||||
the Web path parser `fuel`, is an ugly (but URL-safe) string
|
||||
containing data, encoded as a path component - let's say,
|
||||
`web/DATA`. This string is actually inverted - properly
|
||||
speaking, it's `DATA/web`.
|
||||
|
||||
When we want to compute a dynamic functional namespace which is
|
||||
not just a trivial static file, or a translated file, we divide
|
||||
the Urbit beam into two parts - *driver* and *remainder*.
|
||||
The driver is the path to the function; the remainder is the
|
||||
input to the function.
|
||||
|
||||
In this case, the Urbit webserver asked the filesystem for
|
||||
|
||||
/~lacser-dovlet/main/~2014.7.30/pub/fab/fun/five/DATA/web
|
||||
|
||||
with the content type `%html`. (We lied a little earlier - the
|
||||
content type, or `mark`, is sent separately to the filesystem.)
|
||||
|
||||
To resolve the beam, we travel up it from the bottom, looking for
|
||||
drivers of some sort. Urbit did not find any files in
|
||||
`fun/five/DATA/web`. It also did not find any files in
|
||||
`fun/five/DATA`.
|
||||
|
||||
Going up, it found `fun/five/hymn/hook`, which it took as a way of
|
||||
making `fun/one` with the mark `%hymn`. Ie, an HTML document
|
||||
tree, which we know how to turn into `%html`, so great.
|
||||
|
||||
Then, it gave the remainder of the beam, `/DATA/web` - but
|
||||
inverted to `/web/DATA`, because we decode the remainder from
|
||||
the end inward - as a resource to our page generator. And this
|
||||
is how we could print your IP address and stuff...
|
||||
|
515
main/pub/src/doc/say/arvo/pub3.md
Normal file
515
main/pub/src/doc/say/arvo/pub3.md
Normal file
@ -0,0 +1,515 @@
|
||||
# Ford changes for non-dummies.
|
||||
|
||||
You're used to .hoon files being parsed into a ++twig. This
|
||||
stays true for vanes, hoon.hoon, and %batz apps; but for
|
||||
everything else we get a ++hood.
|
||||
|
||||
It happens that every old .hoon file is also a ++hood. but there
|
||||
are some extra runes at the top which do interesting cool things.
|
||||
|
||||
|
||||
# Top-level file stuff.
|
||||
|
||||
The first, simplest thing that the new build system gives you:
|
||||
without using any other features at all, we treat your file as a
|
||||
list of nested twigs, ie `=~`, not a single twig. So instead of
|
||||
|
||||
=> |%
|
||||
++ library
|
||||
--
|
||||
|%
|
||||
++ program
|
||||
--
|
||||
|
||||
you can write - using my new, official, stylized-tilde divider:
|
||||
|
||||
:: One line that describes this source file.
|
||||
::::
|
||||
:: /hoon/file/fab/pub
|
||||
|%
|
||||
++ library
|
||||
--
|
||||
::
|
||||
::::
|
||||
::
|
||||
|%
|
||||
++ program
|
||||
--
|
||||
|
||||
The conventional way of doing `!:` has also changed. The trouble
|
||||
is that `!:` is a twig and it cannot come above ++hood runes.
|
||||
Actually, the right place to apply !: is per core, and it should
|
||||
stand out visually because it indicates immature code:
|
||||
|
||||
!: |%
|
||||
++ library
|
||||
--
|
||||
|
||||
But you should always use at least one ++hood directive, namely
|
||||
`/?`. This is tied to the version of Urbit as a whole, which in
|
||||
practice means the version of `%zuse` - also defined as ++zuse.
|
||||
Thus, `zuse` is 314 and `hoon` is 164.
|
||||
|
||||
The assumption, currently shaky, is that backward compatibility
|
||||
in both ++zuse and ++hoon will never be broken. This is
|
||||
basically what it means to do Kelvin versioning. With
|
||||
|
||||
/? 314
|
||||
|
||||
you state that this code should work iff `(lte zuse 314)`.
|
||||
|
||||
So this is what the start of a normal .hoon file looks like:
|
||||
|
||||
:: At least one line that describes this source file.
|
||||
::
|
||||
:::: /hoon/file/fab/pub
|
||||
::
|
||||
/? 314
|
||||
/- html, hymn, down, tlon-radio-a
|
||||
/+ tlon-radio, tlon-twitter
|
||||
::
|
||||
:::: ~tasfyn-partyv, ~tomsyt-balsen, ~talsur-todres
|
||||
::
|
||||
|%
|
||||
++ code
|
||||
!!
|
||||
--
|
||||
|
||||
Note that hood runes by convention use *four* spaces, making
|
||||
them visually distinct from twig runes - and preserving the
|
||||
Rastersysteme.
|
||||
|
||||
Formal comments: the path is the `++spur` (path after /===/) of
|
||||
the file, which is generally stored inverted. The list of ships
|
||||
is the list of people who have changed the code, oldest first.
|
||||
|
||||
Anyone whose (new) .hoon files do not match this template is
|
||||
eligible for a yellow card! I mean it!
|
||||
|
||||
|
||||
# Mad hood runes.
|
||||
|
||||
Let's go through these runes one by one, creating a wacky test
|
||||
program as we go.
|
||||
|
||||
There are three main sections of a hood: hooves, horns, hoops.
|
||||
They must be in the file in that order. Let's talk about them
|
||||
in the *opposite* order, though.
|
||||
|
||||
|
||||
# Indirect hoops (simple).
|
||||
|
||||
Hoops are the actual code of your program. You can buy two kinds:
|
||||
|
||||
$% [%& p=twig] :: direct twig
|
||||
[%| p=beam] :: resource location
|
||||
== ::
|
||||
|
||||
The program produced by a hood is a stack of twigs which are
|
||||
composed by `=~`, ie, connected with `=>`. You can specify these
|
||||
twigs directly, as in the above, or you can load them from Urbit.
|
||||
|
||||
Let's build a toy program, `mad`, that uses mad hood skillz.
|
||||
First, let's load it with an indirect hoop. In
|
||||
|
||||
~/urb/pub/src/mad/fib.hoon
|
||||
|
||||
we put
|
||||
|
||||
|%
|
||||
++ fib |=(x=@ ~+(?:((lth x 2) 1 (add $(x (dec x)) $(x (sub x 2))))))
|
||||
--
|
||||
|
||||
and in
|
||||
|
||||
~/urb/pub/fab/mad/one/hymn.hook
|
||||
|
||||
we put
|
||||
|
||||
:: Our first experiment with major hood runes.
|
||||
::
|
||||
:::: /hoon/one/mad/fab/pub
|
||||
::
|
||||
/= gas /$ fuel
|
||||
// /===/pub/src/mad/fib
|
||||
::
|
||||
:::: ~tasfyn-partyv
|
||||
::
|
||||
=+ arg=(biff (~(get by qix.gas) %number) (slat %ud))
|
||||
::
|
||||
;html
|
||||
;head
|
||||
;title: Mad Experiment One
|
||||
==
|
||||
;body
|
||||
;+ ?~ arg
|
||||
;p: Usage: ?number=x
|
||||
;p ; This is an ;{i "HTML file"} which
|
||||
; computes the Fibonacci number
|
||||
; of {<u.arg>}: {<(fib u.arg)>}.
|
||||
==
|
||||
==
|
||||
==
|
||||
|
||||
|
||||
# Indirect hoops (advanced).
|
||||
|
||||
Indirect hoops have a still more amazing power - they can make
|
||||
cores out of directories themselves.
|
||||
|
||||
Let's `cp -r` `fab/mad/one` to `fab/mad/two` and put, in
|
||||
|
||||
~/urb/pub/src/mad/tools/fib.hoon
|
||||
|
||||
the single line
|
||||
|
||||
|=(x=@ ~+(?:((lth x 2) 1 (add $(x (dec x)) $(x (sub x 2))))))
|
||||
|
||||
Then, in
|
||||
|
||||
~/urb/pub/fab/mad/two/hymn.hook
|
||||
|
||||
we put:
|
||||
|
||||
:: Our second experiment with major hood runes.
|
||||
::
|
||||
:::: /hoon/two/mad/fab/pub
|
||||
::
|
||||
/= gas /$ fuel
|
||||
// /===/pub/src/mad/tools
|
||||
::
|
||||
:::: ~tasfyn-partyv
|
||||
::
|
||||
=+ arg=(biff (~(get by qix.gas) %number) (slat %ud))
|
||||
;html
|
||||
;head
|
||||
;title: Mad Experiment Two
|
||||
==
|
||||
;body
|
||||
;+ ?~ arg
|
||||
;p: Usage: ?number=x
|
||||
;p ; This is an ;{i "HTML file"} which
|
||||
; computes the Fibonacci number
|
||||
; of {<u.arg>}: {<(fib u.arg)>}.
|
||||
==
|
||||
==
|
||||
==
|
||||
|
||||
Note that our function name *does not exist anywhere in the
|
||||
source code*, except where it is called. Rather, it's implicit
|
||||
from the filename.
|
||||
|
||||
It would be superfluous to observe that this mechanism is
|
||||
recursive - you can create arbitrarily deep hierarchies of cores
|
||||
whose symbolic namespace follows the source code tree.
|
||||
|
||||
Don't mistake indirect hoops, however, for a library loading
|
||||
mechanism. Hoops may be used to *build* libraries, but `/+`
|
||||
is used to load them. Indirect hoops are for splitting up your
|
||||
program into separate parts, not for sharing code between
|
||||
programs.
|
||||
|
||||
|
||||
# Horns.
|
||||
|
||||
Another thing we like to do is compile data into our application.
|
||||
No, really - one of the stupidest things in many programming
|
||||
environment is dynamically loading static resources. We really
|
||||
try not to do that in Urbit. (At least, this week we try!)
|
||||
|
||||
Before her hoops, the programmer can load a set of referentially
|
||||
transparent `horns`, or resources.
|
||||
|
||||
In
|
||||
~/urb/pub/fab/mad/res/hello/hymn.hook
|
||||
|
||||
we put:
|
||||
|
||||
;p: Hello, world.
|
||||
|
||||
and in
|
||||
|
||||
~/urb/pub/fab/mad/three/hymn.hook
|
||||
|
||||
we put:
|
||||
|
||||
:: This third experiment wears the horns.
|
||||
::
|
||||
:::: /hoon/three/mad/fab/pub
|
||||
::
|
||||
/= hello /: /===/pub/fab/mad/res/hello /hymn/
|
||||
:
|
||||
:::: ~tasfyn-partyv
|
||||
::
|
||||
::
|
||||
;html
|
||||
;head
|
||||
;title: Mad Experiment Three
|
||||
==
|
||||
;body
|
||||
;+ hello
|
||||
==
|
||||
==
|
||||
|
||||
What did we do? We loaded a typed, dynamically built resource
|
||||
from the global namespace onto our reef.
|
||||
|
||||
Note the runic syntax above. You might suspect that this is a
|
||||
tall mode, and you might be right. It condenses:
|
||||
|
||||
/= hello /:/======/res/hello:/hymn/
|
||||
|
||||
Or even:
|
||||
|
||||
Note also how we avoid repeating shared path spans.
|
||||
|
||||
Also, unlike twig runes, hood runes can be replaced with a
|
||||
semantic codename:
|
||||
|
||||
/dub hello /see /======/res/hello /hymn/
|
||||
|
||||
|
||||
# More horns.
|
||||
|
||||
Cool as it is, this example barely scratches the awesome that is
|
||||
Urbit resource loading. For instance, in
|
||||
|
||||
~/urb/pub/fab/mad/res/bible
|
||||
|
||||
put, in `1.html`, `2.html`, and `3.html` respectively,
|
||||
|
||||
<p>The earth was without form, and void.</p>
|
||||
|
||||
<p>Then Cain slew Abel.</p>
|
||||
|
||||
<p>I bring not peace, but a sword.</p>
|
||||
|
||||
then, in
|
||||
|
||||
~/urb/pub/fab/mad/four/hymn.hook
|
||||
|
||||
put
|
||||
|
||||
:: This fourth experiment is profoundly biblical.
|
||||
::
|
||||
:::: /hoon/four/mad/fab/pub
|
||||
::
|
||||
/= bible /: /======/res/bible
|
||||
/; |= a=(list (pair ,@ manx))
|
||||
(turn a |=([* b=manx] b))
|
||||
/@
|
||||
/hymn/
|
||||
::
|
||||
:::: ~tasfyn-partyv
|
||||
::
|
||||
!:
|
||||
;html
|
||||
;head
|
||||
;title: Mad Experiment Four
|
||||
==
|
||||
;body
|
||||
;* bible
|
||||
==
|
||||
==
|
||||
|
||||
What happened here? The `/@` rune loads a list of files named by
|
||||
decimals in ascending order, with the protocol `/hymn/` - the
|
||||
result of parsing HTML. This produces not a list of hymns
|
||||
(actually just `++manx`, the XML node type), but a list of pairs
|
||||
`[number manx]`, so we need to strip the numbers with `/;`.
|
||||
|
||||
We can also understand `/:` a little better. It doesn't mean
|
||||
"load the horn at this beam" - it means "set the beam at which
|
||||
horns within this one are loaded." There is also its cousin
|
||||
`/,`, which just descends within the current beam. The beam
|
||||
starts as the path to the hook file itself.
|
||||
|
||||
Nothing about this system restricts the tree to a fixed depth -
|
||||
we could have not just `/hymn/` in our bible directory,
|
||||
but another `/@` or other arbitrary resource directives.
|
||||
|
||||
`/@` has several cousins for different naming schemes. `/|`
|
||||
reads a folder named by `@dr`, ie, relative date. `/&` reads
|
||||
one named by `@da`, ie, absolute date. An excellent way to
|
||||
organize random events named only by time is to nest `/|` within
|
||||
`/&`, eg, a tree of days with that day's events in it.
|
||||
|
||||
You can also use `/%` to load a map of unparsed names. Finally,
|
||||
`/*` handles multiple heterogeneous subtrees with different
|
||||
horns. You can cast the product of `/*` to a map with `/^`,
|
||||
or you can leave it as a tuple. You can also build a simple list
|
||||
of horns with `/.`.
|
||||
|
||||
Finally, we've already seen `/$`, which calls a parsing function
|
||||
(`++fuel` for web remainders) on the location and remainder of
|
||||
the file. And `/~` lets you stick a simple twig directly in your
|
||||
resource tree, for computing "resources" entirely by hand.
|
||||
|
||||
Here is the structure of horns:
|
||||
|
||||
++ horn :: resource tree
|
||||
$% [%ape p=twig] :: /~ twig by hand
|
||||
[%arg p=twig] :: /$ argument
|
||||
[%day p=horn] :: /| list by @dr
|
||||
[%dub p=term q=horn] :: /= apply face
|
||||
[%fan p=(list horn)] :: /. list
|
||||
[%for p=path q=horn] :: /, descend
|
||||
[%hub p=horn] :: /@ list by @ud
|
||||
[%man p=(map span horn)] :: /* hetero map
|
||||
[%nap p=horn] :: /% homo map
|
||||
[%now p=horn] :: /& list by @da
|
||||
[%saw p=twig q=horn] :: /; operate on
|
||||
[%see p=beam q=horn] :: /: relative to
|
||||
[%sic p=tile q=horn] :: /^ cast
|
||||
[%toy p=mark] :: /mark/ static
|
||||
== ::
|
||||
|
||||
See `%ford` for the structure of horns, and `++fair` in ford for
|
||||
the exact syntax and semantics.
|
||||
|
||||
|
||||
# Hooves: structures.
|
||||
|
||||
At the top of your hood comes the proper way of sharing code
|
||||
between programs: `/-` and `/+`, for structure and library
|
||||
loading respectively.
|
||||
|
||||
Let's try `/-` by reusing one of our earlier examples - this
|
||||
time, with an actual type cast. In
|
||||
|
||||
~/urb/pub/fab/mad/five/down.hook
|
||||
|
||||
put
|
||||
|
||||
/- down
|
||||
^- down
|
||||
:~ :- %par
|
||||
:~ tex/"This is a "
|
||||
emp/bent/~[tex/"fun experiment "]
|
||||
tex/"in markdown; 2 + 2 is {<(add 2 2)>}."
|
||||
== ==
|
||||
|
||||
In plain English, we loaded the `++down` structure and cast our
|
||||
hand-rolled markdown to it. Where did we get this code, exactly?
|
||||
It came from `/===/sur/down/gate/hook`:
|
||||
|
||||
/? 314
|
||||
/- *markdown
|
||||
down
|
||||
|
||||
The `*` tells us that we are dealing not with a single gate, but
|
||||
a core containing multiple gates. `/===/sur/markdown/core/hook`:
|
||||
|
||||
|%
|
||||
++ down (list barb) :: markdown structure
|
||||
++ barb :: block elements
|
||||
$% [%had p=@ud q=(list shin) r=(unit tape)] :: depth, contents, id
|
||||
[%hem p=manx] :: html tag
|
||||
[%hot ~] :: horizontal rule
|
||||
[%lie p=down] :: list element
|
||||
[%lit p=? q=down] :: list
|
||||
[%par p=(list shin)] :: paragraph
|
||||
[%pre p=wall] :: preformatted text
|
||||
[%quo p=down] :: blockquote
|
||||
== ::
|
||||
++ shin :: span elements
|
||||
$% [%cod p=tape] :: inline code
|
||||
[%cut ~] :: break
|
||||
[%emp p=?(%bent %bold %both) q=(list shin)] :: emphasis
|
||||
[%ike p=(list shin)] :: strikethrough
|
||||
[%lin p=(list shin) q=tape r=(unit tape)] :: link
|
||||
[%tex p=tape] :: text
|
||||
== ::
|
||||
--
|
||||
|
||||
We see that markdown isn't a trivial single structure. With `*`
|
||||
in a hoof we do two things. One, we load a core not a gate.
|
||||
Two, we implicitly stick an
|
||||
|
||||
=+ markdown
|
||||
|
||||
on your reef, so that you can use `down` where otherwise you'd
|
||||
have to say `down:markdown`. `down/gate/hook` uses this to
|
||||
export the naked `down` gate into the structure space.
|
||||
|
||||
What actually happens to all the resources you load with `/-`?
|
||||
They go into a single core above the libraries, horns and hoops.
|
||||
Moreover, when libraries, horns and hoops contain `/-` runes of
|
||||
their own, indicating structure dependencies, *all* these
|
||||
dependencies are collected into the single structure core.
|
||||
|
||||
|
||||
# Hooves: global names and conflicts.
|
||||
|
||||
When we use a single symbol, like `down`, we indicate that we're
|
||||
looking for a structure in the same ship, desk, and case as our
|
||||
own. In other words, we're loading a local structure which is
|
||||
tightly coupled to the system loading it.
|
||||
|
||||
We can also use global structures. Here the syntax is
|
||||
|
||||
name/label/~ship
|
||||
|
||||
The desk in the global case is bound to `%main`, because it's
|
||||
assumed that if you're publishing your code to the world it
|
||||
belongs on your `%main`.
|
||||
|
||||
But this still becomes an arm named `structure` in your structure
|
||||
core. What happens if we depend in two places on two hooves,
|
||||
with the same name but different labels or ships?
|
||||
|
||||
For now, we are conservative - all hooves in a hood must match
|
||||
exactly. Eventually we'll parse conventional labels (for Kelvin
|
||||
and semantic versioning) and perform automagic upgrades.
|
||||
|
||||
|
||||
# Hooves: libraries.
|
||||
|
||||
Libraries are loaded much the same way as structures, except with
|
||||
`/+`. The syntax is the same, except that there is no equivalent
|
||||
of `*`. Library dependencies are also collected across the
|
||||
entire build, like structure dependencies.
|
||||
|
||||
Libraries are assumed to be cores, and they are stacked one after
|
||||
another in dependency order - if a depends on b, a obviously must
|
||||
come after b.
|
||||
|
||||
Let's try using a library. In
|
||||
|
||||
~/urb/lib/example/core.hook
|
||||
|
||||
put
|
||||
|
||||
|%
|
||||
++ fib |=(x=@ ~+(?:((lth x 2) 1 (add $(x (dec x)) $(x (sub x 2))))))
|
||||
--
|
||||
|
||||
Then, in
|
||||
|
||||
~/urb/pub/fab/mad/six/hymn.hook
|
||||
|
||||
we put:
|
||||
:: Our sixth experiment with major hood runes.
|
||||
::
|
||||
:::: /hoon/six/mad/fab/pub
|
||||
::
|
||||
/+ example
|
||||
/= gas /$ fuel
|
||||
::
|
||||
:::: ~tasfyn-partyv
|
||||
::
|
||||
=+ arg=(biff (~(get by qix.gas) %number) (slat %ud))
|
||||
;html
|
||||
;head
|
||||
;title: Mad Experiment Two
|
||||
==
|
||||
;body
|
||||
;+ ?~ arg
|
||||
;p: Usage: ?number=x
|
||||
;p ; This is an ;{i "HTML file"} which
|
||||
; computes the Fibonacci number
|
||||
; of {<u.arg>}: {<(fib u.arg)>}.
|
||||
==
|
||||
==
|
||||
==
|
||||
|
@ -1,10 +1,4 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-hoon
|
||||
categories: tut
|
||||
sort: 1
|
||||
title: I - Intro To Hoon
|
||||
---
|
||||
#Intro to Hoon
|
||||
|
||||
> Like all men in Babylon, I have been proconsul; like all, a slave.
|
||||
> - The Lottery in Babylon
|
||||
|
@ -1,10 +1,4 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-hoon
|
||||
categories: tut
|
||||
sort: 2
|
||||
title: II - Moar Hoon Types
|
||||
---
|
||||
#Types
|
||||
|
||||
> What good is a phone call if you're unable to speak?
|
||||
> - The Matrix
|
||||
|
@ -1,10 +1,4 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-hoon
|
||||
categories: tut
|
||||
sort: 3
|
||||
title: III - Hoon Computes
|
||||
---
|
||||
#Hoon Computes
|
||||
|
||||
> I've only been in love with a beer bottle and a mirror.
|
||||
> - Sid Vicious
|
||||
|
@ -1,10 +1,4 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-hoon
|
||||
categories: tut
|
||||
sort: 4
|
||||
title: IV - Gates
|
||||
---
|
||||
#Gates
|
||||
|
||||
> Anyone who thinks he's original is merely ignorant.
|
||||
> - Nicolás Gómez Dávila
|
||||
|
@ -1,10 +1,4 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-hoon
|
||||
categories: tut
|
||||
sort: 5
|
||||
title: V - Tiles
|
||||
---
|
||||
#Tiles
|
||||
|
||||
> Not to get knowledge, but to save yourself from having
|
||||
> ignorance foisted upon you.
|
||||
|
@ -1,10 +1,4 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-hoon
|
||||
categories: tut
|
||||
sort: 6
|
||||
title: VI - Type Inference
|
||||
---
|
||||
#Type Inference
|
||||
|
||||
> Ever, as before, does Madness remain a mysterious-terrific,
|
||||
> altogether infernal boiling-up of the Nether Chaotic Deep,
|
||||
@ -961,4 +955,4 @@ perfectly capable of inferring that when you weld `(list a)` and
|
||||
change might confuse.
|
||||
|
||||
In short: generic polymorphism is cool but wacky. Leave it to
|
||||
the experts, please!
|
||||
the experts, please!
|
||||
|
@ -1,10 +1,5 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-hoon
|
||||
categories: tut
|
||||
sort: 7
|
||||
title: VII - Odds, Ends, Quirks
|
||||
---
|
||||
#Odds, Ends, Quirks
|
||||
|
||||
|
||||
##A bestiary of cores##
|
||||
|
||||
@ -1214,4 +1209,4 @@ In freehand mode (F-Hoon), do whatever the heck you want. Note
|
||||
that while uppercase is not permitted in a symbol, `-` is,
|
||||
suggesting a generally Lisp-like state of gross hyphenated
|
||||
disorder. F-mode is best used for top-layer software which
|
||||
nothing else is based on; prototyping and casual coding; etc.
|
||||
nothing else is based on; prototyping and casual coding; etc.
|
||||
|
29
main/pub/src/doc/say/intro.md
Normal file
29
main/pub/src/doc/say/intro.md
Normal file
@ -0,0 +1,29 @@
|
||||
#Urbit
|
||||
|
||||
We got tired of system software from the 1970s. So we wrote our own. From scratch.
|
||||
|
||||
##Nock, a minimal virtual machine
|
||||
|
||||
[Nock](https://github.com/urbit/urbit/blob/master/urb/zod/spec/nock/5.txt) is a
|
||||
homoiconic combinator algebra, not much fancier than SKI combinators. The spec
|
||||
fits on a T-shirt and gzips to 340 bytes. We never extend Nock or call out to Unix from it.
|
||||
|
||||
##Hoon, a typed functional language
|
||||
|
||||
Hoon is a strict, typed, functional language that compiles itself to Nock.
|
||||
As a functional systems language, Hoon is especially good at metaprogramming,
|
||||
self-virtualization, hotpatching; marshalling and validating untyped data;
|
||||
decoding and encoding binary message formats. Hoon is designed for event
|
||||
programming, so there is no concurrency model.
|
||||
|
||||
##Arvo, a functional operating system
|
||||
|
||||
Arvo is an event-driven server OS built on the same event library as node.js
|
||||
(libuv). Unlike node.js, Arvo is written in Hoon, isolated from Unix and a
|
||||
persistent single-level store. Arvo is modular. Present modules provide a
|
||||
network messaging protocol, a REPL and task manager, a revision-controlled
|
||||
filesystem, a text console, and an HTTP server.
|
||||
|
||||
|
||||
|
||||
|
@ -1,10 +1,4 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-nock
|
||||
categories: tut
|
||||
sort: 1
|
||||
title: I - Intro To Nock
|
||||
---
|
||||
#Intro to Nock
|
||||
|
||||
> What one fool can do, another can.
|
||||
> - Ancient Simian proverb
|
||||
|
@ -1,10 +1,4 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-nock
|
||||
categories: tut
|
||||
sort: 2
|
||||
title: II - Nock Is Easy
|
||||
---
|
||||
#Nock is Easy
|
||||
|
||||
> You get used to it. I don't even see the code. All I see is blonde, brunette, redhead.
|
||||
> - The Matrix
|
||||
|
@ -1,10 +1,5 @@
|
||||
---
|
||||
layout: tutpage
|
||||
axis: doc-nock
|
||||
categories: tut
|
||||
sort: 3
|
||||
title: III - Using Nock
|
||||
---
|
||||
#Using Nock
|
||||
|
||||
> But are you crazy enough?
|
||||
> - Point Break
|
||||
|
||||
|
463
main/pub/src/doc/say/setup.md
Normal file
463
main/pub/src/doc/say/setup.md
Normal file
@ -0,0 +1,463 @@
|
||||
#Setup
|
||||
|
||||
> Tlön is surely a labyrinth, but it is a labyrinth devised
|
||||
> by men, a labyrinth destined to be deciphered by men.
|
||||
> - Tlön, Uqbar, Orbis Tertius
|
||||
|
||||
Urbit runs on Unix machines only. It depends on:
|
||||
|
||||
+ gmp
|
||||
+ libsigsegv
|
||||
+ openssl
|
||||
+ libssl-dev (Linux only)
|
||||
+ ncurses (Linux only)
|
||||
|
||||
Currently we support OSX, Linux (not all distributions have been
|
||||
tested) and \*BSD. There are no instructions for BSD, because
|
||||
only people with a serious clue run BSD. Intrepid ninjas may
|
||||
attempt ports to other OSes. If you're not an intrepid ninja,
|
||||
try a VM (eg, VirtualBox) or use one of our AMIs.
|
||||
|
||||
###Amazon AMIs
|
||||
|
||||
There are public AMIs at the following locations:
|
||||
|
||||
us-west (oregon) ami-6cf88d5c
|
||||
us-west (n. california) ami-78d4ec3d
|
||||
us-east (n. virginia) ami-cd819ba4
|
||||
|
||||
These use Debian Wheezy, so you should be able to
|
||||
|
||||
ssh -i /path/to/your/key/file.pem admin@123.123.123.123
|
||||
|
||||
to get in.
|
||||
|
||||
Since the codebase is changing frequently, run the following once you have ssh-ed in.
|
||||
|
||||
cd /urbit/
|
||||
git pull origin master
|
||||
make clean; make;
|
||||
|
||||
Then jump to "Run" below to get rolling.
|
||||
|
||||
|
||||
###Docker
|
||||
|
||||
[Docker](http://docker.io) is a very convenient way to get in to an Urbit ship quickly. `~simmev-rabryd` maintains the docker approach on GitHub [here](https://github.com/yebyen/urbinit).
|
||||
|
||||
Follow the instructions on the GitHub page, then proceed to "Run" below.
|
||||
|
||||
|
||||
###OS X###
|
||||
|
||||
1. Do you have XCode? Type `gcc`. If it says `no input files`, you have XCode.
|
||||
|
||||
Otherwise, install XCode: `https://developer.apple.com/xcode/`, with the
|
||||
command line tools.
|
||||
|
||||
2. Install dependencies. Pick either one of Homebrew or Macports, but not both.
|
||||
|
||||
- Homebrew? Type `brew`. If it does something, you have Homebrew.
|
||||
|
||||
Otherwise, `ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"`
|
||||
will install it.
|
||||
|
||||
And follow up with `brew install git gmp libsigsegv openssl`
|
||||
|
||||
This will ask you for the root password, which ideally you know.
|
||||
|
||||
- Macports? Type `port`. If it does something, you have Macports.
|
||||
|
||||
Otherwise go [here](http://www.macports.org/install.php "here").
|
||||
|
||||
Then `sudo port install git gmp libsigsegv openssl`
|
||||
|
||||
Enter your root password at the prompt.
|
||||
|
||||
|
||||
###Linux (Ubuntu or Debian)###
|
||||
|
||||
1. `sudo apt-get install libgmp3-dev libsigsegv-dev openssl libssl-dev libncurses5-dev git make exuberant-ctags`
|
||||
|
||||
|
||||
###Linux (AWS)###
|
||||
|
||||
1. `sudo yum --enablerepo epel install gcc git gmp-devel openssl-devel ncurses-devel libsigsegv-devel ctags`
|
||||
|
||||
###Get the source###
|
||||
|
||||
Urbit uses git for its revision control. Eventually, Urbit will use itself, but for now,
|
||||
you need git. If you've followed the above instructions correctly then typing `git` in your terminal should do something.
|
||||
|
||||
If that works, run:
|
||||
|
||||
git clone https://github.com/urbit/urbit.git
|
||||
|
||||
to download Urbit from its repository.
|
||||
|
||||
If for some reason you have moral qualms about using Git, you can also just download and unzip `https://github.com/urbit/urbit/archive/master.zip`. This won't provide any version control
|
||||
|
||||
###Set up your enviroment###
|
||||
|
||||
`cd` to the unpacked Urbit directory you just created:
|
||||
|
||||
cd urbit
|
||||
|
||||
If this works, `ls urb` should show:
|
||||
|
||||
urbit.pill zod/
|
||||
|
||||
Great! Now, let's do some dirty Unix stuff to set up your environment.
|
||||
If you know what this is doing, feel free to do it right. Otherwise:
|
||||
|
||||
echo "export URBIT_HOME=`pwd`/urb" >>~/.bash_profile
|
||||
source ~/.bash_profile
|
||||
|
||||
To make sure this worked,
|
||||
|
||||
echo $URBIT_HOME
|
||||
|
||||
should show `/urb` within the current directory.
|
||||
|
||||
If this didn't work, you'll have to do this the hard way. run `vi ~/.bash_profile` and fix it.
|
||||
|
||||
###Build###
|
||||
|
||||
`make`. Sometimes things are just easy.
|
||||
|
||||
<h3 id="run">Run</h3>
|
||||
|
||||
Run `bin/vere -c mypier`, where `mypier` is a directory that doesn't yet exist.
|
||||
All your state (an append-only log and a memory checkpoint) will live in this
|
||||
directory. Its name doesn't matter and is not visible internally.
|
||||
|
||||
A _pier_ is an Urbit virtual machine that hosts one or more Urbit identities,
|
||||
or _ships_. When you run `vere -c`, it automatically creates a 128-bit ship,
|
||||
or `submarine`. Your name (a hash of a randomly-generated public key) will
|
||||
look like:
|
||||
|
||||
~machec-binnev-dordeb-sogduc--dosmul-sarrum-faplec-nidted
|
||||
|
||||
First you'll see a string of messages like:
|
||||
|
||||
vere: urbit home is /Users/cyarvin/Documents/src/u3/urb
|
||||
loom: mapped 1024MB
|
||||
time: ~2013.9.1..03.57.11..4935
|
||||
ames: on localhost, UDP 63908.
|
||||
generating 2048-bit RSA pair...
|
||||
|
||||
and then it'll pause a little, 'cause this is slow, and then
|
||||
|
||||
saving passcode in /Users/cyarvin/.urbit/~magsut-hopful.txt
|
||||
(for real security, write it down and delete the file...)
|
||||
|
||||
and, then, if the network gods are happy, your submarine will start pulling
|
||||
down Arvo files:
|
||||
|
||||
+ /~machec-binnev-dordeb-sogduc--dosmul-sarrum-faplec-nidted/main/1/bin/ticket/hoon
|
||||
+ /~machec-binnev-dordeb-sogduc--dosmul-sarrum-faplec-nidted/main/1/bin/reset/hoon
|
||||
+ /~machec-binnev-dordeb-sogduc--dosmul-sarrum-faplec-nidted/main/1/bin/ye/hoon
|
||||
+ /~machec-binnev-dordeb-sogduc--dosmul-sarrum-faplec-nidted/main/1/bin/ls/hoon
|
||||
|
||||
and the like. You'll see a couple pages of this stuff. Don't worry too much
|
||||
about the details right now. Finally, you'll get the Arvo shell prompt (which
|
||||
is also a Hoon REPL):
|
||||
|
||||
~machec-binnev-dordeb-sogduc--dosmul-sarrum-faplec-nidted/try=>
|
||||
|
||||
###Register###
|
||||
|
||||
Next, you need to decide whether a mere submarine is enough for
|
||||
you right now. This monicker is a mouthful. You can stick with
|
||||
it (for now), but you're going to need a wider xterm.
|
||||
|
||||
Which might be fine! However, please note that just by sending a
|
||||
simple email, you can get a much better ship - a `destroyer`,
|
||||
with a nice short name like
|
||||
|
||||
~waclux-tomwyc
|
||||
|
||||
Just email `urbit@urbit.org`, with your submarine in the subject.
|
||||
We'll send you destroyers - not one, but _two_. Yes, two! Tell
|
||||
us something cool in the body, and we'll send you even more.
|
||||
|
||||
If you have a destroyer, you need to configure it. Otherwise,
|
||||
just stretch that xterm wide and skip to section 1.2.
|
||||
|
||||
Your destroyers will arrive in the form of `[ship ticket]` pairs.
|
||||
Let's say one of your ships is `~waclux-tomwyc` and its ticket is
|
||||
|
||||
~ribdyr-famtem-larrun-figtyd
|
||||
|
||||
(What are these strings, anyway? Just random unsigned integers,
|
||||
rendered in Hoon's syllabic base, `@p`.)
|
||||
|
||||
A new life awaits you on the off-world colonies! To begin, just
|
||||
type at the prompt:
|
||||
|
||||
:begin ~waclux-tomwyc
|
||||
|
||||
and follow the directions. When the script completes, hit return
|
||||
and you'll be the `~waclux-tomwyc` you wanted to be.
|
||||
|
||||
##Play with Arvo##
|
||||
|
||||
If all went well, you now have a nice short prompt:
|
||||
|
||||
~waclux-tomwyc/try=>
|
||||
|
||||
If all did not go well (send us another email), or you're just
|
||||
too impatient to wait for your destroyer, you have a big long
|
||||
prompt. Which is fine, really, just ugly - and all these
|
||||
exercises will still work.
|
||||
|
||||
###Example commands###
|
||||
|
||||
Let's try a few quick things to stretch your fingers. Type these
|
||||
command lines and you should see the matching results:
|
||||
|
||||
~waclux-tomwyc/try=> "hello, world"
|
||||
"hello, world"
|
||||
|
||||
~waclux-tomwyc/try=> (add 2 2)
|
||||
4
|
||||
|
||||
~waclux-tomwyc/try=> :hello %world
|
||||
"hello, world."
|
||||
|
||||
~waclux-tomwyc/try=> :cat /=main=/bin/hello/hoon
|
||||
::
|
||||
:: /=main=/bin/hello/hoon
|
||||
::
|
||||
|= *
|
||||
|= [planet=@ta ~]
|
||||
^- bowl
|
||||
:_ ~ :_ ~
|
||||
:- %%
|
||||
!>("hello, {(trip planet)}.")
|
||||
|
||||
What did you just do?
|
||||
|
||||
One, you used Arvo as a Hoon REPL to print the constant `"hello,
|
||||
world"`, which is a fancy way to write the Nock noun
|
||||
|
||||
[104 101 108 108 111 44 32 119 111 114 108 100 0]
|
||||
|
||||
Two, you called the Hoon `add` function to see that two plus two
|
||||
is four. Math seems to work the same on the off-world colonies.
|
||||
|
||||
Three, you ran the Arvo application `:hello` with the argument
|
||||
`%world`, which is just a fancy way to write the atom
|
||||
`431.316.168.567` (or, for non-Germans, `431,316,168,567`). You
|
||||
might recognize it better as `0x64.6c72.6f77` - the ASCII
|
||||
characters in LSB first order.
|
||||
|
||||
(Is Urbit German? Sadly, no. But all our noun print formats are
|
||||
URL-safe, which dot is and comma isn't.)
|
||||
|
||||
And you (4) used the Arvo application :cat to print the Hoon file
|
||||
|
||||
/=main=/bin/hello/hoon
|
||||
|
||||
which, supposing your current date is
|
||||
|
||||
~2013.9.1..04.38.31..f259
|
||||
|
||||
(ie, September 1, 2013 at 4:38:31 GMT/LS25 plus 0xf259/65536
|
||||
seconds), is equivalent to the global path
|
||||
|
||||
/~waclux-tomwyc/main/~2013.8.23..04.38.31..f259/bin/hello/hoon
|
||||
|
||||
which anyone in Urbit can, see and even use - but we're getting
|
||||
ahead of ourselves.
|
||||
|
||||
###Control characters###
|
||||
|
||||
In any case, what we've seen is that Arvo is a dangerous and
|
||||
powerful operating system which if handled improperly can cause
|
||||
serious injury or loss of life. We exaggerate. Slightly.
|
||||
|
||||
The first thing you need to know is how to control this tool.
|
||||
Try your arrow keys - you'll see that Arvo has traditional Unix
|
||||
history editing. Up and down, left and right work, as do the
|
||||
simple emacs controls:
|
||||
|
||||
^A go to beginning of line
|
||||
^B left arrow
|
||||
^D delete next character
|
||||
^E go to end of line
|
||||
^F right arrow
|
||||
^K kill to end of line
|
||||
^L clear the screen
|
||||
^R search through history
|
||||
^U kill the whole line
|
||||
^Y yank (restore from kill ring)
|
||||
|
||||
Don't expect any other emacs (or even readline - this is not readline, it's
|
||||
internal to Arvo) commands to work.
|
||||
|
||||
There are also some special control keys specific to Arvo. It's
|
||||
a good idea to learn these first so that you feel in, um,
|
||||
control.
|
||||
|
||||
First, we'll quit out of an infinite loop with `^C`:
|
||||
|
||||
~waclux-tomwyc/try=> :infinite
|
||||
|
||||
When you hit return at the end of this line, Arvo will appear to
|
||||
hang. Do not be alarmed! This is not a bug - it means that
|
||||
we've started running our infinite loop before printing the next
|
||||
console prompt. Simply hit `^C`, and you'll see
|
||||
|
||||
! intr
|
||||
~waclux-tomwyc/try=> :infinite
|
||||
|
||||
(There may be some stacktrace stuff before the `! intr`, depending
|
||||
on whether your kernel was compiled with debugging.)
|
||||
|
||||
Hit `^U` to delete the line and escape from infinity. Arvo is a
|
||||
deterministic OS; you interrupted it while processing an event
|
||||
that would never terminate. It returns to the state it was in
|
||||
before you hit return - as if nothing had ever happened.
|
||||
|
||||
You're probably used to using nondeterministic, preemptive OSes,
|
||||
in which the difference between a waiting task and an
|
||||
executing event isn't apparent to the user. Since Arvo is not
|
||||
preemptive, it has two very different states: waiting and
|
||||
working.
|
||||
|
||||
When Arvo is working, `^C` cancels the event it's working on.
|
||||
This event never happened. Don't worry, nothing bad will happen
|
||||
to your computer.
|
||||
|
||||
When Arvo is waiting, use `^D` to end the current task, which is
|
||||
the task that's currently prompting you. If there is a live
|
||||
prompt and the cursor is not at the end, `^D` will delete the
|
||||
current character - as in Unix.
|
||||
|
||||
Try this by running
|
||||
|
||||
~waclux-tomwyc/try=> :begin
|
||||
|
||||
Do you have a ship and a ticket? yes
|
||||
|
||||
Then hit `^D` and you'll be back to the command prompt (which,
|
||||
unlike in Unix, is not a task itself, but part of the OS).
|
||||
|
||||
We don't always want to kill the prompting task. We often want
|
||||
to switch between tasks, or between tasks and the command line.
|
||||
Sort of like switching between windows, except in a command line.
|
||||
We do this with `^X`. Try
|
||||
|
||||
~waclux-tomwyc/try=> :begin
|
||||
|
||||
Do you have a ship and a ticket? yes
|
||||
|
||||
But hit `^X` instead of `^D`. You'll get a prompt again. Use
|
||||
it:
|
||||
|
||||
~waclux-tomwyc/try=> :begin
|
||||
|
||||
~waclux-tomwyc/try=> :hello %world
|
||||
"hello, world."
|
||||
~waclux-tomwyc/try=>
|
||||
|
||||
Hit `^X` again:
|
||||
|
||||
~waclux-tomwyc/try=> :begin
|
||||
|
||||
~waclux-tomwyc/try=> :hello %world
|
||||
"hello, world."
|
||||
Do you have a ship and a ticket? yes
|
||||
|
||||
And finally, hit `^C` to kill the task.
|
||||
|
||||
Lastly, Arvo is a single-level store. Since it's not the '70s
|
||||
anymore and disk is cheap, everything you do is saved for ever.
|
||||
(In fact, it's saved in two ways - as a memory image and an event
|
||||
log - so you, or the government if they haz your filez, can
|
||||
repeat every computation you've ever performed.)
|
||||
|
||||
If the current prompt is just the shell prompt, `^D` on an empty
|
||||
line will log out - as in Unix:
|
||||
|
||||
~waclux-tomwyc/try=>
|
||||
oxford:~/urbit; pwd
|
||||
/Users/cyarvin/urbit
|
||||
oxford:~/urbit; echo "hello, world"
|
||||
hello, world
|
||||
oxford:~/urbit;
|
||||
|
||||
Then you can restart and be right back where you were - just
|
||||
run `vere` without `-c`:
|
||||
|
||||
oxford:~/urbit; bin/vere mypier
|
||||
vere: urbit home is /Users/cyarvin/urb
|
||||
loom: loaded 9MB
|
||||
time: ~2013.9.1..17.23.05..0cc1
|
||||
ames: on localhost, UDP 60342.
|
||||
http: live on 8080
|
||||
rest: checkpoint to event 383
|
||||
rest: old 0v1c.gkr1o, new 0v10.m4gdu
|
||||
---------------- playback complete----------------
|
||||
waclux-tomwyc/try=>
|
||||
|
||||
Use your arrow keys and you'll see your history is still there.
|
||||
Arvo is indestructible and can be shut down however you like
|
||||
without losing data. Also, starting a new task while an old
|
||||
one is still running will kill the old one safely.
|
||||
|
||||
But don't try to operate the same ship on two Unix hosts at the
|
||||
same time. This will confuse everyone, including yourself.
|
||||
|
||||
###System administration###
|
||||
|
||||
Sometimes we make changes to Hoon or Arvo (we never make changes
|
||||
to Nock) and you need to update your ship.
|
||||
|
||||
There are two steps to updating. You need to get the new files,
|
||||
and you need to install them. To get them:
|
||||
|
||||
~waclux-tomwyc/try=> :update
|
||||
: /~waclux-tomwyc/arvo/2/hoon/hoon
|
||||
: /~waclux-tomwyc/arvo/2/dill/hoon
|
||||
: /~waclux-tomwyc/arvo/2/batz/hoon
|
||||
|
||||
To install them (the simplest, slowest, most general way):
|
||||
|
||||
~waclux-tomwyc/try=> :reset
|
||||
|
||||
%reset-start
|
||||
%reset-parsed
|
||||
%reset-compiled
|
||||
%hoon-load
|
||||
[%tang /~waclux-tomwyc/arvo/~2013.11.26..20.29.15..090f/zuse ~tirnux-latwex]
|
||||
[%vane %a /~waclux-tomwyc/arvo/~2013.11.26..20.29.15..090f/ames ~tolryn-watret]
|
||||
[%vane %b /~waclux-tomwyc/arvo/~2013.11.26..20.29.15..090f/batz ~donfex-ladsem]
|
||||
[%vane %c /~waclux-tomwyc/arvo/~2013.11.26..20.29.15..090f/clay ~picsug-mitref]
|
||||
[%vane %d /~waclux-tomwyc/arvo/~2013.11.26..20.29.15..090f/dill ~dilpex-laptug]
|
||||
[%vane %e /~waclux-tomwyc/arvo/~2013.11.26..20.29.15..090f/eyre ~forbur-disben]
|
||||
|
||||
All of your state, including running tasks, will be unchanged.
|
||||
|
||||
Sometimes the interpreter, called `vere` gets updated. In your urbit directory, back in Unixland, run:
|
||||
|
||||
git pull origin master
|
||||
|
||||
every so often to get the latest Urbit source code.
|
||||
|
||||
###Chat###
|
||||
|
||||
Okay, fine. You're a long way from being an Arvo ninja. But -
|
||||
you're ready for the two most important uses of Urbit right now.
|
||||
One, coding. Two, chatting.
|
||||
|
||||
To start coding, read the next chapter. To start chatting,
|
||||
simply type
|
||||
|
||||
~waclux-tomwyc/try=> :chat
|
||||
&
|
||||
|
||||
and type `?` for help.
|
||||
|
||||
[On to the documentation.](/doc/)
|
@ -1,15 +0,0 @@
|
||||
<div class="footer">
|
||||
<div class="container">
|
||||
<ul class="sidebar-nav">
|
||||
<li class="sidebar-nav-item">
|
||||
<a href="mailto:urbit@urbit.org">urbit@urbit.org</a>
|
||||
</li>
|
||||
<li class="sidebar-nav-item">
|
||||
<a href="/community/articles/martian-computing/">544 Kelvin</a>
|
||||
</li>
|
||||
<li class="sidebar-nav-item">
|
||||
<a href="/community/articles/continuity/">Continuity breach: ~2014.5.30</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
@ -1,39 +0,0 @@
|
||||
<head>
|
||||
<link href="http://gmpg.org/xfn/11" rel="profile">
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
|
||||
<!-- Enable responsiveness on mobile devices-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
|
||||
|
||||
<title>
|
||||
{% if page.title == "Home" %}
|
||||
{{ site.title }} · {{ site.tagline }}
|
||||
{% else %}
|
||||
{{ page.title }} · {{ site.title }}
|
||||
{% endif %}
|
||||
</title>
|
||||
|
||||
<!-- CSS -->
|
||||
<link rel="stylesheet" href="/public/css/poole.css">
|
||||
<link rel="stylesheet" href="/public/css/syntax.css">
|
||||
<link rel="stylesheet" href="/public/css/main.css">
|
||||
|
||||
<!-- JS -->
|
||||
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="/public/js/main.js"></script>
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-47054188-1', 'urbit.org');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
|
||||
<!-- Icons -->
|
||||
|
||||
<link rel="shortcut icon" href="/favicon.png">
|
||||
|
||||
<!-- RSS -->
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS" href="/atom.xml">
|
||||
</head>
|
Binary file not shown.
Before Width: | Height: | Size: 1.0 KiB |
@ -1,21 +0,0 @@
|
||||
<div class="sidebar">
|
||||
<div class="container sidebar-sticky">
|
||||
<div class="sidebar-about">
|
||||
<a href="/">
|
||||
<h1 class="logo"><img src="/gen/main/pub/src/site/res/logo.png" class="logo"/></h1>
|
||||
<h1 class="title">Urbit: a personal cloud computer</h1>
|
||||
</a>
|
||||
</div>
|
||||
<ul class="sidebar-nav">
|
||||
<li class="sidebar-nav-item">
|
||||
<a href="/gen/main/pub/fab/site/documentation/" class="">Documentation</a>
|
||||
</li>
|
||||
<li class="sidebar-nav-item">
|
||||
<a href="/community/" class="">Community</a>
|
||||
</li>
|
||||
<li class="sidebar-nav-item">
|
||||
<a href="/setup/" class="">Setup</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user