Removed old references to setting up fora, streams, collection, web folder, landscape, and plan

This commit is contained in:
Logan Allen 2019-07-05 15:05:09 -07:00
parent 897c0349b1
commit f43a5e1b5d
59 changed files with 0 additions and 11113 deletions

View File

@ -1,610 +0,0 @@
::
:::: /app/collections/hoon
::
/? 309
/- hall
/+ collections
::
:: cols:
::
:: run collections-item renderer on children of /web/collections
:: combine with a bunted config in a +collection structure defined in
:: /lib/collections because the top level collection has no config file
::
:: whenever any of the clay files that compose this renderer change, this app
:: will recompile and the +prep arm will fire. we then check which files
:: changed and notify the corresponding hall circle of that change
::
/= cols
/^ collection:collections
/; |= a=(map knot item:collections)
[*config:collections a]
/: /===/web/collections /_ /collections-item/
::
=, collections
=, space:userlib
::
:: state:
::
:: stores the collection built by above by :cols so that we can compare old
:: and new versions whenever the rendered data changes
::
~% %landscape ..^is ~
|_ [bol=bowl:gall sta=state]
::
:: +this: app core subject
::
++ this .
::
:: +prep:
::
:: on initial boot, create top level hall circle for collections, called %c
::
:: on subsequent compiles, call +ta-update:ta on the old collection data,
:: then update state to store the new collection data
::
++ prep
~/ %land-prep
|= old=(unit state)
^- (quip move _this)
?~ old
:_ this
;: welp
=< ta-done
(~(ta-hall-create-circle ta ~ bol) /c 'collections')
::
:~ [ost.bol %peer /circles [our.bol %hall] /circles/[(scot %p our.bol)]]
[ost.bol %peer /inbox [our.bol %hall] /circle/inbox/config/grams]
[ost.bol %peer /invites [our.bol %hall] /circle/i/grams]
::
:: ?. =(%duke (clan:title our.bol))
:: ~
:: :_ ~
:: :* ost.bol %poke /client-action [our.bol %hall]
:: %hall-action %source %inbox &
:: (sy [[(^sein:title our.bol) %urbit-meta] ~]~)
:: ==
==
==
?- -.u.old
%0
=/ mow=(list move)
=< ta-done
(~(ta-update ta ~ bol) col.u.old cols)
:- mow
%= this
sta [%0 cols str.u.old]
==
==
::
:: +mack:
::
:: recieve acknowledgement for permissions changes, print error if it failed
::
++ mack
|= [wir=wire err=(unit tang)]
^- (quip move _this)
?~ err
[~ this]
(mean u.err)
::
:: +coup: recieve acknowledgement for poke, print error if it failed
::
++ coup
|= [wir=wire err=(unit tang)]
^- (quip move _this)
?~ err
[~ this]
(mean u.err)
::
:: +poke-collections-action:
::
:: the main interface for creating and deleting collections and items
::
++ poke-collections-action
~/ %coll-poke-collections-action
|= act=action
^- (quip move _this)
?: =(who.act our.bol)
:_ this
=< ta-done
(~(ta-act ta ~ bol) act)
:: forward poke if its not meant for us
::
:_ this
:_ ~
:* ost.bol %poke
/forward-collections-action
[who.act %collections]
%collections-action act
==
::
:: +poke-json
::
:: utility for setting whether or not to display the onboarding page
::
++ poke-json
~/ %coll-poke-json
|= jon=json
^- (quip move _this)
?: ?=([%o [[%onboard %b ?] ~ ~]] jon)
:_ this
=< ta-done
(~(ta-write ta ~ bol) /web/landscape/onboard/json [%json !>(jon)])
[~ this]
::
:: +poke-collections-command
::
++ poke-collections-command
|= cod=command
^- (quip move _this)
?- -.cod
%chat-invite
:_ this
:- :* ost.bol
%poke
/permit
[our.bol %hall]
%hall-action
%permit
nom.cod
%.y
who.cod
==
%+ turn ~(tap in who.cod)
|= guy=@p
^- move
:* ost.bol
%poke
/invite
[our.bol %hall]
%hall-action
%phrase
aud=(sy [guy %i] ~)
ses=[%inv & our.bol nom.cod]~
==
::
%collection-invite
:_ this
:- :* ost.bol
%poke
/permit
[our.bol %hall]
%hall-action
%permit
nom.cod
%.y
who.cod
==
%+ turn ~(tap in who.cod)
|= guy=@p
^- move
:* ost.bol
%poke
/invite
[our.bol %hall]
%hall-action
%phrase
aud=(sy [guy %i] ~)
ses=[%app col.cod [%inv & our.bol nom.cod]]~
==
==
::
:: +peer:
::
++ peer
|= wir=wire
^- (quip move _this)
=/ response=streams
?+ wir
%= str.sta
env.inbox (scag 1.000 env.inbox.str.sta)
==
:: negative range from latest
::
[%primary @t ~]
=/ val=@ (slav %ud i.t.wir)
%= str.sta
env.inbox (scag val env.inbox.str.sta)
==
:: negative range from offset
::
[%primary @t @t ~]
=/ offset=@ (slav %ud i.t.wir)
=/ num=@ (slav %ud i.t.t.wir)
%= str.sta
env.inbox (swag [offset num] env.inbox.str.sta)
==
::
==
:_ this
[ost.bol %diff %collections-prize response]~
::
:: +reap: recieve acknowledgement for peer, retry on failure
::
++ reap
|= [wir=wire err=(unit tang)]
^- (quip move _this)
::~& reap+[wir =(~ err)]
?~ err
:: XX send message to users inbox
[~ this]
?~ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
?+ i.wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
%circles
:_ this
[ost.bol %peer /circles [our.bol %hall] /circles/[(scot %p our.bol)]]~
::
%inbox
:_ this
[ost.bol %peer /inbox [our.bol %hall] /circle/inbox/config/grams]~
::
%invites
:_ this
[ost.bol %peer /invites [our.bol %hall] /circle/i/grams]~
::
%our
?< ?=(~ t.wir)
:_ this
[ost.bol %peer /our/[i.t.wir] [our.bol %hall] /circle/[i.t.wir]/config]~
==
::
:: +quit:
::
++ quit
|= wir=wire
^- (quip move _this)
?~ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
?+ i.wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
%circles
:_ this
[ost.bol %peer /circles [our.bol %hall] /circles/[(scot %p our.bol)]]~
::
%inbox
:_ this
[ost.bol %peer /inbox [our.bol %hall] /circle/inbox/config/grams]~
::
%invites
:_ this
[ost.bol %peer /invites [our.bol %hall] /circle/i/grams]~
::
%our
?< ?=(~ t.wir)
:_ this
[ost.bol %peer /our/[i.t.wir] [our.bol %hall] /circle/[i.t.wir]/config]~
==
::
:: +diff-hall-prize:
::
++ diff-hall-prize
|= [wir=wire piz=prize:hall]
^- (quip move _this)
::
::
::~& prize+[wir piz]
?~ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
?+ i.wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
:: %circles: subscribe to the configuration of each of our circles
::
%circles
?> ?=(%circles -.piz)
=/ noms=(set name:hall) (~(dif in cis.piz) (sy ~[%inbox %i %public]))
:_ this(our-circles.str.sta (~(uni in our-circles.str.sta) noms))
^- (list move)
%+ turn ~(tap in noms)
|= nom=name:hall
^- move
[ost.bol %peer /our/[nom] [our.bol %hall] /circle/[nom]/config]
::
:: %inbox: fill inbox config, messages and remote configs with prize data
::
%inbox
?> ?=(%circle -.piz)
:- ~
%= this
con.inbox.str.sta `loc.cos.piz
::
env.inbox.str.sta nes.piz
::
circles.str.sta
%- ~(uni in circles.str.sta)
^- (map circle:hall (unit config:hall))
(~(run by rem.cos.piz) |=(a=config:hall `a))
==
::
:: %invites: fill invite messages with prize data
::
%invites
?> ?=(%circle -.piz)
:- ~
%= this
invites.str.sta nes.piz
==
::
:: %our:
::
%our
?> ?=(%circle -.piz)
=/ nom=name:hall &2:wir
:: XX todo: send rumor or let config-change handle it?
::
:- ~
%= this
circles.str.sta
(~(put by circles.str.sta) [our.bol nom] `loc.cos.piz)
::
our-circles.str.sta (~(put in our-circles.str.sta) nom)
==
==
::
:: +diff-hall-rumor
::
++ diff-hall-rumor
|= [wir=wire rum=rumor:hall]
^- (quip move _this)
::~& rumor+[wir rum]
?~ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
=; upd=[mow=(list move) sta=_this]
:_ sta.upd
%+ welp mow.upd
%+ turn (prey:pubsub:userlib /primary bol)
|= [=bone *]
[bone %diff %hall-rumor rum]
?+ i.wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
:: %circles:
::
%circles
::~& %circles
?> ?=(%circles -.rum)
=? dms.str.sta
?& (is-dm-circle our.bol cir.rum)
!(~(has by dms.str.sta) cir.rum)
==
(~(put by dms.str.sta) cir.rum our.bol ~)
?: add.rum
:_ this(our-circles.str.sta (~(put in our-circles.str.sta) cir.rum))
[ost.bol %peer /our/[cir.rum] [our.bol %hall] /circle/[cir.rum]/config]~
:_ this(our-circles.str.sta (~(del in our-circles.str.sta) cir.rum))
[ost.bol %pull /our/[cir.rum] [our.bol %hall] ~]~
::
:: %inbox:
::
%inbox
?> ?=(%circle -.rum)
?+ -.rum.rum
::~& inbox-unprocessed-rumor+rum.rum
[~ this]
::
:: %remove:
::
%remove
::~& %inbox-remove
::~& %removed-story
[~ this]
::
:: %gram: inbox has recieved messages
::
%gram
::~& %inbox-gram
:: XX TODO: handle stack trace message when foreign circle is killed?
::
?: (is-dm-circle src.rum.rum)
=/ dms=[ini=ship env=(list envelope:hall)]
(~(got by dms.str.sta) nom.src.rum.rum)
=. env.dms [nev.rum.rum env.dms]
:- ~
%= this
env.inbox.str.sta [nev.rum.rum env.inbox.str.sta]
dms.str.sta (~(put by dms.str.sta) nom.src.rum.rum dms)
==
:- ~ ::(send-rumor [%new-msg %inbox nev.rum.rum])
this(env.inbox.str.sta [nev.rum.rum env.inbox.str.sta])
::
:: %config: inbox config has changed
::
%config
=* circ cir.rum.rum
?+ -.dif.rum.rum
::~& inbox-unprocessed-config+dif.rum.rum
[~ this]
::
:: %remove: circle has been erased
::
%remove
::~& %inbox-config-remove
:- ~ ::(send-rumor %config-change cir.rum.rum ~)
%= this
circles.str.sta
(~(del by circles.str.sta) cir.rum.rum)
==
::
:: %source: the sources of our inbox have changed
::
%source
::~& %inbox-config-source
?. =(circ [our.bol %inbox])
[~ this]
:: we've added a source to our inbox
::
?> ?=(^ con.inbox.str.sta)
?: add.dif.rum.rum
=/ conf=config:hall
%= u.con.inbox.str.sta
src (~(put in src.u.con.inbox.str.sta) src.dif.rum.rum)
==
:- ~ ::(send-rumor %config-change [our.bol %inbox] `conf)
%= this
con.inbox.str.sta `conf
::
circles.str.sta
?: (~(has by circles.str.sta) cir.src.dif.rum.rum)
circles.str.sta
(~(put by circles.str.sta) cir.src.dif.rum.rum ~)
==
:: we've removed a source from our inbox
::
=/ conf=config:hall
%= u.con.inbox.str.sta
src (~(del in src.u.con.inbox.str.sta) src.dif.rum.rum)
==
::~& inbox+conf
:- ~ ::(send-rumor %config-change [our.bol %inbox] `conf)
%= this
con.inbox.str.sta `conf
::
circles.str.sta
?: =(our.bol hos.cir.src.dif.rum.rum)
circles.str.sta
(~(del by circles.str.sta) cir.src.dif.rum.rum)
==
::
:: %full: recieved a full config update for one of our sources
::
%full
::~& %inbox-config-full
=* conf cof.dif.rum.rum
:- ~ ::(send-rumor %config-change circ `conf)
%= this
circles.str.sta (~(put by circles.str.sta) circ `conf)
==
::
:: %read: recieved a read reciept
::
%read
?. =([our.bol %inbox] cir.rum.rum)
[~ this]
?> ?=(^ con.inbox.str.sta)
:- ~
%= this
red.u.con.inbox.str.sta red.dif.rum.rum
==
==
==
::
:: %invites:
::
%invites
::~& %invites
?> ?=(%circle -.rum)
?> ?=(%gram -.rum.rum)
?+ -.sep.gam.nev.rum.rum
[~ this(invites.str.sta [nev.rum.rum invites.str.sta])]
::
%inv
=/ circ=circle:hall cir.sep.gam.nev.rum.rum
?: (is-dm-circle circ)
=/ who=(set ship) (sy (rash nom.circ (more dot fed:ag)))
=/ act=poke [%hall-action %newdm who]
:- [ost.bol %poke /join-dm [our.bol %hall] act]~
%= this
invites.str.sta [nev.rum.rum invites.str.sta]
dms.str.sta (~(put by dms.str.sta) nom.circ hos.circ ~)
==
=/ act=poke [%hall-action %source %inbox & (sy [circ ~] ~)]
:- ~
this(invites.str.sta [nev.rum.rum invites.str.sta])
==
::
:: %our:
::
%our
?> ?=(%circle -.rum)
?+ -.rum.rum
::~& our-unprocessed-rumor+rum.rum
[~ this]
::
:: %remove:
::
%remove
::~& %our-remove
[~ this]
::
:: %config:
::
%config
=* circ cir.rum.rum
=* diff dif.rum.rum
?+ -.diff
::~& our-unprocessed-config+diff
[~ this]
::
:: %full: recieved a full config update for one of our sources
::
%full
::~& %our-config-full
=* conf cof.dif.rum.rum
:- ~ ::(send-rumor %config-change circ `conf)
%= this
circles.str.sta (~(put by circles.str.sta) circ `conf)
==
::
:: %read: recieved a read reciept
::
%read
=/ conf (need (~(got by circles.str.sta) circ))
=. red.conf red.dif.rum.rum
:- ~
%= this
circles.str.sta (~(put by circles.str.sta) circ `conf)
==
==
==
==
::
:: +send-rumor: send a rumor to all subscribers
::
++ send-rumor
|= rum=rumor
::~& send-rumor+rum
^- (list move)
%+ turn (prey:pubsub:userlib /primary bol)
|= [=bone *]
[bone %diff %collections-rumor rum]
::
:: +poke-noun: debugging stuff
::
++ poke-noun
|= a=@tas
^- (quip move _this)
?+ a
[~ this]
::
%check-all-subs
~& 'here are all incoming subs'
~& ^- (list (pair ship path))
%+ turn ~(tap by sup.bol)
|= [b=bone s=ship p=path]
^- (pair ship path)
[s p]
[~ this]
::
%print-state
~& str.sta
[~ this]
::
%rebuild-subs
:_ this
:~ [ost.bol %peer /circles [our.bol %hall] /circles/[(scot %p our.bol)]]
[ost.bol %peer /inbox [our.bol %hall] /circle/inbox/config/grams]
[ost.bol %peer /invites [our.bol %hall] /circle/i/grams]
==
==
::
++ is-dm-circle
|= circ=circle:hall
^- ?
?= ^
(rush nom.circ (more dot fed:ag))
--

View File

@ -1,104 +0,0 @@
::
:: /app/fora/hoon
::
::TODO maybe stop relying on %hood one day.
::
/- hall
/+ hall, time-to-id
=, format
=, title
::
|%
++ move (pair bone card)
++ card
$% {$poke wire dock poke}
{$info wire @p toro:clay}
==
++ poke
$% {$hall-action action:hall}
{$write-fora-post spur ship cord cord}
{$write-comment spur ship cord}
==
--
::
|_ {bol/bowl:gall ~}
::
++ prep
|= old/(unit ~)
^- (quip move _..prep)
?^ old [~ ..prep(+<+ u.old)]
:_ ..prep
:~ (act %create %fora-posts 'fora posts' %journal)
(act %create %fora-comments 'fora comments' %journal)
==
::
++ act
|= a/action:hall
^- move
[ost.bol %poke / [our.bol %hall] %hall-action a]
::
++ ra-base-hart .^(hart:eyre %e /(scot %p our.bol)/host/(scot %da now.bol))
::
++ poke-fora-post
|= {pax/path sup/spur hed/@t txt/@t}
^- (quip move _+>)
:_ +>
::
:: if txt is blank then return no moves.
::
?: ?=(^ (rush txt spac:de-json:html)) ~
::
:: otherwise, post the content.
::
:~ %- act
:+ %phrase [[our.bol %fora-posts] ~ ~]
:_ ~
:+ %app dap.bol
:+ %fat
:+ %name
(crip "post by {(cite src.bol)}: {(trip hed)}")
text+(to-wain txt)
=. pax (welp pax /posts/(crip "{<now.bol>}~"))
[%url [ra-base-hart `pax ~] ~]
::
:* ost.bol
%poke
/fora-post
[our.bol %hood]
[%write-fora-post sup src.bol hed txt]
==
==
::
++ poke-fora-comment
|= {pax/path sup/spur txt/@t}
^- (quip move _+>)
:_ +>
::
:: if txt is blank then return no moves.
::
?: ?=(^ (rush txt spac:de-json:html)) ~
::
:: otherwise, post the content.
::
:~ ^- move
%- act
:+ %phrase [[our.bol %fora-comments] ~ ~]
:_ ~
:+ %app dap.bol
^- speech:hall
:+ %fat
:+ %name
=+ nam=?~(sup "" (trip i.sup))
(crip "comment by {(cite src.bol)} on /{nam}")
text+(to-wain txt)
=+ fra=(crip (time-to-id now.bol))
[%url [ra-base-hart `pax ~] `fra]
::
:* ost.bol
%poke
/fora-comment
[our.bol %hood]
[%write-comment sup src.bol txt]
==
==
--

View File

@ -164,9 +164,6 @@
++ poke-helm-verb (wrap poke-verb):from-helm
++ poke-helm-rekey (wrap poke-rekey):from-helm
++ poke-helm-nuke (wrap poke-nuke):from-helm
++ poke-helm-tlon-add-fora (wrap poke-tlon-add-fora):from-helm
++ poke-helm-tlon-add-stream (wrap poke-tlon-add-stream):from-helm
++ poke-helm-tlon-init-stream (wrap poke-tlon-init-stream):from-helm
++ poke-helm-automass (wrap poke-automass):from-helm
++ poke-helm-cancel-automass (wrap poke-cancel-automass):from-helm
++ poke-helm-bonk (wrap poke-bonk):from-helm
@ -192,10 +189,6 @@
++ poke-kiln-permission (wrap poke-permission):from-kiln
++ poke-write-sec-atom (wrap poke-sec-atom):from-write
++ poke-write-paste (wrap poke-paste):from-write
++ poke-write-comment (wrap poke-comment):from-write
++ poke-write-fora-post (wrap poke-fora-post):from-write
++ poke-write-plan-info (wrap poke-plan-info):from-write
++ poke-write-plan-account (wrap poke-plan-account):from-write
++ poke-write-tree (wrap poke-tree):from-write
++ poke-write-wipe (wrap poke-wipe):from-write
++ quit-drum-phat (wrap quit-phat):from-drum

View File

@ -152,19 +152,9 @@
++ skip-completely
^~ ^- (map path tape)
%- my :~ ::TODO don't hardcode
:- /ren/css "not meant to be called outside /web/pack"
:- /ren/js "not meant to be called outside /web/pack"
:- /ren/run "not meant to be called except on a (different) hoon file"
:- /ren/collections "temporarily disabled"
:- /ren/rss-xml "scrys into eyre"
:- /ren/test-gen "temporarily disabled"
:- /ren/urb "temporarily disabled"
:- /ren/x-urb "temporarily disabled"
:- /ren/x-htm "temporarily disabled"
:- /ren/x-collections-snip "temporarily disabled"
:- /ren/x-collections-json "temporarily disabled"
::
:- /web/landscape "/$ doensn't work in tests"
==
::
++ failing

View File

@ -1,11 +0,0 @@
:: tlon: add fora notifications to local urbit-meta
::
:: make the local urbit-meta pull from {for}'s fora notification channels.
::
:::: /gen/hood/tlon/add-fora/hoon
::
:- %say
|= $: {now/@da eny/@uvJ bec/beak}
{{for/ship ~} ~}
==
[%helm-tlon-add-fora for]

View File

@ -1,11 +0,0 @@
:: tlon: add stream to local urbit-meta
::
:: make the local urbit-meta pull from {web}'s stream.
::
:::: /gen/hood/tlon/add-stream/hoon
::
:- %say
|= $: {now/@da eny/@uvJ bec/beak}
{{web/ship ~} ~}
==
[%helm-tlon-add-stream web]

View File

@ -1,12 +0,0 @@
:: tlon: configure stream ship
::
:: create a local stream channel and have it pull from
:: {met}'s urbit-meta.
::
:::: /gen/hood/tlon/init-stream/hoon
::
:- %say
|= $: {now/@da eny/@uvJ bec/beak}
{{met/ship ~} ~}
==
[%helm-tlon-init-stream met]

View File

@ -1,992 +0,0 @@
::
:::: /hoon/collections/lib
::
/? 309
/- hall
/+ cram, elem-to-react-json
:: ::
~% %collections-lib ..is ~
|%
+$ move [bone card]
::
+$ card
$% [%info wire toro:clay]
[%poke wire dock poke]
[%perm wire desk path rite:clay]
[%peer wire dock path]
[%pull wire dock ~]
[%diff diff]
==
::
+$ diff
$% [%collections-prize prize]
[%collections-rumor rumor]
[%hall-rumor rumor:hall]
==
::
+$ poke
$% [%hall-action action:hall]
[%collections-action action]
[%json json]
==
::
+$ state
$% [%0 col=collection str=streams]
==
::
+$ streams
$: :: inbox config and messages
::
inbox=[con=(unit config:hall) env=(list envelope:hall)]
:: names and configs of all circles we know about
::
circles=(map circle:hall (unit config:hall))
:: names of all circles we own
::
our-circles=(set name:hall)
:: list of messages in all our DM circles
::
dms=(map name:hall [ini=ship env=(list envelope:hall)])
:: all the DM invites we've received
::
invites=(list envelope:hall)
==
::
+$ prize
$: :: inbox config and messages
::
inbox=[con=(unit config:hall) env=(list envelope:hall)]
:: names and configs of all circles we know about
::
circles=(map circle:hall (unit config:hall))
:: names of all circles we own
::
our-circles=(set name:hall)
:: list of messages in all our DM circles
::
dms=(map name:hall [ini=ship env=(list envelope:hall)])
:: all the DM invites we've received
::
invites=(list envelope:hall)
==
::
+$ rumor
$% :: if config is given, either add new circle or update existing one
:: if config is nil then delete circle
::
[%config-change cir=circle:hall con=(unit config:hall)]
:: recieved a new inbox message or DM invite
::
[%new-msg nom=?(%inbox %invites) env=envelope:hall]
==
::
+$ command
$% [%chat-invite nom=name:hall who=(set ship)]
[%collection-invite nom=name:hall col=term who=(set ship)]
==
+$ collection [meta=config data=(map nom=knot =item)]
::
+$ item
$~ [%error ~]
$% [%collection col=collection]
[%raw raw=raw-item]
[%both col=collection raw=raw-item]
[%error ~]
==
::
+$ raw-item
$% [%udon meta=(map knot cord) data=@t]
==
::
+$ config
$: full-path=beam
name=@t
description=@t
::
author=@p
::
date-created=@da
last-modified=@da
::
type=@tas
comments=?
sort-key=(unit @)
visible=?
::
==
::
+$ action
$: who=ship
dek=desk
acts=(list sub-action)
==
::
+$ sub-action
$% [%write pax=path for=form]
[%delete pax=path]
[%perms pax=path r=rule:clay w=rule:clay]
::
[%collection pax=path name=@t desc=@t comments=? visible=? type=@tas]
[%post pax=path name=@t type=@tas comments=? content=@t edit=?]
[%comment pax=path content=@t]
==
::
+$ form
$% [%udon @t]
[%collections-config config]
==
::
++ collection-error
~/ %coll-collection-error
|= col=collection
^- ?
|-
=/ vals=(list item) ~(val by data.col)
%+ roll vals
|= [i=item out=_|]
^- ?
?: out out
?+ -.i
%.n
%error %.y
%collection ^$(col col.i)
%both ^$(col col.i)
==
::::
:::: /mar/snip
::::
++ words 1
++ hedtal
=| met/marl
|= a/marl ^- {hed/marl tal/marl}
?~ a [~ ~]
:: looks like it only terminates if it finds an h1?
?. ?=($h1 n.g.i.a)
?: ?=($meta n.g.i.a)
$(a t.a, met [i.a met])
=+ had=$(a c.i.a)
?^ -.had had
$(a t.a)
[c.i.a (weld (flop met) (limit words t.a))]
::
::
++ limit
~/ %coll-limit
|= {lim/@u mal/marl}
=< res
|- ^- {rem/@u res/marl}
?~ mal [lim ~]
?~ lim [0 ~]
=+ ^- {lam/@u hed/manx}
?: ?=(_;/(**) i.mal)
[lim ;/(tay)]:(deword lim v.i.a.g.i.mal)
[rem ele(c res)]:[ele=i.mal $(mal c.i.mal)]
[rem - res]:[hed $(lim lam, mal t.mal)]
::
++ deword
~/ %coll-deword
|= {lim/@u tay/tape} ^- {lim/@u tay/tape}
?~ tay [lim tay]
?~ lim [0 ~]
=+ wer=(dot 1^1 tay)
?~ q.wer
[lim - tay]:[i.tay $(tay t.tay)]
=+ nex=$(lim (dec lim), tay q.q.u.q.wer)
[-.nex [(wonk wer) +.nex]]
::
:: json
::
++ item-to-json
~/ %coll-item-to-json
|= itm=item
^- json
?- -.itm
%error (frond:enjs:format %error ~)
::
%collection
%+ frond:enjs:format
%collection (collection-to-json col.itm)
::
%raw
%- frond:enjs:format
[%item (raw-to-json raw.itm)]
::
%both
%- pairs:enjs:format
:~ [%item (raw-to-json raw.itm)]
[%collection (collection-to-json col.itm)]
==
==
::
++ collection-to-json
~/ %coll-collection-to-json
|= col=collection
^- json
%- pairs:enjs:format
:~ [%meta (config-to-json meta.col)]
:+ %data %a
%+ turn ~(tap by data.col)
|= [nom=knot ite=item]
^- json
%- pairs:enjs:format
:~ [%filename %s nom]
[%item (item-to-json ite)]
==
==
::
++ raw-to-json
~/ %coll-raw-to-json
|= raw=raw-item
^- json
=/ elm=manx elm:(static:cram (ream data.raw))
=/ rec=json (elem-to-react-json elm)
%- pairs:enjs:format
:~ [%data rec]
[%meta (meta-to-json meta.raw)]
==
::
++ config-to-json
~/ %coll-config-to-json
|= con=config
^- json
?: =(con *config)
~
%- pairs:enjs:format
:~ :- %full-path
:- %a
%+ turn (en-beam:format full-path.con)
|= a=@ta
[%s a]
:- %name [%s name.con]
:- %desc [%s description.con]
:- %author (ship:enjs:format author.con)
:- %date-created (time:enjs:format date-created.con)
:- %last-modified (time:enjs:format last-modified.con)
:- %type [%s type.con]
:- %comments [%b comments.con]
:- %sort-key ?~(sort-key.con ~ (numb:enjs:format u.sort-key.con))
:- %visible [%b visible.con]
==
::
++ meta-to-json
~/ %coll-meta-to-json
|= meta=(map knot cord)
^- json
%- pairs:enjs:format
%+ turn ~(tap by meta)
|= [key=@t val=@t]
^- [@t json]
[key [%s val]]
::
++ udon-to-front
~/ %coll-udon-to-front
|= u=@t
^- (map knot cord)
%- ~(run by inf:(static:cram (ream u)))
|= a=dime ^- cord
?+ (end 3 1 p.a) (scot a)
%t q.a
==
::
:: +path-to-circle:
::
:: takes a clay path and returns a hall circle
:: for a path /foo/bar it returns a circle with a :name %c-foo-bar
::
++ path-to-circle
~/ %coll-path-to-circle
|= [pax=path our=@p]
^- circle:hall
=. pax
?: ?=([%web %collections *] pax)
(weld /c (slag 2 `path`pax))
?: ?=([%collections *] pax)
(weld /c (slag 1 `path`pax))
?: ?=([%c *] pax)
`path`pax
`path`(weld /c pax)
=/ nam=term
%+ roll `(list @ta)`pax
|= [seg=@ta out=term]
%^ cat 3
?:(=(%$ out) out (cat 3 out '-'))
;;(@tas seg)
[our nam]
::
:: +allowed-by: checks if ship :who is allowed by the permission rules in :dic
::
++ allowed-by
~/ %coll-allowed-by
|= [who=@p dic=dict:clay our=@p]
^- ?
?: =(who our) &
=/ in-list=?
?| (~(has in p.who.rul.dic) who)
::
%- ~(rep by q.who.rul.dic)
|= [[@ta cru=crew:clay] out=_|]
?: out &
(~(has in cru) who)
==
?: =(%black mod.rul.dic)
!in-list
in-list
::
:: +collection-notify: XX
::
++ collection-notify
~/ %coll-collection-notify
|= [pax=path conf=config]
^- json
%- pairs:enjs:format
:~ ['author' [%s (crip (scow %p author.conf))]]
['host' [%s (crip (scow %p p.full-path.conf))]]
['path' [%a (turn pax |=(a=@ta `json`[%s a]))]]
['name' [%s name.conf]]
['date' [%s (crip (scow %da last-modified.conf))]]
['type' [%s type.conf]]
==
::
:: +item-notify: XX
::
++ item-notify
~/ %coll-item-notify
|= [pax=path raw=raw-item now=@da byk=beak]
^- json
=/ author (fall (~(get by meta.raw) %author) ~.anon)
=/ host (fall (~(get by meta.raw) %host) ~.anon)
=/ dat (fall (~(get by meta.raw) %last-modified) (scot %da now))
=/ nom (fall (~(get by meta.raw) %name) ~.no-title)
=/ typ (fall (~(get by meta.raw) %type) ~.no-type)
::
=/ elm=manx elm:(static:cram (ream data.raw))
=/ snip=marl tal:(hedtal +.elm)
=/ inner
?~ snip
(crip (en-xml:html elm))
(crip (en-xml:html i.snip)) :: inner html
::
=/ parent-spur (slag 1 (flop pax))
=/ bek=beak byk(r [%da now])
=/ parent-path (en-beam:format [bek parent-spur])
=/ parent-dir .^(arch %cy parent-path)
::
=/ parent-conf=json
?: (~(has in dir.parent-dir) ~.udon ~)
%- meta-to-json
%- udon-to-front
.^(@t %cx (weld parent-path /udon))
?: (~(has in dir.parent-dir) ~.collections-config ~)
%- config-to-json
.^(config %cx (weld parent-path /collections-config))
~
::
%- pairs:enjs:format
:~ ['author' [%s author]]
['host' [%s host]]
['path' [%a (turn pax |=(a=@ta `json`[%s a]))]]
['name' [%s nom]]
['date' [%s dat]]
['type' [%s typ]]
['content' [%s data.raw]]
['snip' [%s inner]]
['parent-config' parent-conf]
==
::
:: +front-to-wain: XX
::
++ front-to-wain
~/ %coll-front-to-wain
|= a=(map knot cord)
^- wain
=/ entries=wain
%+ turn ~(tap by a)
|= b=[knot cord]
=/ c=[term cord] ;;([term cord] b)
(crip " [{<-.c>} {<+.c>}]")
::
?~ entries ~
;: weld
[':- :~' ~]
entries
[' ==' ~]
==
::
:: +update-udon-front: XX
::
++ update-udon-front
~/ %coll-update-udon-front
|= [fro=(map knot cord) udon=@t]
^- @t
%- of-wain:format
=/ tum (trip udon)
=/ id (find ";>" tum)
?~ id
%+ weld (front-to-wain fro)
(to-wain:format (crip (weld ";>\0a" tum)))
%+ weld (front-to-wain fro)
(to-wain:format (crip (slag u.id tum)))
::
:: _ta: main event core for collections
::
++ ta
~/ %coll-ta
|_ $: moves=(list move)
bol=bowl:gall
==
::
:: +ta-this: ta core subject
::
++ ta-this .
::
:: +ta-done:
::
:: flop :moves for finalization, since moves are prepended to the list
::
++ ta-done (flop moves)
::
:: +ta-emit: add a +move to :moves
::
++ ta-emit
~/ %coll-ta-emit
|= mov=move
%_ ta-this
moves [mov moves]
==
::
:: +ta-emil: add a list of +move to :moves
::
++ ta-emil
~/ %coll-ta-emil
|= mos=(list move)
%_ ta-this
moves (welp (flop mos) moves)
==
::
:: +ta-act: process collection-action
::
++ ta-act
~/ %coll-ta-act
|= act=action
^+ ta-this
::
:: iterate through list of +sub-action of +action
::
|-
?~ acts.act ta-this
=* a i.acts.act
::
=/ now-id=@da (sub now.bol (div (dis now.bol ~s0..fffe) 2))
=/ dat (scot %da now-id)
=/ bek=beak byk.bol(r [%da now-id])
=/ sap (en-beam:format [bek (flop (path +<.a))])
::
=. ta-this
?- -.a
%write
=/ perms .^([dict:clay dict:clay] %cp sap)
?: (allowed-by src.bol +.perms our.bol)
?- -.for.a
%udon (ta-write pax.a `cage`[-.for.a !>(+.for.a)])
%collections-config (ta-write pax.a `cage`[-.for.a !>(+.for.a)])
==
ta-this
::
%delete
=/ perms .^([dict:clay dict:clay] %cp sap)
?: (allowed-by src.bol +.perms our.bol)
(ta-remove pax.a)
ta-this
::
%perms
?: =(src.bol our.bol) :: XX admin privileges for other users?
(ta-set-permissions pax.a r.a w.a)
ta-this
::
::
:: XX some of this is redunant
::
%collection
=/ perms
.^([dict:clay dict:clay] %cp (weld sap /[dat]/collections-config))
?. (allowed-by src.bol +.perms our.bol)
ta-this
=/ conf=config
:* [bek (flop (weld pax.a /[dat]/collections-config))]
name.a
desc.a
our.bol
now-id
now-id
type.a
comments.a
~
visible.a
==
=. ta-this
%+ ta-write (weld pax.a /[dat]/collections-config)
[%collections-config !>(conf)]
:: restrict permissions on config file
=. ta-this
%^ ta-set-permissions (weld pax.a /[dat]/collections-config)
[%white ((set whom:clay) [[& src.bol] ~ ~])] :: read
[%white ((set whom:clay) [[& src.bol] ~ ~])] :: write
:: open permissions on collection items
=. ta-this
%^ ta-set-permissions (weld pax.a /[dat])
[%black ((set whom:clay) ~)] :: read
[%black ((set whom:clay) ~)] :: write
ta-this
::
%post
=? pax.a !edit.a
(weld pax.a /[dat])
=? sap !edit.a
(en-beam:format [bek (flop pax.a)])
=/ perms .^([dict:clay dict:clay] %cp (weld sap /udon))
?. (allowed-by src.bol +.perms our.bol)
ta-this
=. content.a (crip (weld (trip content.a) "\0a"))
=/ front=(map knot cord)
%- my
:~ [%name name.a]
[%comments ?:(comments.a ~..y ~..n)]
[%author (scot %p src.bol)]
[%host (scot %p our.bol)]
[%date-created (snag 0 (flop pax.a))]
[%last-modified dat]
[%type type.a]
==
=. ta-this
%+ ta-write (weld pax.a /udon)
[%udon !>((update-udon-front front content.a))]
:: restrict permissions on udon file
=. ta-this
%^ ta-set-permissions (weld pax.a /udon)
[%black ((set whom:clay) ~)] :: read
[%white ((set whom:clay) [[& src.bol] ~ ~])] :: write
:: open permissions on comments
=. ta-this
%^ ta-set-permissions pax.a
[%black ((set whom:clay) ~)] :: read
[%black ((set whom:clay) ~)] :: write
ta-this
::
%comment
=/ perms .^([dict:clay dict:clay] %cp (weld sap /[dat]/udon))
?. (allowed-by src.bol +.perms our.bol)
ta-this
=. content.a (crip (weld (trip content.a) "\0a"))
=/ front=(map knot cord)
%- my
:~ [%author (scot %p src.bol)]
[%host (scot %p our.bol)]
[%date-created dat]
[%last-modified dat]
[%type %comments]
==
=. ta-this
%+ ta-write (weld pax.a /[dat]/udon)
[%udon !>((update-udon-front front content.a))]
:: restrict permissions on udon file
=. ta-this
%^ ta-set-permissions (weld pax.a /[dat]/udon)
[%black ((set whom:clay) ~)] :: read
[%white ((set whom:clay) [[& src.bol] ~ ~])] :: write
ta-this
::
==
$(acts.act t.acts.act)
::
:: +ta-update:
::
::
::
++ ta-update
~/ %coll-ta-update
|= [old=collection new=collection]
^+ ta-this
?: =(old new)
ta-this
(ta-update-collection old new /web/collections)
::
++ ta-insert-item
~/ %coll-ta-insert-item
|= [new=item pax=path]
^+ ta-this
=/ parent-path (scag (dec (lent pax)) pax)
::
?- -.new
::
%error
(ta-hall-lin parent-path 'error')
::
%collection
=. ta-this
%^ ta-hall-json parent-path 'new collection'
(collection-notify pax meta.col.new)
::
=. ta-this (ta-hall-create-circle pax name.meta.col.new)
=/ items=(list [nom=@ta =item]) ~(tap by data.col.new)
|-
?~ items ta-this
=. ta-this (ta-insert-item item.i.items (weld pax [nom.i.items ~]))
$(items t.items)
::
%both
=. ta-this (ta-hall-create-circle pax name.meta.col.new)
=/ items=(list [nom=@ta =item]) ~(tap by data.col.new)
=. ta-this
|-
?~ items ta-this
=. ta-this (ta-insert-item item.i.items (weld pax [nom.i.items ~]))
$(items t.items)
::
ta-this
::
%raw
=. ta-this
%^ ta-hall-json
parent-path
'new item'
(item-notify pax raw.new now.bol byk.bol)
?: ?& (~(has by meta.raw.new) %comments)
=('.y' (~(got by meta.raw.new) %comments))
==
=/ author=(unit @ta) (~(get by meta.raw.new) %author)
=/ author-p=@p
?~ author our.bol
(fall (rush u.author ;~(pfix sig fed:ag)) our.bol)
(ta-generate-comments pax author-p)
ta-this
::
==
::
++ ta-remove-item
~/ %coll-ta-remove-item
|= [old=item pax=path]
^+ ta-this
:: flush permissions
:: notify parent of deletion
=/ parent (scag (dec (lent pax)) pax)
:: recurse for children
?- -.old
::
%error
(ta-hall-lin parent 'error')
::
%collection
=. ta-this
%^ ta-hall-json parent 'deleted collection'
(collection-notify pax meta.col.old)
=. ta-this (ta-flush-permissions (weld pax /collections-config))
=/ items=(list [nom=@ta =item]) ~(tap by data.col.old)
|-
?~ items ta-this
=. ta-this (ta-remove-item item.i.items (weld pax [nom.i.items ~]))
$(items t.items)
::
%both
=. ta-this (ta-flush-permissions pax)
=. ta-this (ta-flush-permissions (weld pax /collections-config))
=/ items=(list [nom=@ta =item]) ~(tap by data.col.old)
|-
?~ items ta-this
=. ta-this (ta-remove-item item.i.items (weld pax [nom.i.items ~]))
$(items t.items)
::
%raw
=. ta-this (ta-flush-permissions pax)
%^ ta-hall-json
parent
'deleted item'
(item-notify pax raw.old now.bol byk.bol)
::
==
::
::
::
++ ta-update-item
:: always make sure removals happen first and insertions happen last
:: because removals flush permissions and insertions set them
::
~/ %coll-ta-update-item
|= [old=item new=item pax=path]
^+ ta-this
?: =(old new)
ta-this
::
:: check for changes in item type
?: &(?=(%collection -.old) ?=(%collection -.new))
(ta-update-collection col.old col.new pax)
?: &(?=(%raw -.old) ?=(%raw -.new))
(ta-update-raw-item raw.old raw.new pax)
?: &(?=(%both -.old) ?=(%both -.new))
:: update raw item
=. ta-this (ta-update-collection col.old col.new pax)
(ta-update-raw-item raw.old raw.new pax)
::
?: &(?=(%collection -.old) ?=(%raw -.new))
:: remove collection
:: insert raw item
=. ta-this (ta-remove-item old pax)
(ta-insert-item new pax)
::
?: &(?=(%collection -.old) ?=(%both -.new))
:: insert raw item
:: update-collection
=. ta-this (ta-update-collection col.old col.new pax)
(ta-insert-item new pax)
::
?: &(?=(%raw -.old) ?=(%collection -.new))
:: remove raw item
:: insert collection
=. ta-this (ta-remove-item old pax)
(ta-insert-item new pax)
::
?: &(?=(%raw -.old) ?=(%both -.new))
:: insert collection
:: update raw item
=. ta-this (ta-update-raw-item raw.old raw.new pax)
(ta-insert-item new pax)
::
?: &(?=(%both -.old) ?=(%raw -.new))
:: remove collection
:: update raw item
=. ta-this (ta-remove-item [%collection col.old] pax)
(ta-update-raw-item raw.old raw.new pax)
::
?: &(?=(%both -.old) ?=(%collection -.new))
:: remove raw item
:: update collection
=. ta-this (ta-remove-item [%raw raw.old] pax)
(ta-update-collection col.old col.new pax)
::
::
?: &(?=(%error -.old) ?=(%error -.new))
ta-this
?: &(?=(%error -.old) ?=(%collection -.new))
(ta-insert-item new pax)
?: &(?=(%error -.old) ?=(%raw -.new))
(ta-insert-item new pax)
?: &(?=(%error -.old) ?=(%both -.new))
(ta-insert-item new pax)
?: ?=(%error -.new)
(ta-hall-lin pax 'error')
::
ta-this
::
++ ta-update-raw-item
~/ %coll-ta-update-raw-item
|= [old=raw-item new=raw-item pax=path]
^+ ta-this
?: =(old new)
ta-this
::
=? ta-this !=(data.old data.new)
=/ parent-path (scag (dec (lent pax)) pax)
%^ ta-hall-json
parent-path
'edited item'
(item-notify pax new now.bol byk.bol)
::
=? ta-this
?& =('.y' (fall (~(get by meta.new) %comments) '.n'))
=('.n' (fall (~(get by meta.old) %comments) '.n'))
==
=/ author=(unit @ta) (~(get by meta.new) %author)
=/ author-p=@p
?~ author our.bol
(fall (rush u.author ;~(pfix sig fed:ag)) our.bol)
(ta-generate-comments pax author-p)
::
=? ta-this
?& =('.n' (fall (~(get by meta.new) %comments) '.n'))
=('.y' (fall (~(get by meta.old) %comments) '.n'))
==
:: delete comments
(ta-remove (weld pax /collections-config))
::
ta-this
::
++ ta-update-collection
~/ %coll-ta-update-collection
|= $: old=collection
new=collection
pax=path
==
^+ ta-this
::
=? ta-this !=(meta.old meta.new)
=/ parent-path (scag (dec (lent pax)) pax)
%^ ta-hall-json parent-path 'edited collection'
(collection-notify pax meta.new)
::
?: =(data.old data.new)
ta-this
::
:: new values of all changed items
=/ upd-new (~(dif in (~(int by data.old) data.new)) data.old)
:: old values of all changed items
=/ upd-old (~(dif in (~(int by data.new) data.old)) data.new)
:: all totally new entries
=/ ins-new (~(dif by data.new) data.old)
:: all deleted entries
=/ del-old (~(dif by data.old) data.new)
::
=/ upd-new=(list [nom=knot =item]) ~(tap by upd-new)
=/ upd-old=(list [nom=knot =item]) ~(tap by upd-old)
=/ ins-new=(list [nom=knot =item]) ~(tap by ins-new)
=/ del-old=(list [nom=knot =item]) ~(tap by del-old)
::
=/ lam |=([[a=knot item] out=(list path)] [(weld pax [a ~]) out])
::
=. ta-this |-
?~ upd-new
ta-this
?< ?=(~ upd-old)
=* new-item i.upd-new
=* old-item i.upd-old
=/ new-pax (weld pax [nom.new-item ~])
=. ta-this (ta-update-item item.old-item item.new-item new-pax)
::
%= $
upd-new t.upd-new
upd-old t.upd-old
==
::
=. ta-this |-
?~ ins-new
ta-this
=* new-item i.ins-new
=/ new-pax (weld pax [nom.new-item ~])
=. ta-this (ta-insert-item +.new-item (weld pax [-.new-item ~]))
$(ins-new t.ins-new)
::
=. ta-this |-
?~ del-old
ta-this
=* old-item i.del-old
=/ old-pax (weld pax [nom.old-item ~])
=. ta-this (ta-remove-item +.old-item (weld pax [-.old-item ~]))
$(del-old t.del-old)
::
ta-this
::
++ ta-generate-comments
~/ %coll-ta-generate-comments
|= [pax=path author=ship]
^+ ta-this
=/ sup=path [%collections-config (flop pax)]
=/ bek byk.bol(r [%da now.bol])
=/ pat (en-beam:format [bek sup])
=/ dat=@da (slav %da (snag 0 (flop pax)))
=/ cay=config
:* [bek sup]
'comments'
'comments'
author
dat
dat
%comments
|
~
|
==
(ta-write (flop sup) %collections-config !>(cay))
::
:: writing files
::
++ ta-write
~/ %coll-ta-write
=, space:userlib
|= [pax=path cay=cage]
^+ ta-this
=/ bek byk.bol(r [%da now.bol])
=. pax (en-beam:format bek (flop pax))
%+ ta-emit ost.bol
[%info (weld /ta-write pax) (foal pax cay)]
::
++ ta-remove
=, space:userlib
~/ %coll-ta-remove
|= pax=path
=/ bek byk.bol(r [%da now.bol])
=. pax (en-beam:format bek (flop pax))
^+ ta-this
%+ ta-emit ost.bol
[%info (weld /ta-remove pax) (fray pax)]
::
:: permissions
::
++ ta-set-permissions
~/ %coll-ta-set-permissions
|= [pax=path r=rule:clay w=rule:clay]
^+ ta-this
%+ ta-emit ost.bol
[%perm (weld /perms pax) q.byk.bol pax [%rw `r `w]]
::
++ ta-flush-permissions
~/ %coll-ta-flush-permissions
|= pax=path
^+ ta-this
%+ ta-emit ost.bol
[%perm (weld /perms pax) q.byk.bol pax [%rw ~ ~]]
::
:: hall
::
++ ta-hall-action
~/ %coll-ta-hall-action
|= act=action:hall
^+ ta-this
%+ ta-emit ost.bol
[%poke /col-hall-action [our.bol %hall] %hall-action act]
::
++ ta-hall-actions
~/ %coll-ta-hall-actions
|= act=(list $?(~ action:hall))
^+ ta-this
?~ act ta-this
?~ i.act $(act t.act)
%= $
ta-this (ta-hall-action i.act)
act t.act
==
::
++ ta-hall-create-circle
~/ %coll-ta-hall-create-circle
|= [pax=path name=@t]
^+ ta-this
=/ circ=circle:hall (path-to-circle pax our.bol)
=/ parent=circle:hall
?: =(nom.circ %c)
[our.bol %inbox]
(path-to-circle (scag (dec (lent pax)) pax) our.bol)
=/ acts=(list action:hall)
:~ [%source nom.parent & (sy `source:hall`[circ ~] ~)]
[%create nom.circ name %journal]
==
:: XX should we also source comment circles?
=? acts =(nom.parent %c)
[[%source %inbox & (sy `source:hall`[circ ~] ~)] acts]
(ta-hall-actions (flop acts))
::
++ ta-hall-lin
~/ %coll-ta-hall-lin
|= [pax=path msg=cord]
^+ ta-this
=/ circ=circle:hall (path-to-circle pax our.bol)
%- ta-hall-action
[%phrase [circ ~ ~] [%lin | msg]~]
::
++ ta-hall-json
~/ %coll-ta-hall-json
|= [pax=path header=@t jon=json]
^+ ta-this
=/ circ=circle:hall (path-to-circle pax our.bol)
%- ta-hall-action
:+ %phrase [circ ~ ~]
[%fat [%text ~[header]] [%lin | (crip (en-json:html jon))]]~
::
--
--

View File

@ -225,50 +225,4 @@
|= [wir=wire success=? binding=binding:eyre] =< abet
(emit %flog ~ %text "bound: {<success>}")
::
++ poke-tlon-init-stream
:: creates stream channel and makes it pull from
:: urbit-meta on {met}.
|= met/ship =< abet
%- emil
%- flop
:~ ^- card
:^ %poke /helm/web/stream/create [our %hall]
:- %hall-action
:- %create
[%stream 'stream relay channel' %channel]
::
:^ %poke /helm/web/stream/filter [our %hall]
:- %hall-action
:- %filter
[%stream | |]
::
:^ %poke /helm/web/stream/source [our %hall]
:- %hall-action
:- %source
[%stream & [[[met %urbit-meta] `[da+(sub now ~d1) ~]] ~ ~]]
==
::
++ poke-tlon-add-fora
:: makes the local urbit-meta pull from {for}'s fora
:: notification channels.
|= for/ship =< abet
%- emil
:~ :^ %poke /helm/web/fora/source [our %hall]
:- %hall-action
:- %source
[%urbit-meta & [[[for %fora-posts] `[da+now ~]] ~ ~]]
::
:^ %poke /helm/web/fora/source [our %hall]
:- %hall-action
:- %source
[%urbit-meta & [[[for %fora-comments] `[da+now ~]] ~ ~]]
==
::
++ poke-tlon-add-stream
:: makes the local urbit-meta pull from {web}'s stream.
|= web/ship =< abet
%- emit
:^ %poke /helm/web/stream/source [our %hall]
:+ %hall-action %source
[%urbit-meta & [[[web %stream] `[da+now ~]] ~ ~]]
--

View File

@ -3,7 +3,6 @@
:::: /hoon/write/hood/lib
::
/? 310
/- plan-diff, plan-acct
=, format
=* as-octs as-octs:mimes:html
=, space:userlib
@ -41,45 +40,6 @@
|= {sup/path mim/mime} ^+ abet :: XX determine extension, beak
(poke--data [`%md (flop sup)] %mime mim)
::
++ poke-plan-account
|= {sev/knot usr/plan-acct} ^+ abet
(poke-plan-diff [~ ~ [[sev usr] ~ ~]])
::
++ poke-plan-info
|= {who/@t loc/@t}
(poke-plan-diff [[~ who loc] ~ ~])
::
++ poke-plan-diff
|= dif/plan-diff ^+ abet
?. =(our src)
~|(foreign-write+[our=our src=src] !!)
=/ sev
:: XX this scry will always fail. wat do?
::
=+ .^(path %e /(scot %p our)/serv/(scot %da now))
?>(?=({@tas @tas *} -) -)
=; sob/soba:clay
?~(sob abet abet:(emit %info write+~ `toro:clay`[i.t.sev %& sob]))
=+ pax=`path`/web/plan
=+ paf=(en-beam beak-now (flop pax))
?~ [fil:.^(arch %cy paf)]
=+ ins=(pact-plan [['' ''] ~] dif)
[pax %ins plan+!>(ins)]~
=+ ole=.^({{@t @t} (map knot plan-acct)} %cx paf)
=+ neu=(pact-plan ole dif)
?: =(ole neu) ~
[pax %dif plan-diff+!>(dif)]~
::
++ pact-plan :: XX clay should handle fused insert+diff
|= {all/{{who/@t loc/@t} acc/(map knot plan-acct)} dif/plan-diff}
^+ all
:- (fall inf.dif -.all)
=; neu (~(uni by neu) put.dif)
=+ del=~(tap by del.dif) :: XXX map functions
|- ^+ acc.all
?~ del acc.all
$(del t.del, acc.all (~(del by acc.all) p.i.del))
::
++ poke-paste
|= {typ/?($hoon $md $txt) txt/@t} ^+ abet
(poke--data [`typ /web/paste/(scot %da now)] %mime / (as-octs txt))

View File

@ -1,21 +0,0 @@
|= inner=manx
^- manx
;html
::
;head
;title: Landscape
;meta(charset "utf-8");
;meta
=name "viewport"
=content "width=device-width, initial-scale=1, shrink-to-fit=no";
;link(rel "stylesheet", href "/~~/landscape/css/index.css");
==
::
;body
;div#root
;+ inner
==
;script@"/~~/landscape/js/index-min.js";
==
::
==

View File

@ -1,120 +0,0 @@
::
:::: /hoon/actions/collection/mar
::
/? 309
/+ collections
=, collections
=, format
::
|_ act=action:collections
::
++ grow
|%
++ tank >act<
--
::
++ grab
|%
++ noun action:collections
++ json
|= jon=^json
;; action:collections
=< (action jon)
|%
++ action
%- ot:dejs
:~ ship+(su:dejs fed:ag)
desk+(su:dejs sym)
:- %acts
%- ar:dejs
%- of:dejs
:~ write+write
delete+delete
perms+perms
collection+collection
post+post
comment+comment
==
==
::
++ write
%- ot:dejs
:~ path+(su:dejs ;~(pfix fas (more fas urs:ab)))
mark+(su:dejs sym)
data+so:dejs
==
::
++ delete
%- ot:dejs
:~ path+(su:dejs ;~(pfix fas (more fas urs:ab)))
==
::
++ perms
%- ot:dejs
:~ path+(su:dejs ;~(pfix fas (more fas urs:ab)))
:- %read
%- ot:dejs
:~ mod+(su:dejs ;~(pose (jest %black) (jest %white)))
who+whoms
==
:- %write
%- ot:dejs
:~ mod+(su:dejs ;~(pose (jest %black) (jest %white)))
who+whoms
==
==
::
++ whoms
|= jon=^json
^- (set whom:clay)
=/ x ((ar:dejs (su:dejs fed:ag)) jon)
;; (set whom:clay)
%- ~(run in (sy x))
|=(w=@ [& w])
--
::
++ collection
%- ot:dejs
:~ path+(su:dejs ;~(pfix fas (more fas urs:ab)))
name+sa
desc+so:dejs
comments+bo:dejs
visible+bo:dejs
type+(su:dejs sym)
==
::
++ post
%- ot:dejs
:~ path+(su:dejs ;~(pfix fas (more fas urs:ab)))
name+sa
type+(su:dejs sym)
comments+bo:dejs
content+so:dejs
edit+bo:dejs
==
::
++ comment
%- ot:dejs
:~ path+(su:dejs ;~(pfix fas (more fas urs:ab)))
content+so:dejs
==
::
++ sa :: string as ta
|= jon=^json
?> ?=([%s *] jon)
(scot %tas p.jon)
--
::
--

View File

@ -1,11 +0,0 @@
/? 309
::
/- hall
/+ collections
::
|_ com=command:collections
++ grab
|%
++ noun command:collections
--
--

View File

@ -1,92 +0,0 @@
::
:::: /hoon/config/collection/mar
::
/+ collections
!:
|_ con=config:collections
::
::
++ grow
|%
++ mime
:- /text/x-collection-config
(as-octs:mimes:html (of-wain:format txt))
++ txt
^- wain
::
:~ (cat 3 'full-path: ' (spat (en-beam:format full-path.con)))
(cat 3 'name: ' name.con)
(cat 3 'description: ' description.con)
::
(cat 3 'author: ' (scot %p author.con))
::
(cat 3 'date-created: ' (scot %da date-created.con))
(cat 3 'last-modified: ' (scot %da last-modified.con))
::
(cat 3 'type: ' type.con)
(cat 3 'comments: ' ?:(comments.con 'y' 'n'))
(cat 3 'sort-key: ' ?~(sort-key.con '~' (scot %ud u.sort-key.con)))
(cat 3 'visible: ' ?:(visible.con 'y' 'n'))
==
--
++ grab
|%
++ mime
|= [mite:eyre p=octs:eyre]
(txt (to-wain:format q.p))
++ txt
|= txs=(pole @t)
^- config:collections
:: TODO: putting ~ instead of * breaks this but shouldn't
::
?> ?= $: full-path=@t
name=@t
desc=@t
author=@t
dc=@t
lm=@t
type=@t
com=@t
sk=@t
vis=@t
*
==
txs
::
:* %- need
%+ rash full-path.txs
;~ pfix (jest 'full-path: ')
%+ cook de-beam:format
;~(pfix fas (more fas urs:ab))
==
::
(rash name.txs ;~(pfix (jest 'name: ') (cook crip (star next))))
::
(rash desc.txs ;~(pfix (jest 'description: ') (cook crip (star next))))
::
(rash author.txs ;~(pfix (jest 'author: ~') fed:ag))
::
%+ rash dc.txs
;~ pfix
(jest 'date-created: ~')
(cook year when:so)
==
::
%+ rash lm.txs
;~ pfix
(jest 'last-modified: ~')
(cook year when:so)
==
::
(rash type.txs ;~(pfix (jest 'type: ') (cook crip (star next))))
::
(rash com.txs ;~(pfix (jest 'comments: ') (fuss %y %n)))
::
(rush sk.txs ;~(pfix (jest 'sort-key: ') dem:ag))
::
(rash vis.txs ;~(pfix (jest 'visible: ') (fuss %y %n)))
==
++ noun config:collections
--
++ grad %mime
--

View File

@ -1,17 +0,0 @@
::
:::: /hoon/elem/collection/mar
::
/? 310
=, mimes:html
=, html
|_ own/manx
::
++ grow :: convert to
|%
++ hymn ;html:(head body:"+{own}") :: convert to %hymn
++ html (crip (en-xml hymn)) :: convert to %html
++ mime [/text/html (as-octs html)] :: convert to %mime
--
++ grab |% :: convert from
++ noun manx :: clam from %noun
-- --

View File

@ -1,24 +0,0 @@
::
:::: /hoon/json/collection/mar
::
/? 309
::
:::: compute
::
=, eyre
=, format
=, html
|_ jon/json
::
++ grow :: convert to
|%
++ txt (crip (en-json jon))
++ json jon
--
++ grab
|% :: convert from
++ noun ^json :: clam from %noun
++ json ^json
--
++ grad %mime
--

View File

@ -1,54 +0,0 @@
::
::
/? 309
::
/- hall
/+ collections, hall-json
::
|_ piz=prize:collections
++ grow
|%
++ json
=, enjs:format
^- ^json
%+ frond %landscape
%+ frond %prize
%- pairs
:~ :- %inbox
%- pairs
:~ [%config ?~(con.inbox.piz ~ (conf:enjs:hall-json u.con.inbox.piz))]
[%messages %a (turn env.inbox.piz enve:enjs:hall-json)]
==
::
:+ %circles %a
%+ turn ~(tap by circles.piz)
|= [cir=circle:hall con=(unit config:hall)]
%- pairs
:~ [%circle (circ:enjs:hall-json cir)]
[%config ?~(con ~ (conf:enjs:hall-json u.con))]
==
::
:+ %circles-our %a
%+ turn ~(tap in our-circles.piz)
|= nom=name:hall
[%s nom]
::
:- %dms
%- pairs
%+ turn ~(tap by dms.piz)
|= [nom=name:hall ini=@p env=(list envelope:hall)]
:- nom
%- pairs
:~ [%initiator (ship ini)]
[%messages %a (turn env enve:enjs:hall-json)]
==
::
[%invites %a (turn invites.piz enve:enjs:hall-json)]
==
--
::
++ grab
|%
++ noun prize:collections
--
--

View File

@ -1,36 +0,0 @@
::
::
/? 309
::
/+ collections, hall-json
::
|_ rum=rumor:collections
++ grow
|%
++ json
=, enjs:format
^- ^json
%+ frond %landscape
%+ frond %rumor
%+ frond -.rum
?- -.rum
%config-change
%- pairs
:~ [%circle (circ:enjs:hall-json cir.rum)]
[%config ?~(con.rum ~ (conf:enjs:hall-json u.con.rum))]
==
::
%new-msg
%- pairs
:~ [%circle [%s nom.rum]]
[%message (enve:enjs:hall-json env.rum)]
==
==
--
::
++ grab
|%
++ noun rumor:collections
--
--

View File

@ -1,12 +0,0 @@
::
:::: /mar/fora/comment/hoon
::
/? 310
|_ {pax/path sup/spur txt/@t}
++ grab
|%
++ noun {path spur @t}
++ json
(corl need =>(dejs-soft:format (ot pax+(su fel:stab) sup+(su fel:stab) txt+so ~)))
--
--

View File

@ -1,12 +0,0 @@
::
:::: /mar/fora/post/hoon
::
/? 310
|_ {pax/path sup/spur hed/@t txt/@t}
++ grab
|%
++ noun {path spur @t @t}
++ json
(corl need =>(dejs-soft:format (ot pax+(su fel:stab) sup+(su fel:stab) hed+so txt+so ~)))
--
--

View File

@ -1,11 +0,0 @@
::
:::: /hoon/plan-diff/mar
::
/? 310
/- plan-diff
::
:::: ~fyr
::
|_ plan-diff
++ grab |% ++ noun plan-diff
-- --

View File

@ -1,102 +0,0 @@
::
:::: /hoon/plan/mar
::
/? 310
/- plan-acct, plan-diff
::
:::: ~fyr
::
=, eyre
=, html
=, format
|_ all/{{who/@txname loc/@txloc} acc/(map knot plan-acct)}
::
++ grow :: convert to
=+ all
|%
++ txt
^- wain
:+ (cat 3 'User ' ?~(who 'of Urbit' who))
(cat 3 'Location ' ?~(loc %unknown loc))
%+ turn (sort ~(tap by acc) aor)
|= {a/knot b/plan-acct} ^- cord
%+ rap 3
:^ a ': ' usr.b
?~(url.b ~ [', ' (apix:en-purl u.url.b)])
::
++ plan-json
%- pairs:enjs :~
who+?~(who ~ s+who)
loc+?~(loc ~ s+loc)
acc+o+(~(run by acc) json-acct)
==
++ json-acct :: helper
|= a/plan-acct ^- json
=/ url ?~(url.a ~ (tape:enjs (apix:en-purl u.url.a)))
(pairs:enjs usr+s+usr.a url+url ~)
--
++ grab |% :: convert from
++ noun {{cord cord} (map knot plan-acct)} :: clam from %noun
++ txt
|^ |= a/wain ^+ all
?> ?=({@t @t *} a)
:- [(rash i.a user) (rash i.t.a location)]
(malt (turn t.t.a |=(b/cord (rash b account))))
::
++ user ;~(pfix (jest 'User ') (cook crip (star prn)))
++ knot %+ cook crip
(plus ;~(pose nud low hig hep dot sig cab))
++ location ;~(pfix (jest 'Location ') (cook crip (star prn)))
++ account
;~ plug
knot
;~(pfix col ace knot)
(punt ;~(pfix com ace aurf:de-purl))
==
--
++ mime |=({* a/octs} (txt (to-wain q.a))) :: XX mark translation
--
++ grad
|%
++ form %plan-diff
++ diff
|= neu/_all ^- plan-diff :: XXX map functions
:+ ?:(=(-.all -.neu) ~ (some -.neu))
=< (malt `(list {knot ~})`(murn ~(tap by acc.all) .))
|= {a/knot *} ^- (unit {knot ~})
?:((~(has by acc.neu) a) ~ (some [a ~]))
=< (malt (murn ~(tap by acc.neu) .))
|= {a/knot b/plan-acct} ^- (unit {knot plan-acct})
?: =([~ b] (~(get by acc.all) a))
~
(some [a b])
::
++ pact
|= dif/plan-diff ^+ all :: XXX map functions
:- (fall inf.dif -.all)
=; neu (~(uni by neu) put.dif)
=+ del=~(tap by del.dif)
|- ^+ acc.all
?~ del acc.all
$(del t.del, acc.all (~(del by acc.all) p.i.del))
::
++ can-join
|= {ali/plan-diff bob/plan-diff} ^- ?
?& !&(?=({{^ *} {^ *}} +<) !=(u.inf.ali u.inf.bob)) :: compatible info
=(~ (~(int by `(map knot *)`del.ali) put.bob)) :: no del-put
=(~ (~(int by `(map knot *)`put.ali) del.bob)) :: conflicts
.= (~(int by put.ali) put.bob) :: and all put
(~(int by put.bob) put.ali) :: values match
==
::
++ join
|= {ali/plan-diff bob/plan-diff}
^- (unit plan-diff)
?. (can-join ali bob)
~
%^ some
(mate inf.ali inf.bob)
(~(uni by del.ali) del.bob)
(~(uni by put.ali) put.bob)
--
--

View File

@ -1,26 +0,0 @@
::
:::: /hoon/x-collections-json/mar
::
/? 310
::
:::: compute
::
=, eyre
=, format
=, html
|_ jon/json
::
++ grow :: convert to
|%
++ mime [/application/json (as-octs:mimes txt)] :: convert to %mime
++ txt (crip (en-json jon))
--
++ grab
|% :: convert from
++ mime |=({p/mite q/octs} (fall (rush (@t q.q) apex:de-json) *json))
++ noun json :: clam from %noun
++ numb numb:enjs
++ time time:enjs
--
++ grad %mime
--

View File

@ -1,3 +0,0 @@
|_ a=json
++ grab |% ++ noun json
-- --

View File

@ -1,21 +0,0 @@
/? 310
|_ [hed=marl tal=marl]
++ grow
|%
++ mime
=< mime
|%
++ elem ;div:(h1:"*{hed}" div:"*{tal}") :: convert to %elem
++ hymn ;html:(head:title:"snip" body:"+{elem}") :: convert to %hymn
++ html (crip (en-xml:^html hymn)) :: convert to %html
++ mime [/text/html (as-octs:mimes:^html html)] :: convert to %mime
--
++ collections-snip [hed tal]
--
::
++ grab
|%
+$ noun [marl marl]
--
--

View File

@ -1,3 +0,0 @@
|_ a=manx
++ grab |% ++ noun manx
-- --

View File

@ -1,22 +0,0 @@
::
:::: /ren/collections/hoon
::
/? 309
/+ collections
::
:: collections:
::
:: get collection-config file at rendered path,
:: and all collections-item files the subpath.
:: outputs a +collection defined in /lib/collections/hoon
::
:: recursive renderer, see its counterpart in /ren/collections/item/hoon
::
/= collection
/^ collection:collections
/; |= [a=config:collections b=(map knot item:collections) ~]
[a b]
/. /collections-config/
/_ /collections-item/
==
collection

View File

@ -1,322 +0,0 @@
::
::::
::
/? 309
/+ collections, cram
/= gas /$ fuel:html
/= itm /collections-web-item/
::
::
/= collection-post
/: /===/web/landscape/collections/post /!noun/
::
=< (item-to-elem itm)
|%
++ item-to-elem
!:
|= itm=item:collections
^- manx
?< =(/collections/web s.bem.gas)
=/ sho (fall (~(get by qix.gas) %show) %default)
;div.container
;+
?+ -.itm !!
%error ;div: 404
::
%collection
?+ sho !!
::
%default
;div.row
;div.flex-col-2;
;div.flex-col-x
;div
;+ (meta-to-elem itm sho)
;+ (collection-to-elem col.itm)
==
==
;+ ?: =(type.meta.col.itm %blog)
;div.flex-col-5;
?: =(type.meta.col.itm %fora)
;div.flex-col-4;
;div.flex-col-4;
==
::
%post
;div.row
;div.flex-col-2;
;div.flex-col-x
;div
;+ (meta-to-elem itm sho)
;+ (collection-post ~ (flop s.bem.gas))
==
==
;div.flex-col-2;
==
==
:: %raw
::
%both
?+ sho !!
::
%default
;div.row
;div.flex-col-2;
;div.flex-col-x
;div
;+ (meta-to-elem itm sho)
;+ (both-to-elem col.itm raw.itm)
==
==
;div.flex-col-3;
==
::
%edit
;div.row
;div.flex-col-2;
;div.flex-col-x
;div
;+ (meta-to-elem itm sho)
;+ (collection-post `raw.itm (flop s.bem.gas))
==
==
;div.flex-col-2;
==
==
==
==
++ collection-to-elem
|= col=collection:collections
^- manx
;ul.vanilla
;* %+ roll
%+ sort ~(tap by data.col)
|= [[knot a=item:collections] [knot b=item:collections]]
=/ a-dat (extract-date-created a)
=/ b-dat (extract-date-created b)
(lth a-dat b-dat)
|= [[nom=knot ite=item:collections] out=marl]
^- marl
?: ?=(%error -.ite)
out
:_ out
^- manx
;li.collection-post.mt-6
;+ (item-to-snip nom ite)
==
==
::
++ raw-to-elem
|= raw=raw-item:collections
^- manx
=/ elm elm:(static:cram (ream data.raw))
=/ ht (hedtal:collections +.elm)
=/ title (fall (~(get by meta.raw) %name) -.s.bem.gas)
=/ date (fall (~(get by meta.raw) %date-created) 'missing date')
=/ author (fall (~(get by meta.raw) %author) 'anonymous')
::
;div.mb-18.mt-4
;+ elm
==
::
++ both-to-elem
|= [col=collection:collections raw=raw-item:collections]
^- manx
;div
;+ (raw-to-elem raw)
::
;div
;div.flex.align-center.mb-5
;div(urb-component "IconComment");
;div.ml-2.text-small.text-mono.text-600: {<~(wyt by data.col)>}
==
::
;ul.vanilla
;* %+ turn
%+ sort ~(tap by data.col)
|= [[knot a=item:collections] [knot b=item:collections]]
=/ a-dat (extract-date-created a)
=/ b-dat (extract-date-created b)
(lte a-dat b-dat)
|= [nom=knot ite=item:collections]
^- manx
?> ?=(%raw -.ite)
=/ author (fall (~(get by meta.raw.ite) %author) 'anonymous')
=/ host (fall (~(get by meta.raw.ite) %host) 'anonymous')
=/ date (fall (~(get by meta.raw.ite) %date-created) 'missing date')
;li.mb-6
;div.flex.align-center
;div.mr-2
=urb-component "Sigil"
=urb-ship "{(trip author)}"
=urb-size "18"
=urb-prefix "true";
;div
;a.vanilla.text-mono.text-small.text-700.mr-4
=href "/~~/{(trip host)}/==/web/landscape/profile"
; {(trip author)}
==
==
;div.text-host-breadcrumb
=urb-component "Elapsed"
=urb-timestring "{(trip date)}";
==
;div.collection-comment-content
;+ elm:(static:cram (ream data.raw.ite))
==
==
==
::
;div
=urb-component "CommentCreate"
=urb-pax "{<(flop s.bem.gas)>}"
=urb-ship "{(scow %p p.bem.gas)}";
==
==
::
++ extract-date-created
|= i=item:collections
^- @da
?- -.i
%error *@da
%collection date-created.meta.col.i
%both date-created.meta.col.i
%raw (slav %da (~(got by meta.raw.i) %date-created))
==
::
::
::
++ item-to-snip
|= [nom=knot itm=item:collections]
^- manx
?- -.itm
%error
;div: 404
%collection
(collection-to-snip nom col.itm)
%raw
(raw-to-snip nom raw.itm)
%both
(both-to-snip nom col.itm raw.itm)
==
::
++ collection-to-snip
|= [nom=knot col=collection:collections]
^- manx
=/ lnk=tape
"/~~/{(scow %p p.full-path.meta.col)}/=={(spud (flop (slag 1 s.full-path.meta.col)))}"
;div
;div.collection-date: {<date-created.meta.col>}
;h2.mt-0.mb-0
;a(href lnk): {(trip name.meta.col)}
==
;div.who.text-mono.text-600: {<author.meta.col>}
;div.meta-cont
;div.com-count.ml-12
; {(trip (scot %ud ~(wyt by data.col)))} comments
==
==
==
::
++ raw-to-snip
|= [nom=knot raw=raw-item:collections]
^- manx
=/ elm=manx elm:(static:cram (ream data.raw))
=/ ht (hedtal:collections +.elm)
=? tal.ht ?=(~ hed.ht)
(scag 5 c.elm)
=/ title (fall (~(get by meta.raw) %name) nom)
=/ date (fall (~(get by meta.raw) %date-created) 'missing date')
=/ author (fall (~(get by meta.raw) %author) 'anonymous')
=/ lnk=tape
"/~~/{(scow %p p.bem.gas)}/=={(spud (flop s.bem.gas))}/{(trip nom)}"
::
;div
;div.collection-date: {(trip date)}
;h2
;+ ?~ hed.ht
;a(href lnk): {(trip title)}
;a(href lnk): *{hed.ht}
==
;div.who.text-mono.text-600: {(trip author)}
;div.snippet
;* tal.ht
==
==
::
++ both-to-snip
|= [nom=knot col=collection:collections raw=raw-item:collections]
^- manx
=/ elm=manx elm:(static:cram (ream data.raw))
=/ ht (hedtal:collections +.elm)
=? tal.ht ?=(~ hed.ht)
(scag 5 c.elm)
=/ title (fall (~(get by meta.raw) %name) nom)
=/ lnk=tape
"/~~/{(scow %p p.bem.gas)}/=={(spud (flop s.bem.gas))}/{(trip nom)}"
::
;div
;div.collection-date: {<date-created.meta.col>}
;h2.mt-0.mb-0.text-500
;+ ?~ hed.ht
;a(href lnk): {(trip title)}
;a(href lnk): *{hed.ht}
==
;div.text-mono.text-small.text-300.mt-1.mb-1: {<author.meta.col>}
;div
;div.icon-label.justify-start
;div(urb-component "IconComment");
;div.ml-2
; {(trip (scot %ud ~(wyt by data.col)))}
==
==
==
==
::
++ meta-to-elem
|= [itm=item:collections sho=@tas]
^- manx
=/ mat=mart
:~ [%type "hidden"]
[%name "urb-metadata"]
[%urb-show (trip sho)]
[%urb-path (spud (flop s.bem.gas))]
==
:_ ~
:- %input
%+ weld mat
^- mart
?- -.itm
%error ~
%collection
=* met meta.col.itm
:~ [%urb-name (trip name.met)]
[%urb-author (scow %p author.met)]
[%urb-host (scow %p p.full-path.met)]
[%urb-date-created (scow %da date-created.met)]
[%urb-last-modified (scow %da last-modified.met)]
[%urb-content-type (trip type.met)]
[%urb-structure-type "collection-index"]
==
%raw
=/ met ~(got by meta.raw.itm)
:~ [%urb-name (trip (met %name))]
[%urb-author (trip (met %author))]
[%urb-host (trip (met %host))]
[%urb-date-created (trip (met %date-created))]
[%urb-last-modified (trip (met %last-modified))]
[%urb-content-type (trip (met %type))]
[%urb-structure-type "collection-post"]
==
%both
=/ met ~(got by meta.raw.itm)
:~ [%urb-name (trip (met %name))]
[%urb-author (trip (met %author))]
[%urb-host (trip (met %host))]
[%urb-date-created (trip (met %date-created))]
[%urb-last-modified (trip (met %last-modified))]
[%urb-content-type (trip (met %type))]
[%urb-structure-type "collection-post"]
==
==
--

View File

@ -1,56 +0,0 @@
::
:::: /ren/collections/item/hoon
::
/? 309
/+ collections
::
:: item:
::
:: render a collection-item at this path
:: outputs a +item defined in /lib/collections/hoon
::
:: recursive renderer, see its counterpart in /ren/collections/hoon
::
/= item
/^ item:collections
::
:: run a gate which checks if the output of the renderers below are null or not,
:: crash in the case that both are null
:: tag them with %collection, %raw, or %both for the 3 remaining permissible cases,
::
/; |= $: raw=?(~ raw-item:collections)
col=?(~ collection:collections)
~
==
?~ raw
?~ col
[%error ~]
[%collection col]
?~ col
[%raw raw]
[%both col raw]
::
:: run a pair of renderers
::
:: 1. get a .udon file together with its frontmatter, or else return ~
::
:: 2. run the collections renderer, if it fails return ~
:: (it fails if .collections-config file does not exist at this path)
::
/.
::
/| /; |= [a=(map knot cord) b=@t ~]
[%udon a b]
/. /front/
/udon/
==
/~ ~
==
::
/| /collections/
/~ ~
==
::
==
::
item

View File

@ -1,10 +0,0 @@
/? 309
/+ collections
/= gas /$ fuel:html
/= jon
/^ json
/; item-to-json:collections
::
/collections-web-item/
::
jon

View File

@ -1,50 +0,0 @@
/+ collections
/= gas /$ fuel:html
/= raw
/^ $@(~ raw-item:collections)
/| /; |= [a=(map knot cord) b=@t ~]
^- raw-item:collections
[%udon a b]
/. /front/
/udon/
==
::
/~ ~
==
::
/= col
/^ $@ ~
$% [%config config=config:collections items=(map knot item:collections) ~]
[%no-config items=(map knot item:collections) ~]
==
/| /. /~ %config
/collections-config/
/_ /collections-item/
==
::
/. /~ %no-config
/_ /collections-item/
==
::
/~ ~
==
::
::
^- item:collections
?~ col
?~ raw
[%error ~]
[%raw raw]
::
?: ?=(%no-config -.col)
?: =(s.bem.gas /collections/web)
?~ raw
[%collection *config:collections items.col]
[%both [*config:collections items.col] raw]
?~ raw
[%error ~]
[%raw raw]
?~ raw
[%collection config.col items.col]
[%both [config.col items.col] raw]

View File

@ -1,9 +0,0 @@
:: /!css/ in /===web/pack
::
:::: /hoon/css/ren
::
/? 310
/, /web/pack/css /!css/
/ /~ !!
==
-.-

View File

@ -1,9 +0,0 @@
:: /!js/ in /===web/pack
::
:::: /hoon/js/ren
::
/? 309
/, /web/pack/js /!js/
/ /~ !!
==
-.-

View File

@ -1,19 +0,0 @@
::
:::: /hoon/urb/ren
::
/? 309
/+ landscape
/= full-page
/^ manx
/|
/, /web/collections /; landscape /collections-elem/
/web/landscape /; landscape /!hymn/
/web/pages /| /!hymn/
/hymn/
==
/ /; landscape /!hymn/
==
::
/: /===/web/404 /; landscape /!hymn/
==
full-page

View File

@ -1,13 +0,0 @@
::
:::: /hoon/json/ren
::
/? 309
/= page
/^ json
/, /web/collections
/& json
/collections-json/
/
/!json/
==
page

View File

@ -1 +0,0 @@
|=(a=json a)

View File

@ -1,16 +0,0 @@
::
:: no snip view for collections, only items
::
/= snipped-udon
/& snip
/& elem
/udon/
^- manx
;div
;h1
;* hed.snipped-udon
==
;* tal.snipped-udon
==

View File

@ -1 +0,0 @@
|=(a=manx [*marl ~[a]])

View File

@ -1,12 +0,0 @@
::
:::: /hoon/elem/x-htm/ren
::
/? 309
/= page
/^ manx
/, /web/collections
/collections-elem/
/
/!hymn/
==
page

View File

@ -1 +0,0 @@
|=(a=manx a)

View File

@ -1,16 +0,0 @@
::
:::: /hoon/elem/x-urb/ren
::
/? 309
/= inner
/^ manx
/|
/, /web/collections /collections-elem/
/ /| /!hymn/
/hymn/
==
==
::
/: /===/web/404 /!hymn/
==
inner

View File

@ -1,14 +0,0 @@
:: Add tree chrome
::
:::: /hoon/wrap/urb/ren
::
/? 309
/+ landscape
/= wrapped
/^ $-(inr=manx out=manx)
/, /web/collections /~ landscape
/web/landscape /~ landscape
/web/pages /~ |=(manx +<)
/ /~ landscape
==
wrapped

View File

@ -1,185 +0,0 @@
:: https://developer.github.com/v3/
::
:: These types correspond to the types that Github's API
:: produces, so please check Github's documentation for
:: details.
::
:: For parsing JSON into these types, check out the gh-parse
:: library.
::
|%
++ repository
$: id/id
name/@t
full-name/@t
owner/user
private/?
html-url/@t
description/@t
fork/?
url/@t
forks-url/@t
keys-url/@t
collaborators-url/@t
teams-url/@t
hooks-url/@t
issue-events-url/@t
events-url/@t
assignees-url/@t
branches-url/@t
tags-url/@t
blobs-url/@t
git-tags-url/@t
git-refs-url/@t
trees-url/@t
statuses-url/@t
languages-url/@t
stargazers-url/@t
contributors-url/@t
subscribers-url/@t
subscription-url/@t
commits-url/@t
git-commits-url/@t
comments-url/@t
issue-comment-url/@t
contents-url/@t
compare-url/@t
merges-url/@t
archive-url/@t
downloads-url/@t
issues-urls/@t
pulls-url/@t
milestones-url/@t
notifications-url/@t
labels-url/@t
releases-url/@t
created-at/time
updated-at/time
pushed-at/time
git-url/@t
ssh-url/@t
clone-url/@t
svn-url/@t
homepage/json
size/@ud
stargazers-count/@ud
watchers-count/@ud
language/json
has-issues/?
has-downloads/?
has-wiki/?
has-pages/?
forks-count/@ud
mirror-url/json
open-issues-count/@ud
forks/@ud
open-issues/@ud
watchers/@ud
default-branch/@t
==
++ commit
$: sha/@t
url/@t
author/author
committer/author
message/@t
tree/point
parents/(list point)
verification/verification
==
++ user
$: login/@t
id/id
avatar-url/@t
gravatar-id/@t
url/@t
html-url/@t
followers-url/@t
following-url/@t
gists-url/@t
starred-url/@t
subscriptions-url/@t
organizations-url/@t
repos-url/@t
events-url/@t
received-events/@t
type/@t
site-admin/?
==
++ issue
$: raw/json
url/@t
labels-url/@t
comments-url/@t
events-url/@t
html-url/@t
id/id
number/@ud
title/@t
user/user
labels/(list label)
state/@t
locked/?
assignee/(unit user)
milestone/json
comments/@ud
created-at/time
updated-at/time
closed-at/(unit time)
body/@t
==
++ author
$: date/@t
name/@t
email/@t
==
++ point
$: url/@t
sha/@t
==
++ verification
$: verified/?
reason/@t
signature/(unit @t)
payload/(unit @t)
==
++ label
$: url/@t
name/@t
color/@t
==
++ comment
$: url/@t
html-url/@t
issue-url/@t
id/id
user/user
created-at/time
updated-at/time
body/@t
==
++ id @t
++ time @t
++ issues
$: repository/repository
sender/user
$= action
$% {$assigned assignee/user}
{$unassigned assignee/user}
{$labeled label/label}
{$unlabeled label/label}
{$opened ~}
{$closed ~}
{$reopened ~}
==
issue/issue
==
++ issue-comment
$: repository/repository
sender/user
action/@t
issue/issue
comment/comment
==
++ ping {repo/json sender/json hok/(list @t) hook-id/@t zen/json}
--

View File

@ -1 +0,0 @@
{usr/knot url/(unit purf:eyre)}

View File

@ -1,2 +0,0 @@
/- plan-acct
{inf/(unit {@txname @txloc}) del/(map knot ~) put/(map knot plan-acct)}

View File

@ -1,97 +0,0 @@
/+ *test, collections
::
/= app /: /===/app/collections /!noun/
/= gall-vane /: /===/sys/vane/gall /!noun/
::
=, gall
=>
|%
++ gall-args [~1234.5.7 0vagine *slyt]
::
++ hype
|= tak=task:able:gall
^- (hypo (hobo task:able:gall))
[-:!>(tak) tak]
::
++ gall-gate (gall-vane !>(..zuse))
--
::
|%
::
++ test-prep
=/ prep-bone 20
=/ our-ship ~marzod
=/ bol
%* . *bowl:gall
our our-ship
ost prep-bone
==
::
=/ moves -:(~(prep app bol *state:collections) ~)
;: weld
%+ expect-eq
!> %- sort
:_ aor
^- (list move:collections)
:~ :* prep-bone %poke /col-hall-action [our-ship %hall]
%hall-action %create %c 'collections' %journal
==
::
:* prep-bone %poke /col-hall-action [our-ship %hall]
%hall-action %source %inbox & (sy [[our-ship %c] ~]~)
==
::
:* prep-bone %peer /circles [our-ship %hall]
/circles/[(scot %p our-ship)]
==
::
:* prep-bone %peer /inbox [our-ship %hall]
/circle/inbox/config/grams
==
::
:* prep-bone %peer /invites [our-ship %hall]
/circle/i/grams
==
==
!> (sort moves aor)
::
=. our-ship ~davtyr-nimren
=. bol bol(our our-ship)
::
=/ moves -:(~(prep app bol *state:collections) ~)
%+ expect-eq
!> %- sort
:_ aor
^- (list move:collections)
:~ :* prep-bone %poke /col-hall-action [our-ship %hall]
%hall-action %create %c 'collections' %journal
==
::
:* prep-bone %poke /col-hall-action [our-ship %hall]
%hall-action %source %inbox & (sy [[our-ship %c] ~]~)
==
::
:* prep-bone %peer /circles [our-ship %hall]
/circles/[(scot %p our-ship)]
==
::
:* prep-bone %peer /inbox [our-ship %hall]
/circle/inbox/config/grams
==
::
:* prep-bone %peer /invites [our-ship %hall]
/circle/i/grams
==
::
==
!> (sort moves aor)
==
::
::++ test-load-app
:: =/ gall-door (gall-gate gall-args)
:: =/ init (call:gall-door [/test]~ (hype %init ~marzod))
:: %+ expect-eq
:: !>
:: !>
::
--

View File

@ -1,5 +0,0 @@
^- manx
;meta(http-equiv "refresh", content "0; url=/~~/landscape");
;script(type "text/javascript")
; window.location = "/~~/landscape"
==

View File

@ -1,4 +0,0 @@
::
:::: /hoon/404/web
::
;div.urb-404-page: 404

View File

@ -1,27 +0,0 @@
:: Console front-end
::
:::: /hoon/dojo/web
::
/? 310
|%
++ cdnj |=(a/tape ;script(src "//cdnjs.cloudflare.com/ajax/libs/{a}");)
--
::
::::
::
^- manx
;module
=nav_title "Dojo"
=nav_no-dpad ""
=nav_no-sibs ""
;script(src "//cdnjs.cloudflare.com/ajax/libs/mousetrap/1.4.6/mousetrap.js");
;style:'''
#term { width: 100%; }
#term * { margin: 0px; }
.module pre { margin-bottom: 0; }
'''
;div#err;
;div#term:""
;script@"/lib/js/sole.js";
;sole(appl "dojo");
==

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
.CodeMirror {
height: 100%
}
.cm-s-default .cm-atom {color: #70f}
.cm-s-default .cm-operator {color: #097}

View File

@ -1,14 +0,0 @@
input.red {
background: hsl(0, 100%, 60%);
}
form.inline {
display: inline;
}
.edit-toggle:checked ~ .edit-off {
display: none;
}
.edit-toggle:not(:checked) ~ .edit-on {
display: none;
}

View File

@ -1,84 +0,0 @@
@font-face {
font-family: "bau";
src: url("//media.urbit.org/fonts/bau.woff");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "bau";
src: url("//media.urbit.org/fonts/bau-italic.woff");
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: "bau";
src: url("//media.urbit.org/fonts/bau-medium.woff");
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: "bau";
src: url("//media.urbit.org/fonts/bau-mediumitalic.woff");
font-weight: 500;
font-style: italic;
}
@font-face {
font-family: "bau";
src: url("//media.urbit.org/fonts/bau-bold.woff");
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: "bau";
src: url("//media.urbit.org/fonts/bau-bolditalic.woff");
font-weight: 600;
font-style: italic;
}
@font-face {
font-family: "bau";
src: url("//media.urbit.org/fonts/bau-super.woff");
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: "bau";
src: url("//media.urbit.org/fonts/bau-superitalic.woff");
font-weight: 600;
font-style: italic;
}
@font-face {
font-family: "scp";
src: url("//media.urbit.org/fonts/scp-extralight.woff");
font-weight: 200;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("//media.urbit.org/fonts/scp-light.woff");
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("//media.urbit.org/fonts/scp-regular.woff");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("//media.urbit.org/fonts/scp-medium.woff");
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("//media.urbit.org/fonts/scp-bold.woff");
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: "scp";
src: url("//media.urbit.org/fonts/scp-black.woff");
font-weight: 700;
font-style: normal;
}

View File

@ -1,47 +0,0 @@
//REVIEW this feels too complicated
let match_url_end = (pattern,out={})=> {
if(!pattern) return out
let here = document.location.pathname.split("/").reverse()
while(!here[0]) here.shift()
for(let segment of pattern.split("/").reverse()){
let val = here.shift()
if(segment[0] != ":") continue //REVIEW check for match?
out[segment.slice(1)] = val
}
return out
}
//
window.easy_form = {
submit: (form)=> {
const param = (key)=> {
var x = form.elements[`easy_form:${key}`]
return x && x.value
}
let mark = param("mark")
if(!mark) throw new TypeError("Need a mark")
let appl = param("appl") || mark.match(/^[^-]*/)[0]
let tag = param("tag")
//
if(param("confirm") != null && !confirm("Are you sure?"))
return false
//
let req = {}
req = match_url_end(param("url_end"),req)
//
for (let [k,v] of new FormData(form)){
if(!/^easy_form:/.test(k)) {
req[k] = v
}
}
if(tag) req = {[tag]:req}
fetch("/~/auth.json", {credentials: "same-origin"})
.then((res)=>res.json())
.then(({oryx})=> fetch(`/~/to/${appl}/${mark}`,{
method: "POST",
body:JSON.stringify({oryx,wire:"/",xyro:req}),
credentials: "same-origin"
}))
return false
}
}

View File

@ -1,164 +0,0 @@
CodeMirror.defineMode("hoon", function() {
glyph = /[+\-|$%:.#^~;=?!_,&\/<>%*]/
term = /^[$&|]|^[a-z]([a-z0-9\-]*[a-z0-9])?/
num = /~[a-z0-9._~-]+|-?-?^[0-9]([0-9.]*|[xwbv]?[0-9a-zA-Z.-~]*)/
res = {}
res.startState = function(){return {soblock: false, doqblock:false, sail:false, space:true}}
var propOrVar = function(c){
if(c == '.')
return 'property'
return 'variable'
}
res.token = function(stream, state){
if(state.soqblock && stream.sol()){
if(stream.match(/\s*'''/)){
state.soqblock = false
}
else {
stream.skipToEnd()
}
return "string"
}
if(state.doqblock){
if(stream.match(/\s*"""/)){
state.doqblock = false
}
else {
stream.skipToEnd()
}
return "string"
}
if(stream.sol())
state.space = true
if(state.sail){
if(stream.peek().match(/[^#./() ]/)||stream.eol()){
state.sail = false
if(stream.match(/:? /)){
stream.skipToEnd()
return 'string'
}
if(stream.match(term))
state.sail = true
return;
if(stream.match(':'))
state.sail = true
return 'operator'
}
}
if(stream.match("'")){
if(stream.match("''")){
state.soqblock = true
return 'string'
}
while(stream.match(/^[^'\\]/) || stream.match(/\\./));
stream.eat("'")
return 'string'
}
if(stream.match('"')){
if(stream.match('""')){
state.doqblock = true
stream.skipToEnd()
return 'string'
}
while(stream.match(/^[^"\\]/) || stream.match(/\\./));
stream.eat('"')
return 'string'
}
if(stream.match(' ;')){
if(stream.eat(' ')){
stream.skipToEnd()
return 'string'
}
if(!stream.match(glyph)){
state.sail = true
}
return 'builtin'
}
if(stream.match('::')){
stream.skipToEnd()
return 'comment'
}
if(stream.match('++ ') || stream.match('+- ')){
stream.match(term)
return 'header'
}
if(state.space && stream.match('--')){
if(stream.eat(glyph) || stream.eat(/[a-z0-9]/))
stream.backUp(3)
else return 'header'
}
if(stream.match(/^@[a-z]*[A-Z]?/))
return 'atom'
if(stream.match(num))
return 'number'
if(stream.eat(/[%$]/))
if(stream.match(term) || stream.match(num) || stream.match('~'))
return 'tag'
else stream.backUp(1)
if(state.space && stream.match('==')){
return 'tag'
}
if(stream.eat('~')){
if(/[()]/.exec(stream.peek()))
return 'builtin'
return 'tag'
}
if(stream.eat(/[+\-]/)){
while(stream.eat(/[<>]/) && stream.eat(/[+\-]/));
return propOrVar(stream.peek())
}
if(stream.eat('`')){
state.space = false
return 'operator'
}
if(stream.sol() && stream.eatWhile(glyph)){
state.space = false
return 'builtin'
}
if(stream.eat(glyph)){
state.space = false
stream.backUp(2)
if(stream.eat(/[ ([{]/) || (stream.peek().match(/[^+\-<>]/)
&& stream.eat(glyph))){ // expression start
stream.eatWhile(glyph)
return 'builtin'
}
stream.next()
if(state.space && stream.eat('=')){
if(/[()]/.exec(stream.peek()))
return 'builtin'
return 'operator'
}
if(stream.eat(/[=:.^/]/))
return 'operator'
stream.next()
return 'builtin'
}
if(stream.match(term)){
if(state.space && stream.match('+'))
return 'tag'
state.space = false
return propOrVar(stream.peek())
}
if(stream.eat(/[ \[({]/)){
state.space = true
return
}
stream.next()
}
res.lineComment = '::'
res.fold = "indent"
return res
});
CodeMirror.defineMIME("text/x-hoon", "hoon");

View File

@ -1,787 +0,0 @@
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var Matr, Prompt, Share, TreeActions, buffer, div, pre, recl, ref, ref1, rele, span, str, u,
slice = [].slice,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
ref = [React.createClass, React.createElement], recl = ref[0], rele = ref[1];
ref1 = React.DOM, div = ref1.div, u = ref1.u, pre = ref1.pre, span = ref1.span;
TreeActions = window.tree.actions;
str = JSON.stringify;
Share = require("./share.coffee");
buffer = {
"": new Share("")
};
Prompt = recl({
displayName: "Prompt",
render: function() {
var buf, cur, pro, ref2, ref3;
pro = (ref2 = this.props.prompt[this.props.appl]) != null ? ref2 : "X";
cur = this.props.cursor;
buf = this.props.input + " ";
return pre({}, this.props.appl + pro, span({
style: {
background: 'lightgray'
}
}, buf.slice(0, cur), u({}, (ref3 = buf[cur]) != null ? ref3 : " "), buf.slice(cur + 1)));
}
});
Matr = recl({
displayName: "Matr",
render: function() {
var lines;
lines = this.props.rows.map(function(lin, key) {
return pre({
key: key
}, lin, " ");
});
lines.push(rele(Prompt, {
key: "prompt",
appl: this.props.appl,
prompt: this.props.prompt,
input: this.props.input,
cursor: this.props.cursor
}));
return div({}, lines);
}
});
TreeActions.registerComponent("sole", recl({
displayName: "Sole",
getInitialState: function() {
return {
rows: [],
appl: this.props.appl,
prompt: {
"": "# "
},
input: "",
cursor: 0,
history: [],
offset: 0,
error: ""
};
},
render: function() {
return div({}, div({
id: "err"
}, this.state.error), rele(Matr, this.state));
},
flash: function($el, background) {
$el.css({
background: background
});
if (background) {
return setTimeout(((function(_this) {
return function() {
return _this.flash($el, '');
};
})(this)), 50);
}
},
bell: function() {
return this.flash($('body'), 'black');
},
choose: function(appl) {
if (buffer[appl] == null) {
buffer[appl] = new Share("");
}
this.updPrompt('', null);
return this.setState({
appl: appl,
cursor: 0,
input: buffer[appl].buf
});
},
print: function(txt) {
return this.setState({
rows: slice.call(this.state.rows).concat([txt])
});
},
sync: function(ted, app) {
var b;
if (app == null) {
app = this.state.appl;
}
if (app === this.state.appl) {
b = buffer[app];
return this.setState({
input: b.buf,
cursor: b.transpose(ted, this.state.cursor)
});
}
},
updPrompt: function(app, pro) {
var prompt;
prompt = $.extend({}, this.state.prompt);
if (pro != null) {
prompt[app] = pro;
} else {
delete prompt[app];
}
return this.setState({
prompt: prompt
});
},
sysStatus: function() {
var app, k, pro, ref2, v;
return this.updPrompt('', ((ref2 = [
this.state.appl, (function() {
var ref2, results;
ref2 = this.state.prompt;
results = [];
for (k in ref2) {
v = ref2[k];
if (k !== '') {
results.push(k);
}
}
return results;
}).call(this)
], app = ref2[0], pro = ref2[1], ref2), app === '' ? (pro.join(', ')) + '# ' : null));
},
peer: function(ruh, app) {
var mapr, v;
if (app == null) {
app = this.state.appl;
}
if (ruh.map) {
return ruh.map((function(_this) {
return function(rul) {
return _this.peer(rul, app);
};
})(this));
}
mapr = this.state;
switch (Object.keys(ruh)[0]) {
case 'txt':
return this.print(ruh.txt);
case 'tan':
return ruh.tan.split("\n").map(this.print);
case 'pro':
return this.updPrompt(app, ruh.pro.cad);
case 'hop':
this.setState({
cursor: ruh.hop
});
return this.bell();
case 'blk':
return console.log("Stub " + (str(ruh)));
case 'det':
buffer[app].receive(ruh.det);
return this.sync(ruh.det.ted, app);
case 'act':
switch (ruh.act) {
case 'clr':
return this.setState({
rows: []
});
case 'bel':
return this.bell();
case 'nex':
return this.setState({
input: "",
cursor: 0,
history: !mapr.input ? mapr.history : [mapr.input].concat(slice.call(mapr.history)),
offset: 0
});
}
break;
default:
v = Object.keys(ruh);
return console.log(v, ruh[v[0]]);
}
},
join: function(app) {
if (this.state.prompt[app] != null) {
return this.print('# already-joined: ' + app);
}
this.choose(app);
return urb.bind("/sole", {
appl: this.state.appl,
wire: "/"
}, (function(_this) {
return function(err, d) {
if (err) {
return console.log(err);
} else if (d.data) {
return _this.peer(d.data, app);
}
};
})(this));
},
cycle: function() {
var apps, ref2;
apps = Object.keys(this.state.prompt);
if (apps.length < 2) {
return;
}
return this.choose((ref2 = apps[1 + apps.indexOf(this.state.appl)]) != null ? ref2 : apps[0]);
},
part: function(appl) {
var mapr;
mapr = this.state;
if (mapr.prompt[appl] == null) {
return this.print('# not-joined: ' + appl);
}
urb.drop("/sole", {
appl: appl,
wire: "/"
});
if (appl === mapr.appl) {
this.cycle();
}
this.updPrompt(appl, null);
return this.sysStatus();
},
componentWillUnmount: function() {
return this.mousetrapStop();
},
componentDidMount: function() {
this.mousetrapInit();
return this.join(this.state.appl);
},
sendAction: function(data) {
var app, appl;
appl = this.state.appl;
if (appl) {
return urb.send(data, {
appl: appl,
mark: 'sole-action'
}, (function(_this) {
return function(e, res) {
if (res.status !== 200) {
return _this.setState({
error: res.data.mess
});
}
};
})(this));
} else if (data === 'ret') {
app = /^[a-z-]+$/.exec(buffer[""].buf.slice(1));
if (!((app != null) && (app[0] != null))) {
return this.bell();
} else {
switch (buffer[""].buf[0]) {
case '+':
this.doEdit({
set: ""
});
return this.join(app[0]);
case '-':
this.doEdit({
set: ""
});
return this.part(app[0]);
default:
return this.bell();
}
}
}
},
doEdit: function(ted) {
var det;
det = buffer[this.state.appl].transmit(ted);
this.sync(ted);
return this.sendAction({
det: det
});
},
eatKyev: function(mod, key) {
var _, appl, cha, cursor, history, input, mapr, n, offset, prev, ref2, ref3, rest;
mapr = this.state;
switch (mod.sort().join('-')) {
case '':
case 'shift':
if (key.str) {
this.doEdit({
ins: {
cha: key.str,
at: mapr.cursor
}
});
this.setState({
cursor: mapr.cursor + 1
});
}
switch (key.act) {
case 'entr':
return this.sendAction('ret');
case 'up':
history = mapr.history.slice();
offset = mapr.offset;
if (history[offset] === void 0) {
return;
}
ref2 = [history[offset], mapr.input], input = ref2[0], history[offset] = ref2[1];
offset++;
this.doEdit({
set: input
});
return this.setState({
offset: offset,
history: history,
cursor: input.length
});
case 'down':
history = mapr.history.slice();
offset = mapr.offset;
offset--;
if (history[offset] === void 0) {
return;
}
ref3 = [history[offset], mapr.input], input = ref3[0], history[offset] = ref3[1];
this.doEdit({
set: input
});
return this.setState({
offset: offset,
history: history,
cursor: input.length
});
case 'left':
if (mapr.cursor > 0) {
return this.setState({
cursor: mapr.cursor - 1
});
}
break;
case 'right':
if (mapr.cursor < mapr.input.length) {
return this.setState({
cursor: mapr.cursor + 1
});
}
break;
case 'baxp':
if (mapr.cursor > 0) {
return this.doEdit({
del: mapr.cursor - 1
});
}
}
break;
case 'ctrl':
switch (key.str || key.act) {
case 'a':
case 'left':
return this.setState({
cursor: 0
});
case 'e':
case 'right':
return this.setState({
cursor: mapr.input.length
});
case 'l':
return this.setState({
rows: []
});
case 'entr':
return this.bell();
case 'w':
return this.eatKyev(['alt'], {
act: 'baxp'
});
case 'p':
return this.eatKyev([], {
act: 'up'
});
case 'n':
return this.eatKyev([], {
act: 'down'
});
case 'b':
return this.eatKyev([], {
act: 'left'
});
case 'f':
return this.eatKyev([], {
act: 'right'
});
case 'g':
return this.bell();
case 'x':
return this.cycle();
case 'v':
appl = mapr.appl !== '' ? '' : this.state.appl;
this.setState({
appl: appl,
cursor: 0,
input: buffer[appl].buf
});
return this.sysStatus();
case 't':
if (mapr.cursor === 0 || mapr.input.length < 2) {
return this.bell();
}
cursor = mapr.cursor;
if (cursor < mapr.input.length) {
cursor++;
}
this.doEdit([
{
del: cursor - 1
}, {
ins: {
at: cursor - 2,
cha: mapr.input[cursor - 1]
}
}
]);
return this.setState({
cursor: cursor
});
case 'u':
this.yank = mapr.input.slice(0, mapr.cursor);
return this.doEdit((function() {
var i, ref4, results;
results = [];
for (n = i = 1, ref4 = mapr.cursor; 1 <= ref4 ? i <= ref4 : i >= ref4; n = 1 <= ref4 ? ++i : --i) {
results.push({
del: mapr.cursor - n
});
}
return results;
})());
case 'k':
this.yank = mapr.input.slice(mapr.cursor);
return this.doEdit((function() {
var i, ref4, ref5, results;
results = [];
for (_ = i = ref4 = mapr.cursor, ref5 = mapr.input.length; ref4 <= ref5 ? i < ref5 : i > ref5; _ = ref4 <= ref5 ? ++i : --i) {
results.push({
del: mapr.cursor
});
}
return results;
})());
case 'y':
return this.doEdit((function() {
var i, len, ref4, ref5, results;
ref5 = (ref4 = this.yank) != null ? ref4 : '';
results = [];
for (n = i = 0, len = ref5.length; i < len; n = ++i) {
cha = ref5[n];
results.push({
ins: {
cha: cha,
at: mapr.cursor + n
}
});
}
return results;
}).call(this));
default:
return console.log(mod, str(key));
}
break;
case 'alt':
switch (key.str || key.act) {
case 'f':
case 'right':
rest = mapr.input.slice(mapr.cursor);
rest = rest.match(/\W*\w*/)[0];
return this.setState({
cursor: mapr.cursor + rest.length
});
case 'b':
case 'left':
prev = mapr.input.slice(0, mapr.cursor);
prev = prev.split('').reverse().join('');
prev = prev.match(/\W*\w*/)[0];
return this.setState({
cursor: mapr.cursor - prev.length
});
case 'baxp':
prev = mapr.input.slice(0, mapr.cursor);
prev = prev.split('').reverse().join('');
prev = prev.match(/\W*\w*/)[0];
this.yank = prev;
return this.doEdit((function() {
var i, len, results;
results = [];
for (n = i = 0, len = prev.length; i < len; n = ++i) {
_ = prev[n];
results.push({
del: mapr.cursor - 1 - n
});
}
return results;
})());
}
break;
default:
return console.log(mod, str(key));
}
},
mousetrapStop: function() {
return Mousetrap.handleKey = this._defaultHandleKey;
},
mousetrapInit: function() {
this._defaultHandleKey = Mousetrap.handleKey;
return Mousetrap.handleKey = (function(_this) {
return function(char, mod, e) {
var chac, key, norm, ref2;
norm = {
capslock: 'caps',
pageup: 'pgup',
pagedown: 'pgdn',
backspace: 'baxp',
enter: 'entr'
};
key = (function() {
var ref2;
switch (false) {
case char.length !== 1:
if (e.type === 'keypress') {
chac = char.charCodeAt(0);
if (chac < 32) {
char = String.fromCharCode(chac | 96);
}
return {
str: char
};
}
break;
case e.type !== 'keydown':
if (char !== 'space') {
return {
act: (ref2 = norm[char]) != null ? ref2 : char
};
}
break;
case !(e.type === 'keyup' && norm[key] === 'caps'):
return {
act: 'uncap'
};
}
})();
if (!key) {
return;
}
if (key.act && (ref2 = key.act, indexOf.call(mod, ref2) >= 0)) {
return;
}
e.preventDefault();
return _this.eatKyev(mod, key);
};
})(this);
}
}));
},{"./share.coffee":2}],2:[function(require,module,exports){
var clog, str;
str = JSON.stringify;
clog = function(a) {
return console.log(a);
};
module.exports = (function() {
function exports(buf, ven, leg) {
this.buf = buf != null ? buf : "";
this.ven = ven != null ? ven : [0, 0];
this.leg = leg != null ? leg : [];
}
exports.prototype.abet = function() {
return {
buf: this.buf,
leg: this.leg.slice(),
ven: this.ven.slice()
};
};
exports.prototype.apply = function(ted) {
var at, cha, ref;
switch (false) {
case 'nop' !== ted:
break;
case !ted.map:
return ted.map(this.apply, this);
default:
switch (Object.keys(ted)[0]) {
case 'set':
return this.buf = ted.set;
case 'del':
return this.buf = this.buf.slice(0, ted.del) + this.buf.slice(ted.del + 1);
case 'ins':
ref = ted.ins, at = ref.at, cha = ref.cha;
return this.buf = this.buf.slice(0, at) + cha + this.buf.slice(at);
default:
throw "%sole-edit -lost." + (str(ted));
}
}
};
exports.prototype.transmute = function(sin, dex) {
var at, cha, ref;
switch (false) {
case !(sin === 'nop' || dex === 'nop'):
return dex;
case !sin.reduce:
return sin.reduce(((function(_this) {
return function(dex, syn) {
return _this.transmute(syn, dex);
};
})(this)), dex);
case !dex.map:
return dex.map((function(_this) {
return function(dax) {
return _this.transmute(sin, dax);
};
})(this));
case dex.set === void 0:
return dex;
default:
switch (Object.keys(sin)[0]) {
case 'set':
return 'nop';
case 'del':
if (sin.del === dex.del) {
return 'nop';
}
dex = $.extend(true, {}, dex);
switch (Object.keys(dex)[0]) {
case 'del':
if (sin.del < dex.del) {
dex.del--;
}
break;
case 'ins':
if (sin.del < dex.ins.at) {
dex.ins.at--;
}
}
return dex;
case 'ins':
dex = $.extend(true, {}, dex);
ref = sin.ins, at = ref.at, cha = ref.cha;
switch (Object.keys(dex)[0]) {
case 'del':
if (at < dex.del) {
dex.del++;
}
break;
case 'ins':
if (at < dex.ins.at || (at === dex.ins.at && !(cha <= dex.ins.cha))) {
dex.ins.at++;
}
}
return dex;
default:
throw "%sole-edit -lost." + (str(sin));
}
}
};
exports.prototype.commit = function(ted) {
this.ven[0]++;
this.leg.push(ted);
return this.apply(ted);
};
exports.prototype.inverse = function(ted) {
switch (false) {
case 'nop' !== ted:
return ted;
case !ted.map:
return ted.map((function(_this) {
return function(tad) {
var res;
res = _this.inverse(tad);
_this.apply(tad);
return res;
};
})(this)).reverse();
default:
switch (Object.keys(ted)[0]) {
case 'set':
return {
set: this.buf
};
case 'ins':
return {
del: ted.ins
};
case 'del':
return {
ins: {
at: ted.del,
cha: this.buf[ted.del]
}
};
default:
throw "%sole-edit -lost." + (str(ted));
}
}
};
exports.prototype.receive = function(arg) {
var dat, ler, ted;
ler = arg.ler, ted = arg.ted;
if (!(ler[1] === this.ven[1])) {
throw "-out-of-sync.[" + (str(ler)) + " " + (str(this.ven)) + "]";
}
this.leg = this.leg.slice(this.leg.length + ler[0] - this.ven[0]);
dat = this.transmute(this.leg, ted);
this.ven[1]++;
this.apply(dat);
return dat;
};
exports.prototype.remit = function() {
throw 'stub';
};
exports.prototype.transmit = function(ted) {
var act;
act = {
ted: ted,
ler: [this.ven[1], this.ven[0]]
};
this.commit(ted);
return act;
};
exports.prototype.transceive = function(arg) {
var dat, ler, old, ted;
ler = arg.ler, ted = arg.ted;
old = new Share(this.buf);
dat = this.receive({
ler: ler,
ted: ted
});
return old.inverse(dat);
};
exports.prototype.transpose = function(ted, pos) {
var ref;
if (pos === void 0) {
return this.transpose(this.leg, ted);
} else {
return ((ref = (this.transmute(ted, {
ins: {
at: pos
}
})).ins) != null ? ref : {
at: 0
}).at;
}
};
return exports;
})();
},{}]},{},[1]);

View File

@ -1,328 +0,0 @@
window.urb = window.urb || {}
window.urb.appl = window.urb.appl || null
window.urb.init = function(onload){ // XX proper class?
onload = onload || function(){}
var $init = this.init
if($init.loaded) return onload()
if($init.loading) return $init.loading.push(onload)
$init.loading = [onload]
var s = document.createElement('script')
s.src = "/~/at/~/auth.js" // XX nop.js? auth.json?
s.onload = function(){
$init.loading.map(function(f){f()})
delete $init.loading
$init.loaded = true
}
document.body.appendChild(s)
}
window.urb.init.loaded = window.urb.oryx
window.urb.req = function(method,url,params,json,cb) {
var xhr = new XMLHttpRequest()
method = method.toUpperCase()
if(method == "PUT" || method == "DELETE")
xhr.open("POST", url+"?"+method)
else xhr.open(method, url)
if(json)
xhr.setRequestHeader("content-type", "text/json")
xhr.timeout = 60000
if(!window.urb.oryx) throw "No CSRF token" // XX fetch auth.json
_data = {oryx: window.urb.oryx}
if(params.xyro) { _data.xyro = params.xyro; }
if(params.ship) { _data.ship = params.ship; }
if(params.path) { _data.path = params.path; }
if(params.appl) { _data.appl = params.appl; }
if(params.mark) { _data.mark = params.mark; }
if(params.wire) { _data.wire = params.wire; }
if(cb) {
xhr.onload = function() {
var err,res
try {
err = null
res = {
status:this.status,
data: JSON.parse(this.responseText)
}
if(res.data.reload)
res.reload = res.data.reload
} catch(e) {
// if(urb.wall !== false) document.write(this.responseText) // XX
err = {
message:"Failed to parse JSON",
raw:this.responseText
}
res = null
}
finally {
cb(err,res)
}
}
xhr.ontimeout = function() {
cb({
status:408,
data:null
})
}
xhr.onerror = function() {
cb({
status:this.status,
data:this.responseText
})
}
}
xhr.send(JSON.stringify(_data))
}
// window.urb.getJSON = function(url,cb){ window.urb.reqJSON("GET",url, null, cb)}
// window.urb.reqJSON = function(method, url, data, cb){
// var xhr = new XMLHttpRequest()
// xhr.open(method, url)
// xhr.onload = function(){
// urb.fetchTag.call(xhr)
// if(cb) cb(JSON.parse(xhr.responseText))
// }
// xhr.send(data === null ? null : JSON.stringify(data))
// }
window.urb.reqq = []
window.urb.qreq = function(method,url,params,json,cb) {
walk = function() {
qobj = {}
qobj.oargs = window.urb.reqq[0]
qobj.nargs = [].slice.call(qobj.oargs,0,4)
qobj.nargs.push(function(){
if(this.oargs[4])
this.oargs[4].apply(window.urb,arguments)
window.urb.reqq.shift()
if(window.urb.reqq.length > 0)
walk()
}.bind(qobj))
window.urb.req.apply(this,qobj.nargs)
}
l = window.urb.reqq.length
window.urb.reqq.push(arguments);
if(l == 0) { walk() }
}
window.urb.send = function(data,params,cb) { // or send(data, cb)
if(!params || typeof params === "function")
{cb = params; params = {}}
var url, $send
$send = this.send
params.data = data
params.ship = params.ship || this.ship
params.appl = params.appl || this.appl
params.mark = params.mark || $send.mark
// params.seqn = params.seqn || $send.seqn
params.wire = params.wire || "/"
params.xyro = (typeof(params.data) === 'undefined') ? null : params.data
if(!params.mark) throw new Error("You must specify a mark for urb.send.")
if(!params.appl) throw new Error("You must specify an appl for urb.send.")
url = ["to",params.appl,params.mark]
url = "/~/"+url.join("/")
// $send.seqn++
this.qreq('post',url,params,true,function(err,data) {
/* if(err) { $send.seqn--; }
else */ if(data && data.data.fail && urb.wall !== false && params.wall !== false) {
document.location = "#ERROR"
document.write("<pre>"+JSON.stringify(params.xyro)+"\n"
+data.data.mess+"</pre>") // XX
}
if(cb) { cb.apply(this,arguments); }
})
}
// window.urb.send.seqn = 0
window.urb.send.mark = "json"
window.urb.gsig = function(params) {
var path = params.path
if(!path) path = ""
if(path[0] !== "/") path = "/"+path
return "~"+params.ship+"/"+
params.appl+
path.replace(/[^\x00-\x7F]/g, "")
}
window.urb.puls = false
window.urb.cabs = {}
window.urb.poll = function(params) {
if(!params) throw new Error("You must supply params to urb.poll.")
var url, $this
seqn = this.poll.seqn
if(params.seqn) seqn = params.seqn()
url = "/~/of/"+this.ixor+"?poll="+seqn
this.puls = true
$this = this
this.req("get",url,params,true,function(err,res) {
$this.poll.dely = params.dely || $this.poll.dely
if(res){
if(res.data.beat) {
$this.poll.dely = params.dely || 250
return $this.poll(params)
}
switch(res.data.type){
case "news":
return document.location.reload() // XX check autoreload
case "rush":
case "mean":
var err2 = err
if(res.data.type == "mean")
err2 = res.data.data
var fn = $this.gsig(res.data.from)
if($this.cabs[fn])
$this.cabs[fn].call(this,err2,
{status: res.status, data: res.data.data.json}) // XX non-json
break;
case "quit":
// XX necessary behaviour?
break;
default:
throw new Error("Lost event %"+res.data.type)
}
if(params.incs)
params.incs()
else
$this.poll.seqn++
$this.poll.dely = 250
return $this.poll(params)
}
else if(err){
setTimeout(function() {
$this.poll(params)
}, $this.poll.dely)
$this.poll.dely += Math.ceil($this.poll.dely*.2)
}
else throw "Neither error nor result on poll"
})
}
window.urb.poll.seqn = 1
window.urb.poll.dely = 250
window.urb.bind = function(path, params, cb, nicecb){ // or bind(path, cb)
if(!params || typeof params === "function")
{cb = params; params = {}}
params.path = path
if(params.path[0] !== "/") params.path = "/"+params.path
params.ship = params.ship || this.ship
params.appl = params.appl || this.appl
params.mark = params.mark || this.bind.mark
params.wire = params.wire || params.path
if(typeof path != "string")
throw new Error("You must specify a string path for urb.bind.")
if(!params.appl) throw new Error("You must specify an appl for urb.bind.")
if(!cb) throw new Error("You must supply a callback to urb.bind.")
var method, perm, url, $this
if(params.mark !== "json")
throw new Error("Non-json subscriptions unimplemented.") // XX
url = "/~/is/"+this.gsig(params)+"."+params.mark
params.path = params.wire
this.cabs[this.gsig(params)] = cb
$this = this
this.qreq("put",url,params,true,function(err,res) {
if(nicecb) { nicecb.apply(this,[err,{status: res.status, data: res.data}])}
// XX give raw data
//
if(!err && !$this.puls) $this.poll(params)
})
}
urb.bind.mark = "json"
window.urb.drop = function(path, params, cb){ // or drop(path,cb)
if(typeof params === "function")
{cb = params; params = {}}
params.path = path
if(params.path[0] !== "/") params.path = "/"+params.path
params.ship = params.ship || this.ship
params.appl = params.appl || this.appl
params.wire = params.wire || params.path
if(typeof path != "string")
throw new Error("You must specify a string path for urb.drop.")
if(!params.appl) throw new Error("You must specify an appl for urb.drop.")
url = "/~/is/"+this.gsig(params)+".json"
method = "delete"
this.req("delete",url,params,true,function(err,res) {
if(cb) cb(err,res)
})
}
window.urb.subscribe = function(params,cb) { // legacy interface
if(!params) throw new Error("You must supply params to urb.subscribe")
return window.urb.bind(params.path, params, cb, cb)
}
window.urb.unsubscribe = function(params,cb) { // legacy intreface
if(!params) throw new Error("You must supply params to urb.unsubscribe.")
return window.urb.drop(params.path, params, cb)
}
window.urb.util = {
isURL: function(s) {
r = new RegExp('^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$', 'i');
return s.length < 2083 && r.test(s);
},
numDot: function(n) {
_n = String(n)
fun = function(s){
if(s.length <= 3)
return s
return fun(s.slice(0,-3))+"."+s.slice(-3)
}
return fun((_n))
},
toDate: function (dat){
var mils = Math.floor((0x10000 * dat.getUTCMilliseconds()) / 1000).toString(16)
function pad(num, str){
return ((new Array(num + 1)).join('0') + str).substr(-num,num)
}
return '~' + dat.getUTCFullYear() +
'.' + (dat.getUTCMonth() + 1) +
'.' + dat.getUTCDate() +
'..' + pad(2, dat.getUTCHours()) +
'.' + pad(2, dat.getUTCMinutes()) +
'.' + pad(2, dat.getUTCSeconds()) +
'..' + pad(4, mils)
},
basepath: function(spur, pathname){
spur = spur || ''
if(spur === '/') spur = ''
pathname = pathname || window.location.pathname
base = ""
if(pathname.indexOf("/~~") == 0)
base = "/~~"
if(pathname.indexOf("/~/as/") == 0)
base = "/~/as/"+pathname.split("/")[3]
if(pathname.indexOf("/~/away") == 0)
base = "/~/away"
return base+spur
}
}

View File

@ -1,8 +0,0 @@
:- ~[comments+&]
;>
# Static
You can put static files in here to serve them to the web. Actually, you can put static files anywhere in `/web` and see them in a browser.
Docs on static publishing with urbit are forthcoming — but feel free to drop markdown files in `/web` to try it out.

View File

@ -1,58 +0,0 @@
:- ~[comments+&]
;>
# Writing Unit Tests
Urbit comes with a built in system for writing tests. Like hoon files with a
certain shape go in `%/app` or `%/gen` or `%/mar`, hoon files with a certain
shape can go in `%/tests` and then are exposed to a system wide test runner.
Say you put a test suite in `%/tests/new-hoon/thr.hoon`:
```
> +ls %/tests
new-hoon/
> +ls %/tests/new-hoon
ls/hoon mp/hoon myb/hoon thr/hoon
```
You can then just run that individual test suite (and not the ones that are beside it in the `%/tests/new-hoon` directory) with:
```
> +tests /new-hoon/thr
/new-hoon/thr/test-seconds OK
/new-hoon/thr/test-partition OK
/new-hoon/thr/test-firsts OK
/new-hoon/thr/test-apply OK
```
## The test file
So what is the structure of these test files? They contain a door, with arms starting with `++test-` or `++check-`. At minimum:
```
/+ *test
|%
++ test-some-test
(expect-eq !>(4) !>(4))
--
```
All of the utilities you need to write tests are in the tester library. Also, like other hoon files, you can stack cores for models and utility functions with only the final core being inspected for test arms.
## Some Details
So internally, how does this work?
The `+test` generator depends on each file/directory in `%/tests/` through a renderer. Each node in the filesystem tree is rendered by `%/ren/test-tree.hoon`, which calls itself recursively for subdirectories.
This means all compiling of test cases happens inside ford, which can cache work and not recompile tests whose dependencies haven't changed. At runtime, all the `+test` generator does is filter and execute tests from the tree.
I would like to get to a place where any direct scrying of the filesystem is discouraged, and almost everything flows through the functional reactive build system. This is what it is here for.
### Future distribution of hoon libraries
Implicit in having a standard way to write tests and a standard `+test` runner is the idea that all functionality on the current desk should be tested.
Let's say I'm shipping a program on Urbit and I use multiple third-party libraries. Each of those libraries should have their own test suites placed in `%/tests/`. When I `|merge` their desks into my application desk, having a standard test runner means that all their tests and all my application tests get run. If you're depending on a library, you want to make sure that the tests for your dependencies run when you test your application.